From a5fb50ffb5e08c6f2e68e4e55f05e86d6a39ec86 Mon Sep 17 00:00:00 2001 From: Greg Shuflin Date: Sun, 20 Feb 2022 02:01:45 -0800 Subject: [PATCH] Tests and test output over serial working --- .cargo/config | 3 +++ Cargo.lock | 41 +++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 6 ++++++ src/main.rs | 42 ++++++++++++++++++++++++++++++++++++++++++ src/serial.rs | 33 +++++++++++++++++++++++++++++++++ 5 files changed, 125 insertions(+) create mode 100644 src/serial.rs diff --git a/.cargo/config b/.cargo/config index f6a4ad5..62f4a82 100644 --- a/.cargo/config +++ b/.cargo/config @@ -5,3 +5,6 @@ build-std-features = ["compiler-builtins-mem"] [build] target = "x86_64_target.json" +# Facilitates running tests with qemu +[target.'cfg(target_os = "none")'] +runner = "bootimage runner" diff --git a/Cargo.lock b/Cargo.lock index 9bf077c..5c9e9e5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,18 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "bit_field" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcb6dd1c2376d2e096796e234a70e17e94cc2d5d54ff8ce42b28cef1d0d359a4" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + [[package]] name = "bootloader" version = "0.9.21" @@ -33,6 +45,8 @@ dependencies = [ "bootloader", "lazy_static", "spin 0.9.2", + "uart_16550", + "x86_64", ] [[package]] @@ -55,3 +69,30 @@ checksum = "511254be0c5bcf062b019a6c89c01a664aa359ded62f78aa72c6fc137c0590e5" dependencies = [ "lock_api", ] + +[[package]] +name = "uart_16550" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af81448a9a53c7b0f66198381f80912fd18f2c8965f9da4319e6f92e740bca5b" +dependencies = [ + "bitflags", + "x86_64", +] + +[[package]] +name = "volatile" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4c2dbd44eb8b53973357e6e207e370f0c1059990df850aca1eca8947cf464f0" + +[[package]] +name = "x86_64" +version = "0.14.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "958ab3202b01bc43ba2eb832102c4a487ed93151667a2289062e5f2b00058be2" +dependencies = [ + "bit_field", + "bitflags", + "volatile", +] diff --git a/Cargo.toml b/Cargo.toml index 5caf1f3..834d407 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,8 +8,14 @@ edition = "2021" #bootloader = "0.10.12" bootloader = "0.9.8" spin = "0.9.2" +x86_64 = "0.14.8" +uart_16550 = "0.2.16" [dependencies.lazy_static] version = "1.4.0" features = ["spin_no_std"] + +[package.metadata.bootimage] +test-args = ["-device", "isa-debug-exit,iobase=0xf4,iosize=0x04", "-serial", "stdio"] +test-success-exit-code = 33 # (0x10 << 1) | 1 diff --git a/src/main.rs b/src/main.rs index bbacd23..556493f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,8 +2,14 @@ #![no_std] #![no_main] +#![feature(custom_test_frameworks)] +#![test_runner(crate::test_runner)] +#![reexport_test_harness_main = "test_main"] + #[macro_use] mod vga_buffer; +#[macro_use] +mod serial; use core::panic::PanicInfo; @@ -15,6 +21,42 @@ fn panic(info: &PanicInfo) -> ! { #[no_mangle] pub extern "C" fn _start() -> ! { + #[cfg(test)] + test_main(); + println!("Gamarjoba, munde!"); loop {} } + +#[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); // isa-debug-exit port, see Cargo.toml + port.write(exit_code as u32); + } +} + +#[cfg(test)] +fn test_runner(tests: &[&dyn Fn()]) { + serial_println!("Running {} test(s)", tests.len()); + for test in tests { + test(); + } + + exit_qemu(QemuExitCode::Success); +} + +#[test_case] +fn basic_test() { + serial_print!("Trivial test... "); + assert_eq!(5, 5); + serial_println!("[ok]"); +} + diff --git a/src/serial.rs b/src/serial.rs new file mode 100644 index 0000000..870f82d --- /dev/null +++ b/src/serial.rs @@ -0,0 +1,33 @@ +use uart_16550::SerialPort; +use spin::Mutex; +use lazy_static::lazy_static; + + +lazy_static! { + pub static ref SERIAL1: Mutex = { + let mut serial_port = unsafe { SerialPort::new(0x3f8) }; // 0x3f8 is standard address of 1st serial port + serial_port.init(); + Mutex::new(serial_port) + }; +} + +#[doc(hidden)] +pub fn _print(args: ::core::fmt::Arguments) { + use core::fmt::Write; + SERIAL1.lock().write_fmt(args).expect("Serial print failed"); +} + +#[macro_export] +macro_rules! serial_print { + ($($arg:tt)*) => { + $crate::serial::_print(format_args!($($arg)*)); + }; +} + +#[macro_export] +macro_rules! serial_println { + () => ($crate::serial_print!("\n")); + ($fmt:expr) => ($crate::serial_print!(concat!($fmt, "\n"))); + ($fmt:expr, $($arg:tt)*) => ($crate::serial_print!( + concat!($fmt, "\n"), $($arg)*)); +}