Skip to content

Commit 219ab2e

Browse files
committed
feat(12): Adapt test framework for Raspberry Pi 5
Adapts the custom test framework introduced in Tutorial 12 to the Raspberry Pi 5, which lacks QEMU support. 1. Makefile: Implements a 'Compile, Don't Run' strategy for the 'test', 'test_unit', and 'test_integration' targets when BSP=rpi5. This allows the test binaries to be compiled for verification without attempting to run them in a non-existent emulator. 2. On-Hardware Test Console: A 'qemu_bring_up_console' function is implemented for the Pi 5 BSP to perform the necessary on-hardware GPIO and UART initialization, enabling test binaries to produce UART output when run on the device. 3. Integration Test: The '02_exception_sync_page_fault' test is updated to use a 129 GiB faulting address for the Pi 5, ensuring it correctly triggers a translation fault given the board's larger 128 GiB virtual address space.
1 parent 34512a6 commit 219ab2e

File tree

3 files changed

+214
-73
lines changed

3 files changed

+214
-73
lines changed

12_integrated_testing/Makefile

Lines changed: 101 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
## SPDX-License-Identifier: MIT OR Apache-2.0
22
##
33
## Copyright (c) 2018-2023 Andre Richter <andre.o.richter@gmail.com>
4+
## Copyright (c) 2025 Devansh Lodha <devanshlodha12@gmail.com>
45

56
include ../common/docker.mk
67
include ../common/format.mk
@@ -58,6 +59,21 @@ else ifeq ($(BSP),rpi4)
5859
JTAG_BOOT_IMAGE = ../X1_JTAG_boot/jtag_boot_rpi4.img
5960
LD_SCRIPT_PATH = $(shell pwd)/kernel/src/bsp/raspberrypi
6061
RUSTC_MISC_ARGS = -C target-cpu=cortex-a72
62+
else ifeq ($(BSP),rpi5)
63+
TARGET = aarch64-unknown-none-softfloat
64+
KERNEL_BIN = kernel8.img
65+
QEMU_BINARY = qemu-system-aarch64
66+
QEMU_MACHINE_TYPE =
67+
QEMU_RELEASE_ARGS = -serial stdio -display none
68+
QEMU_TEST_ARGS = $(QEMU_RELEASE_ARGS) -semihosting
69+
OBJDUMP_BINARY = aarch64-none-elf-objdump
70+
NM_BINARY = aarch64-none-elf-nm
71+
READELF_BINARY = aarch64-none-elf-readelf
72+
GDB_BINARY = aarch64-elf-gdb
73+
OPENOCD_ARG = -f ../debug/pi5/cmsis-dap.cfg -f ../debug/pi5/raspberrypi5.cfg
74+
GDB_INIT_FILE = ../debug/pi5/gdb-init.txt
75+
LD_SCRIPT_PATH = $(shell pwd)/kernel/src/bsp/raspberrypi5
76+
RUSTC_MISC_ARGS = -C target-cpu=cortex-a76
6177
endif
6278

6379
# Export for build.rs.
@@ -72,74 +88,75 @@ KERNEL_MANIFEST = kernel/Cargo.toml
7288
KERNEL_LINKER_SCRIPT = kernel.ld
7389
LAST_BUILD_CONFIG = target/$(BSP).build_config
7490

75-
KERNEL_ELF = target/$(TARGET)/release/kernel
91+
KERNEL_ELF = target/$(TARGET)/release/kernel
7692
# This parses cargo's dep-info file.
7793
# https://doc.rust-lang.org/cargo/guide/build-cache.html#dep-info-files
78-
KERNEL_ELF_DEPS = $(filter-out %: ,$(file < $(KERNEL_ELF).d)) $(KERNEL_MANIFEST) $(LAST_BUILD_CONFIG)
94+
KERNEL_ELF_DEPS = $(filter-out %: ,$(shell cat $(KERNEL_ELF).d 2>/dev/null)) $(KERNEL_MANIFEST) $(LAST_BUILD_CONFIG)
7995

8096

8197

8298
##--------------------------------------------------------------------------------------------------
8399
## Command building blocks
84100
##--------------------------------------------------------------------------------------------------
85-
RUSTFLAGS = $(RUSTC_MISC_ARGS) \
101+
RUSTFLAGS = $(RUSTC_MISC_ARGS) \
86102
-C link-arg=--library-path=$(LD_SCRIPT_PATH) \
87103
-C link-arg=--script=$(KERNEL_LINKER_SCRIPT)
88104

89105
RUSTFLAGS_PEDANTIC = $(RUSTFLAGS) \
90106
-D warnings \
91107
-D missing_docs
92108

93-
FEATURES = --features bsp_$(BSP)
109+
FEATURES = --features bsp_$(BSP)
94110
COMPILER_ARGS = --target=$(TARGET) \
95-
$(FEATURES) \
111+
$(FEATURES) \
96112
--release
97113

98-
RUSTC_CMD = cargo rustc $(COMPILER_ARGS) --manifest-path $(KERNEL_MANIFEST)
99-
DOC_CMD = cargo doc $(COMPILER_ARGS)
100-
CLIPPY_CMD = cargo clippy $(COMPILER_ARGS)
101-
TEST_CMD = cargo test $(COMPILER_ARGS) --manifest-path $(KERNEL_MANIFEST)
102-
OBJCOPY_CMD = rust-objcopy \
103-
--strip-all \
114+
BASE_RUSTC_CMD = cargo rustc $(COMPILER_ARGS) --manifest-path $(KERNEL_MANIFEST)
115+
BASE_DOC_CMD = cargo doc $(COMPILER_ARGS)
116+
BASE_CLIPPY_CMD = cargo clippy $(COMPILER_ARGS)
117+
BASE_TEST_CMD = cargo test $(COMPILER_ARGS) --manifest-path $(KERNEL_MANIFEST)
118+
BASE_OBJCOPY_CMD = rust-objcopy \
119+
--strip-all \
104120
-O binary
105121

106122
EXEC_QEMU = $(QEMU_BINARY) -M $(QEMU_MACHINE_TYPE)
107123
EXEC_TEST_DISPATCH = ruby ../common/tests/dispatch.rb
108124
EXEC_MINIPUSH = ruby ../common/serial/minipush.rb
109125

110126
##------------------------------------------------------------------------------
111-
## Dockerization
127+
## OS-dependent commands and Dockerization
112128
##------------------------------------------------------------------------------
113-
DOCKER_CMD = docker run -t --rm -v $(shell pwd):/work/tutorial -w /work/tutorial
114-
DOCKER_CMD_INTERACT = $(DOCKER_CMD) -i
115-
DOCKER_ARG_DIR_COMMON = -v $(shell pwd)/../common:/work/common
116-
DOCKER_ARG_DIR_JTAG = -v $(shell pwd)/../X1_JTAG_boot:/work/X1_JTAG_boot
117-
DOCKER_ARG_DEV = --privileged -v /dev:/dev
118-
DOCKER_ARG_NET = --network host
129+
DOCKER_CMD_PREFIX = docker run -t --rm -v $(shell pwd):/work/tutorial -w /work/tutorial
130+
DOCKER_CMD_INTERACT = $(DOCKER_CMD_PREFIX) -i
119131

120-
# DOCKER_IMAGE defined in include file (see top of this file).
121-
DOCKER_QEMU = $(DOCKER_CMD_INTERACT) $(DOCKER_IMAGE)
122-
DOCKER_TOOLS = $(DOCKER_CMD) $(DOCKER_IMAGE)
123-
DOCKER_TEST = $(DOCKER_CMD) $(DOCKER_ARG_DIR_COMMON) $(DOCKER_IMAGE)
124-
DOCKER_GDB = $(DOCKER_CMD_INTERACT) $(DOCKER_ARG_NET) $(DOCKER_IMAGE)
132+
# DOCKER_IMAGE is defined in ../common/docker.mk
133+
DOCKER_TOOLS_WRAPPER = $(DOCKER_CMD_PREFIX) $(DOCKER_IMAGE)
125134

126-
# Dockerize commands, which require USB device passthrough, only on Linux.
127135
ifeq ($(shell uname -s),Linux)
128-
DOCKER_CMD_DEV = $(DOCKER_CMD_INTERACT) $(DOCKER_ARG_DEV)
129-
130-
DOCKER_CHAINBOOT = $(DOCKER_CMD_DEV) $(DOCKER_ARG_DIR_COMMON) $(DOCKER_IMAGE)
131-
DOCKER_JTAGBOOT = $(DOCKER_CMD_DEV) $(DOCKER_ARG_DIR_COMMON) $(DOCKER_ARG_DIR_JTAG) $(DOCKER_IMAGE)
132-
DOCKER_OPENOCD = $(DOCKER_CMD_DEV) $(DOCKER_ARG_NET) $(DOCKER_IMAGE)
133-
else
134-
DOCKER_OPENOCD = echo "Not yet supported on non-Linux systems."; \#
136+
OPENOCD_CMD = $(DOCKER_CMD_INTERACT) --privileged -v /dev:/dev --network host -v $(shell pwd)/../debug:/work/debug $(DOCKER_IMAGE) openocd
137+
GDB_CMD = $(DOCKER_CMD_INTERACT) --network host -v $(shell pwd)/../debug:/work/debug $(DOCKER_IMAGE) gdb-multiarch
138+
STUB_MAKE_CMD = $(DOCKER_TOOLS_WRAPPER) -v $(shell pwd)/../X2_pi5_jtag_halt_stub:/work/X2_pi5_jtag_halt_stub $(MAKE)
139+
else ifeq ($(shell uname -s),Darwin) # macOS - Use local tools for hardware interaction
140+
OPENOCD_CMD = openocd # Assumes OpenOCD is installed locally
141+
GDB_CMD = $(GDB_BINARY) # Assumes aarch64-elf-gdb is in PATH
142+
STUB_MAKE_CMD = $(DOCKER_TOOLS_WRAPPER) -v $(shell pwd)/../X2_pi5_jtag_halt_stub:/work/X2_pi5_jtag_halt_stub $(MAKE)
143+
else # Fallback for other OSes
144+
OPENOCD_CMD = echo "OpenOCD on this OS is not supported by this Makefile."; false
145+
GDB_CMD = echo "GDB on this OS is not supported by this Makefile."; false
135146
endif
136147

137-
148+
# These commands are always local, as per the repository's design
149+
RUSTC_CMD = $(BASE_RUSTC_CMD)
150+
DOC_CMD = $(BASE_DOC_CMD)
151+
CLIPPY_CMD = $(BASE_CLIPPY_CMD)
152+
TEST_CMD = $(BASE_TEST_CMD)
153+
OBJCOPY_CMD = $(BASE_OBJCOPY_CMD)
154+
CLEAN_CMD = cargo clean
138155

139156
##--------------------------------------------------------------------------------------------------
140157
## Targets
141158
##--------------------------------------------------------------------------------------------------
142-
.PHONY: all doc qemu chainboot clippy clean readelf objdump nm check
159+
.PHONY: all doc qemu clippy clean readelf objdump nm check
143160

144161
all: $(KERNEL_BIN)
145162

@@ -188,73 +205,72 @@ else # QEMU is supported.
188205

189206
qemu: $(KERNEL_BIN)
190207
$(call color_header, "Launching QEMU")
191-
@$(DOCKER_QEMU) $(EXEC_QEMU) $(QEMU_RELEASE_ARGS) -kernel $(KERNEL_BIN)
208+
@$(DOCKER_CMD_INTERACT) $(DOCKER_IMAGE) $(EXEC_QEMU) $(QEMU_RELEASE_ARGS) -kernel $(KERNEL_BIN)
192209

193210
endif
194211

195-
##------------------------------------------------------------------------------
196-
## Push the kernel to the real HW target
197-
##------------------------------------------------------------------------------
198-
chainboot: $(KERNEL_BIN)
199-
@$(DOCKER_CHAINBOOT) $(EXEC_MINIPUSH) $(DEV_SERIAL) $(KERNEL_BIN)
200-
201212
##------------------------------------------------------------------------------
202213
## Run clippy
203214
##------------------------------------------------------------------------------
204215
clippy:
205216
@RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(CLIPPY_CMD)
206217
@RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(CLIPPY_CMD) --features test_build --tests \
207-
--manifest-path $(KERNEL_MANIFEST)
218+
--manifest-path $(KERNEL_MANIFEST)
208219

209220
##------------------------------------------------------------------------------
210221
## Clean
211222
##------------------------------------------------------------------------------
212223
clean:
213-
rm -rf target $(KERNEL_BIN)
224+
@$(CLEAN_CMD)
225+
@rm -f kernel8.img
214226

215227
##------------------------------------------------------------------------------
216228
## Run readelf
217229
##------------------------------------------------------------------------------
218230
readelf: $(KERNEL_ELF)
219231
$(call color_header, "Launching readelf")
220-
@$(DOCKER_TOOLS) $(READELF_BINARY) --headers $(KERNEL_ELF)
232+
@$(DOCKER_TOOLS_WRAPPER) $(READELF_BINARY) --headers $(KERNEL_ELF)
221233

222234
##------------------------------------------------------------------------------
223235
## Run objdump
224236
##------------------------------------------------------------------------------
225237
objdump: $(KERNEL_ELF)
226238
$(call color_header, "Launching objdump")
227-
@$(DOCKER_TOOLS) $(OBJDUMP_BINARY) --disassemble --demangle \
228-
--section .text \
229-
--section .rodata \
230-
$(KERNEL_ELF) | rustfilt
239+
@$(DOCKER_TOOLS_WRAPPER) $(OBJDUMP_BINARY) --disassemble --demangle \
240+
--section .text \
241+
--section .rodata \
242+
$(KERNEL_ELF) | rustfilt
231243

232244
##------------------------------------------------------------------------------
233245
## Run nm
234246
##------------------------------------------------------------------------------
235247
nm: $(KERNEL_ELF)
236248
$(call color_header, "Launching nm")
237-
@$(DOCKER_TOOLS) $(NM_BINARY) --demangle --print-size $(KERNEL_ELF) | sort | rustfilt
249+
@$(DOCKER_TOOLS_WRAPPER) $(NM_BINARY) --demangle --print-size $(KERNEL_ELF) | sort | rustfilt
238250

239251

240252

241253
##--------------------------------------------------------------------------------------------------
242254
## Debugging targets
243255
##--------------------------------------------------------------------------------------------------
244-
.PHONY: jtagboot openocd gdb gdb-opt0
256+
.PHONY: sd_image openocd gdb gdb-opt0
245257

246258
##------------------------------------------------------------------------------
247-
## Push the JTAG boot image to the real HW target
259+
## Build the JTAG halt stub and copy it for SD card use
248260
##------------------------------------------------------------------------------
249-
jtagboot:
250-
@$(DOCKER_JTAGBOOT) $(EXEC_MINIPUSH) $(DEV_SERIAL) $(JTAG_BOOT_IMAGE)
261+
sd_image:
262+
$(call color_header, "Building JTAG halt stub for SD card")
263+
@$(STUB_MAKE_CMD) -C ../X2_pi5_jtag_halt_stub
264+
@cp ../X2_pi5_jtag_halt_stub/halt_stub.img ./kernel8.img
265+
$(call color_progress_prefix, "Name")
266+
@echo "kernel8.img (Halt Stub)"
251267

252268
##------------------------------------------------------------------------------
253269
## Start OpenOCD session
254270
##------------------------------------------------------------------------------
255271
openocd:
256272
$(call color_header, "Launching OpenOCD")
257-
@$(DOCKER_OPENOCD) openocd $(OPENOCD_ARG)
273+
@$(OPENOCD_CMD) $(OPENOCD_ARG)
258274

259275
##------------------------------------------------------------------------------
260276
## Start GDB session
@@ -263,7 +279,11 @@ gdb: RUSTC_MISC_ARGS += -C debuginfo=2
263279
gdb-opt0: RUSTC_MISC_ARGS += -C debuginfo=2 -C opt-level=0
264280
gdb gdb-opt0: $(KERNEL_ELF)
265281
$(call color_header, "Launching GDB")
266-
@$(DOCKER_GDB) gdb-multiarch -q $(KERNEL_ELF)
282+
ifeq ($(BSP),rpi5)
283+
@$(GDB_CMD) -q -x $(GDB_INIT_FILE) $(KERNEL_ELF)
284+
else
285+
@$(GDB_CMD) -q $(KERNEL_ELF)
286+
endif
267287

268288

269289

@@ -274,19 +294,18 @@ gdb gdb-opt0: $(KERNEL_ELF)
274294

275295
test_unit test_integration: FEATURES += --features test_build
276296

277-
ifeq ($(QEMU_MACHINE_TYPE),) # QEMU is not supported for the board.
278-
279-
test_boot test_unit test_integration test:
280-
$(call color_header, "$(QEMU_MISSING_STRING)")
281-
282-
else # QEMU is supported.
283-
284297
##------------------------------------------------------------------------------
285298
## Run boot test
286299
##------------------------------------------------------------------------------
287300
test_boot: $(KERNEL_BIN)
288-
$(call color_header, "Boot test - $(BSP)")
289-
@$(DOCKER_TEST) $(EXEC_TEST_DISPATCH) $(EXEC_QEMU) $(QEMU_RELEASE_ARGS) -kernel $(KERNEL_BIN)
301+
ifeq ($(BSP),rpi5)
302+
@$(call color_header, "Skipping boot test for $(BSP) (no QEMU support)")
303+
else ifeq ($(QEMU_MACHINE_TYPE),)
304+
@$(call color_header, "$(QEMU_MISSING_STRING)")
305+
else
306+
@$(call color_header, "Boot test - $(BSP)")
307+
@$(DOCKER_CMD_INTERACT) $(DOCKER_IMAGE) $(EXEC_TEST_DISPATCH) $(EXEC_QEMU) $(QEMU_RELEASE_ARGS) -kernel $(KERNEL_BIN)
308+
endif
290309

291310
##------------------------------------------------------------------------------
292311
## Helpers for unit and integration test targets
@@ -302,7 +321,7 @@ define KERNEL_TEST_RUNNER
302321
TEST_BINARY=$$(echo $$1.img | sed -e 's/.*target/target/g')
303322

304323
$(OBJCOPY_CMD) $$TEST_ELF $$TEST_BINARY
305-
$(DOCKER_TEST) $(EXEC_TEST_DISPATCH) $(EXEC_QEMU) $(QEMU_TEST_ARGS) -kernel $$TEST_BINARY
324+
$(DOCKER_CMD_INTERACT) $(DOCKER_IMAGE) $(EXEC_TEST_DISPATCH) $(EXEC_QEMU) $(QEMU_TEST_ARGS) -kernel $$TEST_BINARY
306325
endef
307326

308327
export KERNEL_TEST_RUNNER
@@ -317,18 +336,30 @@ endef
317336
## Run unit test(s)
318337
##------------------------------------------------------------------------------
319338
test_unit:
320-
$(call color_header, "Compiling unit test(s) - $(BSP)")
321-
$(call test_prepare)
339+
ifeq ($(BSP),rpi5)
340+
@echo "## Compiling unit test(s) for $(BSP), but not running."
341+
@echo "Due to no QEMU support, tests are built but not executed."
342+
@echo "Load and run the test binaries on-target manually for verification."
343+
@RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(TEST_CMD) --no-run --lib
344+
else
345+
@$(call color_header, "Compiling unit test(s) - $(BSP)")
346+
@$(call test_prepare)
322347
@RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(TEST_CMD) --lib
348+
endif
323349

324350
##------------------------------------------------------------------------------
325351
## Run integration test(s)
326352
##------------------------------------------------------------------------------
327353
test_integration:
328-
$(call color_header, "Compiling integration test(s) - $(BSP)")
329-
$(call test_prepare)
354+
ifeq ($(BSP),rpi5)
355+
@echo "## Compiling integration test(s) for $(BSP), but not running."
356+
@echo "Due to no QEMU support, tests are built but not executed."
357+
@echo "Load and run the test binaries on-target manually for verification."
358+
@RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(TEST_CMD) --no-run $(TEST_ARG)
359+
else
360+
@$(call color_header, "Compiling integration test(s) - $(BSP)")
361+
@$(call test_prepare)
330362
@RUSTFLAGS="$(RUSTFLAGS_PEDANTIC)" $(TEST_CMD) $(TEST_ARG)
363+
endif
331364

332365
test: test_boot test_unit test_integration
333-
334-
endif

0 commit comments

Comments
 (0)