This commit is contained in:
janis 2026-07-19 13:15:10 +02:00
parent fc9fc22261
commit bbe0551ac5
Signed by: janis
SSH key fingerprint: SHA256:bB1qbbqmDXZNT0KKD5c2Dfjg53JGhj7B3CFcLIzSqq8
8 changed files with 135 additions and 8 deletions

1
.gitignore vendored
View file

@ -1 +1,2 @@
/.direnv/
/kernel/qemu.log

View file

@ -10,8 +10,12 @@ test = false
bench = false
[lib]
test = false
test = true
bench = false
[[test]]
name = "simple"
harness = false
[dependencies]
bitflags = "2.13.1"

View file

@ -1,6 +1,7 @@
fn main() {
println!("cargo::rerun-if-changed=build.rs");
println!("cargo::rustc-link-arg-bin=kernel=-Tkernel.lds");
println!("cargo::rerun-if-changed=kernel.lds");
println!("cargo::rustc-link-arg=-Tkernel.lds");
// println!("cargo::rustc-link-arg-tests=-Tkernel.lds");
}

View file

@ -8,16 +8,41 @@ canonicalised="$(realpath -- "$bin")"
parent="$(dirname -- "$canonicalised")"
bin_name="$(basename -- "$canonicalised")"
image="$parent/$bin_name.img"
parent_base="$(basename -- "$parent")"
case "$parent_base" in
rustdoctest*)
is_doctest=1
;;
*)
is_doctest=0
;;
esac
case "$parent" in
*/deps|*/deps/)
is_test=1
;;
*)
is_test=$is_doctest
;;
esac
echo "Running $bin_name (is_test=$is_test, is_doctest=$is_doctest)"
if [[ $is_test -eq 1 ]]; then
QEMU_TEST_ARGS=("-display" "none" "-device" "isa-debug-exit,iobase=0xf4,iosize=0x04")
else
QEMU_TEST_ARGS=()
fi
image="$parent/$bin_name.img"
if [[ "$canonicalised" -nt "$image" ]]; then
echo "Creating image $image"
cat > /tmp/limine.conf <<EOF
timeout: 0
serial: yes
serial_baudrate: 9600
/Kernel
protocol: limine
@ -39,10 +64,22 @@ EOF
mcopy -i "$image" "$limine_uefi_path" ::/EFI/BOOT/BOOTX64.EFI
fi
# cp -n "$OVMF_PATH/FV/OVMF_VARS.fd" "$parent/$bin_name.OVMF_VARS.fd"
set +e
qemu-system-x86_64 \
-drive file="$image",format=raw \
-machine q35,accel=kvm -enable-kvm \
-drive if=pflash,format=raw,readonly=on,file="$OVMF_PATH/FV/OVMF_CODE.fd" \
-serial stdio \
-vga std
-chardev stdio,id=serial0,logfile=qemu.log,signal=off \
-serial chardev:serial0 \
-vga std \
${QEMU_TEST_ARGS[@]}
qemu_ret=$?
if [[ $is_test -eq 1 ]]; then
exit $([ $qemu_ret -eq 33 ])
fi

View file

@ -1,11 +1,19 @@
#![no_std]
#![feature(const_trait_impl, const_default)]
#![cfg_attr(test, feature(custom_test_frameworks))]
#![cfg_attr(test, test_runner(crate::tests::test_runner))]
#![cfg_attr(test, no_main)]
#![cfg_attr(test, reexport_test_harness_main = "test_main")]
pub mod limine;
pub mod serial;
pub mod sync;
pub mod x86_64;
pub mod testing;
#[cfg(test)]
mod tests;
/// # Safety
pub unsafe fn volatile_copy<T: Sized>(src: *const T, dst: *mut T, count: usize) {
unsafe {

37
kernel/src/testing.rs Normal file
View file

@ -0,0 +1,37 @@
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u16)]
pub enum QemuExitCode {
Success = 0x10,
Failed = 0x11,
}
pub fn exit_qemu(exit_code: QemuExitCode) -> ! {
use crate::x86_64::PortU16;
unsafe {
let port = PortU16(0xf4);
port.write(exit_code as u16);
}
crate::x86_64::halt_loop()
}
pub fn test_panic_handler(info: &core::panic::PanicInfo) -> ! {
crate::serial_println!("[PANIC] {}", info);
exit_qemu(QemuExitCode::Failed)
}
pub trait Testable {
fn run(&self);
}
impl<T> Testable for T
where
T: Fn(),
{
fn run(&self) {
crate::serial_print!("{}...\t", core::any::type_name::<T>());
self();
crate::serial_println!("[ok]");
}
}

26
kernel/src/tests.rs Normal file
View file

@ -0,0 +1,26 @@
use crate::testing::{QemuExitCode, Testable, exit_qemu};
pub fn test_runner(tests: &[&dyn Testable]) {
crate::serial_println!("Running {} tests", tests.len());
for test in tests {
test.run();
}
crate::serial_println!("[ok] All tests passed");
}
#[panic_handler]
fn panic_thunk(info: &core::panic::PanicInfo) -> ! {
crate::testing::test_panic_handler(info)
}
#[unsafe(export_name = "_start")]
fn main() -> ! {
crate::test_main();
exit_qemu(QemuExitCode::Success)
}
// #[test_case]
// fn panics() {
// panic!("This test should panic");
// }

13
kernel/tests/simple.rs Normal file
View file

@ -0,0 +1,13 @@
#![no_main]
#![no_std]
#[unsafe(export_name = "_start")]
pub extern "C" fn main() -> ! {
kernel::serial_println!("Hello, world!");
kernel::testing::exit_qemu(kernel::testing::QemuExitCode::Success)
}
#[panic_handler]
fn panic_thunk(info: &core::panic::PanicInfo) -> ! {
kernel::testing::test_panic_handler(info)
}