From c3f181a64154e15b823c41a1ede220f936102460 Mon Sep 17 00:00:00 2001 From: clizia Date: Wed, 27 Aug 2025 23:53:59 +0200 Subject: [PATCH] added tests + exiting by interacting with qemu through a I/O port --- .cargo/config.toml | 1 + Cargo.toml | 8 +++++++- src/main.rs | 40 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 1 deletion(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index f95e6aa..ef1222f 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,6 +1,7 @@ [unstable] build-std-features = ["compiler-builtins-mem"] build-std = ["core", "compiler_builtins"] +panic-abort-tests = true [build] target = "x86_64-totos.json" diff --git a/Cargo.toml b/Cargo.toml index 6cf02d0..d9de3f6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ edition = "2024" [[bin]] name = "totos" -test = false +test = true bench = false [profile.dev] @@ -18,7 +18,13 @@ panic = "abort" # disable stack unwinding on panic bootloader = "0.9" volatile = "0.2.6" spin = "0.5.2" +x86_64 = "0.14.2" [dependencies.lazy_static] version = "1.0" features = ["spin_no_std"] + +# this enables exiting qemu from the guest system +[package.metadata.bootimage] +test-args = ["-device", "isa-debug-exit,iobase=0xf4,iosize=0x04"] +test-success-exit-code = 33 # (0x10 << 1) | 1 = 33 diff --git a/src/main.rs b/src/main.rs index e13f673..cc96953 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,8 @@ #![no_std] // dont link the standard library #![no_main] // disable all rust-level entry points +#![feature(custom_test_frameworks)] +#![test_runner(crate::test_runner)] +#![reexport_test_harness_main = "test_main"] use core::panic::PanicInfo; @@ -7,12 +10,31 @@ mod vga_buffer; static HELLO: &[u8] = b"Hello toto :3"; +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u32)] +pub enum QemuExitCode { + Success = 0x10, + Failed = 0x11, +} + +pub fn exit_qemu(exit_code: QemuExitCode) { + use x86_64::instructions::port::Port; + + unsafe { + let mut port = Port::new(0xF4); + port.write(exit_code as u32); + } +} + // this function is the entry point since the linker // looks for a function named `_start` by default #[unsafe(no_mangle)] pub extern "C" fn _start() -> ! { println!("smoking cigarettes in the shower\nwhen they get wet i just light another\n:{}", 3); + #[cfg(test)] + test_main(); + loop {} } @@ -23,3 +45,21 @@ fn panic(info: &PanicInfo) -> ! { loop {} } + +#[cfg(test)] +pub fn test_runner(tests: &[&dyn Fn()]) { + println!("Running {} tests", tests.len()); + + for test in tests { + test(); + } + + exit_qemu(QemuExitCode::Success); +} + +#[test_case] +fn trivial_assertion() { + print!("asserzione triviale... "); + assert_eq!(1, 1); + println!("[ok]"); +}