cmake: add a simple does-the-os-boot-successfully test

the test will repeated boot the operating system and use the serial log to determine
if the boot was successful. if a problem is detected, a debugger is automatically
started and attached.
This commit is contained in:
2026-03-15 09:49:44 +00:00
parent 1e9fe24b39
commit a01b5ddb11
4 changed files with 157 additions and 0 deletions

View File

@@ -1,3 +1,4 @@
include(System-Disk)
include(QEMU)
include(Bochs)
include(Test)

35
arch/x86_64/Test.cmake Normal file
View File

@@ -0,0 +1,35 @@
find_package(Python COMPONENTS Interpreter)
if (NOT Python_EXECUTABLE)
message(STATUS "QEMU: Cannot find python. Direct-kernel boot testing unavailable")
return()
endif ()
find_program(QEMU qemu-system-${TARGET_ARCH} REQUIRED)
if (NOT QEMU)
message(STATUS "QEMU: Cannot find qemu-system-${TARGET_ARCH}. Direct-kernel boot testing unavailable")
return()
endif ()
set(patched_kernel ${CMAKE_CURRENT_BINARY_DIR}/kernel/${kernel_name}.elf32)
set(generic_flags -m 1G -cpu qemu64,+rdrand)
set(this_dir ${CMAKE_SOURCE_DIR}/arch/${CMAKE_SYSTEM_PROCESSOR})
set(no_debug_flags)
if (${CMAKE_HOST_SYSTEM_NAME} STREQUAL "Linux")
message(STATUS "QEMU: Enabling KVM acceleration")
set(no_debug_flags ${no_debug_flags} -enable-kvm)
else ()
message(STATUS "QEMU: Host system is not Linux. KVM acceleration unavailable")
endif ()
message(STATUS "Test: Enable direct-kernel boot testing with QEMU")
add_custom_target(test-successful-boot
COMMAND
${this_dir}/test/successful-boot
${Python_EXECUTABLE}
${this_dir}/test/check-results
${QEMU}
${patched_kernel}
${sys_dir}/${bsp_name}
USES_TERMINAL
DEPENDS ${patched_kernel} bsp)

View File

@@ -0,0 +1,52 @@
#!/usr/bin/env python3
# vim: ft=python
import sys
def log(f, msg):
print(msg)
f.write(msg)
f.write('\n')
def successful_boot(boot_log, out):
nr_panic = boot_log.count("---[ kernel panic")
if nr_panic == 1:
log(out, "Kernel panic!")
return 1
if nr_panic > 1:
log(out, "Multiple kernel panics!")
return 1
nr_boots = boot_log.count('Mango kernel version')
if nr_boots == 0:
log(out, "Kernel didn't start!")
return 1
if nr_boots > 1:
log(out, "Kernel rebooted during test!")
return 1
nr_finish = boot_log.count("ld finished")
if nr_finish == 0:
log(out, "Didn't reach end of boot sequence!")
return 1
if nr_finish > 1:
log(out, "Boot sequence performed multiple times!")
return 1
return 0
tests = {
'successful-boot': successful_boot,
}
test_name = sys.argv[1]
boot_log_path = sys.argv[2]
out_path = sys.argv[3]
boot_log_file = open(boot_log_path, 'r')
boot_log = boot_log_file.read()
boot_log_file.close()
out_file = open(out_path, 'a')
exit(tests[test_name](boot_log, out_file))

View File

@@ -0,0 +1,69 @@
#!/bin/bash
# vim: ft=bash
log_dir="test-results/successful-boot"
rm -rf $log_dir
mkdir -p $log_dir
logfile="$log_dir/main.log"
log() {
if [ -n "$logfile" ]; then
printf '%s\n' "$@" >> "$logfile"
fi
printf '%s\n' "$@"
}
log "Running boot test. Press Ctrl+\\ to stop."
declare -i result
declare -i count
declare -i pass
declare -i fail
count=0
pass=0
fail=0
python=$1
validation_script=$2
qemu=$3
kernel=$4
initrd=$5
while true; do
log "Test $count"
result_file="$log_dir/$count.log"
$qemu \
-kernel $kernel \
-initrd $initrd \
-serial file:$result_file \
-cpu qemu64,+rdrand \
--append kernel.early-console=ttyS0 -s > /dev/null &
qemu_id=$!
sleep 1.2
$python $validation_script successful-boot $result_file $logfile
result=$?
count=$count+1
if [ $result -eq 0 ]; then
pass=$pass+1
else
mv $result_file "$result_file.FAIL"
fail=$fail+1
lldb \
-o "file kernel/mango_kernel.debug" \
-o "gdb-remote localhost:1234"
fi
kill -INT $qemu_id
log "---------------"
log "Total tests: $count"
log "Pass: $pass"
log "Fail: $fail"
log "---------------"
done