@@ -7,30 +7,155 @@ IFS=$'\n\t'
77DIR=$( dirname " $( realpath " $0 " ) " )
88cd " $DIR " || exit
99
10+ BINS_DIR=bins/target/x86-unknown-none/release
11+ ANSI_HIGHLIGHT=" \e[1;32m" # green + bold
12+ ANSI_HIGHLIGHT_ERROR=" \e[1;31m" # red + bold
13+ ANSI_RESET=" \e[0m"
14+ QEMU_ARGS_BASE=(
15+ -machine q35,accel=kvm
16+ -m 128m # for OVMF, we need more than just 24
17+ -debugcon stdio
18+ -serial file:serial.txt
19+ -no-reboot
20+ -device isa-debug-exit,iobase=0xf4,iosize=0x04
21+ -display none ` # relevant for the CI`
22+ )
23+
1024function fn_main() {
25+ git submodule update --init
26+ fn_build_limine_hosttool
1127 fn_build_rust_bins
12- fn_multiboot2_integrationtest
13- fn_multiboot2_header_integrationtest
28+
29+ fn_test_payload
30+ fn_test_loader
31+ }
32+
33+ function fn_build_limine_hosttool() {
34+ cd limine-bootloader
35+ make
36+ test -f ./limine
37+ file --brief ./limine | grep -q " ELF 64-bit LSB executable"
38+ cd -
1439}
1540
1641function fn_build_rust_bins() {
1742 cd " bins"
1843 cargo --version
1944 cargo build --release --verbose
20- cd " $DIR "
45+ cd -
46+
47+ test -f $BINS_DIR /multiboot2_chainloader
48+ file --brief $BINS_DIR /multiboot2_chainloader | grep -q " ELF 32-bit LSB executable"
49+ # For simplicity, the chainloader itself boots via Multiboot 1. Sufficient.
50+ grub-file --is-x86-multiboot $BINS_DIR /multiboot2_chainloader
51+
52+ test -f $BINS_DIR /multiboot2_payload
53+ file --brief $BINS_DIR /multiboot2_payload | grep -q " ELF 32-bit LSB executable"
54+ grub-file --is-x86-multiboot2 $BINS_DIR /multiboot2_payload
55+ }
56+
57+ function fn_prepare_test_vol() {
58+ TEST_VOL=" $TEST_DIR /.vol"
59+ rm -rf $TEST_VOL
60+ mkdir -p $TEST_VOL
61+ cp $TEST_DIR /limine.cfg $TEST_VOL
62+
63+ # copy limine artifacts
64+ mkdir -p $TEST_VOL /limine
65+ cp limine-bootloader/limine-bios-cd.bin $TEST_VOL /limine
66+ cp limine-bootloader/limine-bios.sys $TEST_VOL /limine
67+ cp limine-bootloader/limine-uefi-cd.bin $TEST_VOL /limine
68+
69+ mkdir -p $TEST_VOL /EFI/BOOT
70+ cp limine-bootloader/BOOTX64.EFI $TEST_VOL /EFI_BOOT
2171}
2272
23- function fn_multiboot2_integrationtest() {
24- cd tests/multiboot2
25- ./build_img.sh
26- ./run_qemu.sh
27- cd " $DIR "
73+
74+
75+ # Builds a hybrid-bootable image using Limine as bootloader. Expects that
76+ # all relevant files are in the directory describing the root volume.
77+ function fn_build_limine_iso() {
78+ xorriso -as mkisofs -b limine/limine-bios-cd.bin \
79+ -no-emul-boot -boot-load-size 4 -boot-info-table \
80+ --efi-boot limine/limine-uefi-cd.bin \
81+ -efi-boot-part --efi-boot-image --protective-msdos-label \
82+ $TEST_VOL -o $TEST_DIR /image.iso 2> /dev/null
83+
84+ ./limine-bootloader/limine bios-install $TEST_DIR /image.iso 2> /dev/null
2885}
2986
30- function fn_multiboot2_header_integrationtest() {
31- cd tests/multiboot2-header
32- ./run_qemu.sh
33- cd " $DIR "
87+ function fn_run_qemu() {
88+ set +e
89+
90+ # As QEMU can't print serial and debugcon to stdout simultaneously, I
91+ # add a background task watching serial.txt
92+ rm serial.txt
93+ touch serial.txt
94+ tail -f serial.txt &
95+
96+ qemu-system-x86_64 " ${QEMU_ARGS[@]} "
97+ EXIT_CODE=$?
98+ # Custom exit code used by the integration test to report success.
99+ QEMU_EXIT_SUCCESS=73
100+
101+ set -e
102+
103+ echo " #######################################"
104+ if [[ $EXIT_CODE -eq $QEMU_EXIT_SUCCESS ]]; then
105+ echo -e " ${ANSI_HIGHLIGHT} SUCCESS${ANSI_RESET} "
106+ echo # newline
107+ else
108+ echo -e " ${ANSI_HIGHLIGHT_ERROR} FAILED - Integration Test 'multiboot2-header'${ANSI_RESET} "
109+ exit " $EXIT_CODE "
110+ fi
111+ }
112+
113+ function fn_run_test_bios() {
114+ local ISO=$1
115+ local QEMU_ARGS=(" ${QEMU_ARGS_BASE[@]} " ) # copy array
116+ local QEMU_ARGS+=(
117+ -cdrom " $ISO "
118+ )
119+ echo -e " Running '${ANSI_HIGHLIGHT} $ISO ${ANSI_RESET} ' in QEMU (with legacy BIOS firmware)"
120+ fn_run_qemu
121+ }
122+
123+ function fn_run_test_uefi() {
124+ local ISO=$1
125+ local QEMU_ARGS=(" ${QEMU_ARGS_BASE[@]} " ) # copy array
126+ local QEMU_ARGS+=(
127+ # Usually, this comes from the Nix shell.
128+ -bios $OVMF
129+ -cdrom " $ISO "
130+ )
131+ echo -e " Running '${ANSI_HIGHLIGHT} $ISO ${ANSI_RESET} ' in QEMU (with UEFI/OVMF firmware)"
132+ fn_run_qemu $QEMU_ARGS
133+ }
134+
135+ function fn_test_payload() {
136+ local TEST_DIR=tests/01-boot-payload
137+ fn_prepare_test_vol
138+
139+ cp $BINS_DIR /multiboot2_payload $TEST_VOL /kernel
140+
141+ fn_build_limine_iso
142+
143+ fn_run_test_bios $TEST_DIR /image.iso
144+ fn_run_test_uefi $TEST_DIR /image.iso
145+ }
146+
147+ # Tests the loader by chainloading the Multiboot2 payload.
148+ function fn_test_loader() {
149+ local TEST_DIR=tests/02-boot-loader-and-chainload
150+ fn_prepare_test_vol
151+
152+ cp $BINS_DIR /multiboot2_chainloader $TEST_VOL /kernel
153+ cp $BINS_DIR /multiboot2_payload $TEST_VOL /payload
154+
155+ fn_build_limine_iso
156+
157+ fn_run_test_bios $TEST_DIR /image.iso
158+ fn_run_test_uefi $TEST_DIR /image.iso
34159}
35160
36161fn_main
0 commit comments