-
-
Notifications
You must be signed in to change notification settings - Fork 816
/
Copy pathMakefile
393 lines (313 loc) · 16 KB
/
Makefile
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
## SPDX-License-Identifier: MIT OR Apache-2.0
##
## Copyright (c) 2018-2023 Andre Richter <[email protected]>
include ../common/docker.mk
include ../common/format.mk
include ../common/operating_system.mk
##--------------------------------------------------------------------------------------------------
## Optional, user-provided configuration values
##--------------------------------------------------------------------------------------------------
# Default to the RPi3.
BSP ?= rpi3
# Default to a serial device name that is common in Linux.
DEV_SERIAL ?= /dev/ttyUSB0
# Optional debug prints.
ifdef DEBUG_PRINTS
FEATURES = --features debug_prints
endif
# Optional integration test name.
ifdef TEST
TEST_ARG = --test $(TEST)
else
TEST_ARG = --test '*'
endif
##--------------------------------------------------------------------------------------------------
## BSP-specific configuration values
##--------------------------------------------------------------------------------------------------
QEMU_MISSING_STRING = "This board is not yet supported for QEMU."
ifeq ($(BSP),rpi3)
TARGET = aarch64-unknown-none-softfloat
KERNEL_BIN = kernel8.img
QEMU_BINARY = qemu-system-aarch64
QEMU_MACHINE_TYPE = raspi3
QEMU_RELEASE_ARGS = -serial stdio -display none
QEMU_TEST_ARGS = $(QEMU_RELEASE_ARGS) -semihosting
OBJDUMP_BINARY = aarch64-none-elf-objdump
NM_BINARY = aarch64-none-elf-nm
READELF_BINARY = aarch64-none-elf-readelf
OPENOCD_ARG = -f /openocd/tcl/interface/ftdi/olimex-arm-usb-tiny-h.cfg -f /openocd/rpi3.cfg
JTAG_BOOT_IMAGE = ../X1_JTAG_boot/jtag_boot_rpi3.img
LD_SCRIPT_PATH = $(shell pwd)/kernel/src/bsp/raspberrypi
RUSTC_MISC_ARGS = -C target-cpu=cortex-a53 -C force-frame-pointers
else ifeq ($(BSP),rpi4)
TARGET = aarch64-unknown-none-softfloat
KERNEL_BIN = kernel8.img
QEMU_BINARY = qemu-system-aarch64
QEMU_MACHINE_TYPE =
QEMU_RELEASE_ARGS = -serial stdio -display none
QEMU_TEST_ARGS = $(QEMU_RELEASE_ARGS) -semihosting
OBJDUMP_BINARY = aarch64-none-elf-objdump
NM_BINARY = aarch64-none-elf-nm
READELF_BINARY = aarch64-none-elf-readelf
OPENOCD_ARG = -f /openocd/tcl/interface/ftdi/olimex-arm-usb-tiny-h.cfg -f /openocd/rpi4.cfg
JTAG_BOOT_IMAGE = ../X1_JTAG_boot/jtag_boot_rpi4.img
LD_SCRIPT_PATH = $(shell pwd)/kernel/src/bsp/raspberrypi
RUSTC_MISC_ARGS = -C target-cpu=cortex-a72 -C force-frame-pointers
endif
# Export for build.rs.
export LD_SCRIPT_PATH
##--------------------------------------------------------------------------------------------------
## Targets and Prerequisites
##--------------------------------------------------------------------------------------------------
KERNEL_MANIFEST = kernel/Cargo.toml
KERNEL_LINKER_SCRIPT = kernel.ld
LAST_BUILD_CONFIG = target/$(BSP)_$(DEBUG_PRINTS).build_config
KERNEL_ELF_RAW = target/$(TARGET)/release/kernel
# This parses cargo's dep-info file.
# https://doc.rust-lang.org/cargo/guide/build-cache.html#dep-info-files
KERNEL_ELF_RAW_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF_RAW).d)) $(KERNEL_MANIFEST) $(LAST_BUILD_CONFIG)
##------------------------------------------------------------------------------
## Translation tables
##------------------------------------------------------------------------------
TT_TOOL_PATH = tools/translation_table_tool
KERNEL_ELF_TTABLES = target/$(TARGET)/release/kernel+ttables
KERNEL_ELF_TTABLES_DEPS = $(KERNEL_ELF_RAW) $(wildcard $(TT_TOOL_PATH)/*)
##------------------------------------------------------------------------------
## Kernel symbols
##------------------------------------------------------------------------------
export KERNEL_SYMBOLS_TOOL_PATH = tools/kernel_symbols_tool
KERNEL_ELF_TTABLES_SYMS = target/$(TARGET)/release/kernel+ttables+symbols
# Unlike with KERNEL_ELF_RAW, we are not relying on dep-info here. One of the reasons being that the
# name of the generated symbols file varies between runs, which can cause confusion.
KERNEL_ELF_TTABLES_SYMS_DEPS = $(KERNEL_ELF_TTABLES) \
$(wildcard kernel_symbols/*) \
$(wildcard $(KERNEL_SYMBOLS_TOOL_PATH)/*)
export TARGET
export KERNEL_SYMBOLS_INPUT_ELF = $(KERNEL_ELF_TTABLES)
export KERNEL_SYMBOLS_OUTPUT_ELF = $(KERNEL_ELF_TTABLES_SYMS)
KERNEL_ELF = $(KERNEL_ELF_TTABLES_SYMS)
##--------------------------------------------------------------------------------------------------
## Command building blocks
##--------------------------------------------------------------------------------------------------
RUSTFLAGS = $(RUSTC_MISC_ARGS) \
-C link-arg=--library-path=$(LD_SCRIPT_PATH) \
-C link-arg=--script=$(KERNEL_LINKER_SCRIPT)
RUSTFLAGS_PEDANTIC = $(RUSTFLAGS) \
-D warnings \
-D missing_docs
FEATURES += --features bsp_$(BSP)
COMPILER_ARGS = --target=$(TARGET) \
$(FEATURES) \
--release
# build-std can be skipped for helper commands that do not rely on correct stack frames and other
# custom compiler options. This results in a huge speedup.
RUSTC_CMD = cargo rustc $(COMPILER_ARGS) -Z build-std=core,alloc --manifest-path $(KERNEL_MANIFEST)
DOC_CMD = cargo doc $(COMPILER_ARGS)
CLIPPY_CMD = cargo clippy $(COMPILER_ARGS)
TEST_CMD = cargo test $(COMPILER_ARGS) -Z build-std=core,alloc --manifest-path $(KERNEL_MANIFEST)
OBJCOPY_CMD = rust-objcopy \
--strip-all \
-O binary
EXEC_QEMU = $(QEMU_BINARY) -M $(QEMU_MACHINE_TYPE)
EXEC_TT_TOOL = ruby $(TT_TOOL_PATH)/main.rb
EXEC_TEST_DISPATCH = ruby ../common/tests/dispatch.rb
EXEC_MINIPUSH = ruby ../common/serial/minipush.rb
##------------------------------------------------------------------------------
## Dockerization
##------------------------------------------------------------------------------
DOCKER_CMD = docker run -t --rm -v $(shell pwd):/work/tutorial -w /work/tutorial
DOCKER_CMD_INTERACT = $(DOCKER_CMD) -i
DOCKER_ARG_DIR_COMMON = -v $(shell pwd)/../common:/work/common
DOCKER_ARG_DIR_JTAG = -v $(shell pwd)/../X1_JTAG_boot:/work/X1_JTAG_boot
DOCKER_ARG_DEV = --privileged -v /dev:/dev
DOCKER_ARG_NET = --network host
# DOCKER_IMAGE defined in include file (see top of this file).
DOCKER_QEMU = $(DOCKER_CMD_INTERACT) $(DOCKER_IMAGE)
DOCKER_TOOLS = $(DOCKER_CMD) $(DOCKER_IMAGE)
DOCKER_TEST = $(DOCKER_CMD) $(DOCKER_ARG_DIR_COMMON) $(DOCKER_IMAGE)
DOCKER_GDB = $(DOCKER_CMD_INTERACT) $(DOCKER_ARG_NET) $(DOCKER_IMAGE)
# Dockerize commands, which require USB device passthrough, only on Linux.
ifeq ($(shell uname -s),Linux)
DOCKER_CMD_DEV = $(DOCKER_CMD_INTERACT) $(DOCKER_ARG_DEV)
DOCKER_CHAINBOOT = $(DOCKER_CMD_DEV) $(DOCKER_ARG_DIR_COMMON) $(DOCKER_IMAGE)
DOCKER_JTAGBOOT = $(DOCKER_CMD_DEV) $(DOCKER_ARG_DIR_COMMON) $(DOCKER_ARG_DIR_JTAG) $(DOCKER_IMAGE)
DOCKER_OPENOCD = $(DOCKER_CMD_DEV) $(DOCKER_ARG_NET) $(DOCKER_IMAGE)
else
DOCKER_OPENOCD = echo "Not yet supported on non-Linux systems."; \#
endif
##--------------------------------------------------------------------------------------------------
## Targets
##--------------------------------------------------------------------------------------------------
.PHONY: all doc qemu chainboot clippy clean readelf objdump nm check
all: $(KERNEL_BIN)
##------------------------------------------------------------------------------
## Save the configuration as a file, so make understands if it changed.
##------------------------------------------------------------------------------
$(LAST_BUILD_CONFIG):
@rm -f target/*.build_config
@mkdir -p target
@touch $(LAST_BUILD_CONFIG)
##------------------------------------------------------------------------------
## Compile the kernel ELF
##------------------------------------------------------------------------------
$(KERNEL_ELF_RAW): $(KERNEL_ELF_RAW_DEPS)
$(call color_header, "Compiling kernel ELF - $(BSP)")
@RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(RUSTC_CMD)
##------------------------------------------------------------------------------
## Precompute the kernel translation tables and patch them into the kernel ELF
##------------------------------------------------------------------------------
$(KERNEL_ELF_TTABLES): $(KERNEL_ELF_TTABLES_DEPS)
$(call color_header, "Precomputing kernel translation tables and patching kernel ELF")
@cp $(KERNEL_ELF_RAW) $(KERNEL_ELF_TTABLES)
@$(DOCKER_TOOLS) $(EXEC_TT_TOOL) $(BSP) $(KERNEL_ELF_TTABLES)
##------------------------------------------------------------------------------
## Generate kernel symbols and patch them into the kernel ELF
##------------------------------------------------------------------------------
$(KERNEL_ELF_TTABLES_SYMS): $(KERNEL_ELF_TTABLES_SYMS_DEPS)
$(call color_header, "Generating kernel symbols and patching kernel ELF")
@$(MAKE) --no-print-directory -f kernel_symbols.mk
##------------------------------------------------------------------------------
## Generate the stripped kernel binary
##------------------------------------------------------------------------------
$(KERNEL_BIN): $(KERNEL_ELF_TTABLES_SYMS)
$(call color_header, "Generating stripped binary")
@$(OBJCOPY_CMD) $(KERNEL_ELF_TTABLES_SYMS) $(KERNEL_BIN)
$(call color_progress_prefix, "Name")
@echo $(KERNEL_BIN)
$(call color_progress_prefix, "Size")
$(call disk_usage_KiB, $(KERNEL_BIN))
##------------------------------------------------------------------------------
## Generate the documentation
##------------------------------------------------------------------------------
doc: clean
$(call color_header, "Generating docs")
@$(DOC_CMD) --document-private-items --open
##------------------------------------------------------------------------------
## Run the kernel in QEMU
##------------------------------------------------------------------------------
ifeq ($(QEMU_MACHINE_TYPE),) # QEMU is not supported for the board.
qemu:
$(call color_header, "$(QEMU_MISSING_STRING)")
else # QEMU is supported.
qemu: $(KERNEL_BIN)
$(call color_header, "Launching QEMU")
@$(DOCKER_QEMU) $(EXEC_QEMU) $(QEMU_RELEASE_ARGS) -kernel $(KERNEL_BIN)
endif
##------------------------------------------------------------------------------
## Push the kernel to the real HW target
##------------------------------------------------------------------------------
chainboot: $(KERNEL_BIN)
@$(DOCKER_CHAINBOOT) $(EXEC_MINIPUSH) $(DEV_SERIAL) $(KERNEL_BIN)
##------------------------------------------------------------------------------
## Run clippy
##------------------------------------------------------------------------------
clippy:
@RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(CLIPPY_CMD)
@RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(CLIPPY_CMD) --features test_build --tests \
--manifest-path $(KERNEL_MANIFEST)
##------------------------------------------------------------------------------
## Clean
##------------------------------------------------------------------------------
clean:
rm -rf target $(KERNEL_BIN)
##------------------------------------------------------------------------------
## Run readelf
##------------------------------------------------------------------------------
readelf: $(KERNEL_ELF)
$(call color_header, "Launching readelf")
@$(DOCKER_TOOLS) $(READELF_BINARY) --headers $(KERNEL_ELF)
##------------------------------------------------------------------------------
## Run objdump
##------------------------------------------------------------------------------
objdump: $(KERNEL_ELF)
$(call color_header, "Launching objdump")
@$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \
--section .text \
--section .rodata \
$(KERNEL_ELF) | rustfilt
##------------------------------------------------------------------------------
## Run nm
##------------------------------------------------------------------------------
nm: $(KERNEL_ELF)
$(call color_header, "Launching nm")
@$(DOCKER_TOOLS) $(NM_BINARY) --demangle --print-size $(KERNEL_ELF) | sort | rustfilt
##--------------------------------------------------------------------------------------------------
## Debugging targets
##--------------------------------------------------------------------------------------------------
.PHONY: jtagboot openocd gdb gdb-opt0
##------------------------------------------------------------------------------
## Push the JTAG boot image to the real HW target
##------------------------------------------------------------------------------
jtagboot:
@$(DOCKER_JTAGBOOT) $(EXEC_MINIPUSH) $(DEV_SERIAL) $(JTAG_BOOT_IMAGE)
##------------------------------------------------------------------------------
## Start OpenOCD session
##------------------------------------------------------------------------------
openocd:
$(call color_header, "Launching OpenOCD")
@$(DOCKER_OPENOCD) openocd $(OPENOCD_ARG)
##------------------------------------------------------------------------------
## Start GDB session
##------------------------------------------------------------------------------
gdb-opt0: RUSTC_MISC_ARGS += -C opt-level=0
gdb gdb-opt0: $(KERNEL_ELF)
$(call color_header, "Launching GDB")
@$(DOCKER_GDB) gdb-multiarch -q $(KERNEL_ELF)
##--------------------------------------------------------------------------------------------------
## Testing targets
##--------------------------------------------------------------------------------------------------
.PHONY: test test_boot test_unit test_integration
test_unit test_integration: FEATURES += --features test_build
ifeq ($(QEMU_MACHINE_TYPE),) # QEMU is not supported for the board.
test_boot test_unit test_integration test:
$(call color_header, "$(QEMU_MISSING_STRING)")
else # QEMU is supported.
##------------------------------------------------------------------------------
## Run boot test
##------------------------------------------------------------------------------
test_boot: $(KERNEL_BIN)
$(call color_header, "Boot test - $(BSP)")
@$(DOCKER_TEST) $(EXEC_TEST_DISPATCH) $(EXEC_QEMU) $(QEMU_RELEASE_ARGS) -kernel $(KERNEL_BIN)
##------------------------------------------------------------------------------
## Helpers for unit and integration test targets
##------------------------------------------------------------------------------
define KERNEL_TEST_RUNNER
#!/usr/bin/env bash
# The cargo test runner seems to change into the crate under test's directory. Therefore, ensure
# this script executes from the root.
cd $(shell pwd)
TEST_ELF=$$(echo $$1 | sed -e 's/.*target/target/g')
TEST_ELF_SYMS="$${TEST_ELF}_syms"
TEST_BINARY=$$(echo $$1.img | sed -e 's/.*target/target/g')
$(DOCKER_TOOLS) $(EXEC_TT_TOOL) $(BSP) $$TEST_ELF > /dev/null
# This overrides the two ENV variables. The other ENV variables that are required as input for
# the .mk file are set already because they are exported by this Makefile and this script is
# started by the same.
KERNEL_SYMBOLS_INPUT_ELF=$$TEST_ELF \
KERNEL_SYMBOLS_OUTPUT_ELF=$$TEST_ELF_SYMS \
$(MAKE) --no-print-directory -f kernel_symbols.mk > /dev/null 2>&1
$(OBJCOPY_CMD) $$TEST_ELF_SYMS $$TEST_BINARY
$(DOCKER_TEST) $(EXEC_TEST_DISPATCH) $(EXEC_QEMU) $(QEMU_TEST_ARGS) -kernel $$TEST_BINARY
endef
export KERNEL_TEST_RUNNER
define test_prepare
@mkdir -p target
@echo "$$KERNEL_TEST_RUNNER" > target/kernel_test_runner.sh
@chmod +x target/kernel_test_runner.sh
endef
##------------------------------------------------------------------------------
## Run unit test(s)
##------------------------------------------------------------------------------
test_unit:
$(call color_header, "Compiling unit test(s) - $(BSP)")
$(call test_prepare)
@RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(TEST_CMD) --lib
##------------------------------------------------------------------------------
## Run integration test(s)
##------------------------------------------------------------------------------
test_integration:
$(call color_header, "Compiling integration test(s) - $(BSP)")
$(call test_prepare)
@RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(TEST_CMD) $(TEST_ARG)
test: test_boot test_unit test_integration
endif