@@ -7,30 +7,155 @@ IFS=$'\n\t'
7
7
DIR=$( dirname " $( realpath " $0 " ) " )
8
8
cd " $DIR " || exit
9
9
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
+
10
24
function fn_main() {
25
+ git submodule update --init
26
+ fn_build_limine_hosttool
11
27
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 -
14
39
}
15
40
16
41
function fn_build_rust_bins() {
17
42
cd " bins"
18
43
cargo --version
19
44
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
21
71
}
22
72
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
28
85
}
29
86
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
34
159
}
35
160
36
161
fn_main
0 commit comments