diff --git a/Cargo.lock b/Cargo.lock index ff21abbb..370d630a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -25,6 +25,7 @@ dependencies = [ "bootloader 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "uart_16550 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "volatile 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "x86_64 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -209,6 +210,15 @@ dependencies = [ "remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "uart_16550" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "x86_64 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "unicode-width" version = "0.1.5" @@ -316,6 +326,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ceac490aa12c567115b40b7b7fceca03a6c9d53d5defea066123debc83c5dc1f" "checksum spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44363f6f51401c34e7be73db0db371c04705d35efbe9f7d6082e03a921a32c55" "checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" +"checksum uart_16550 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b9392f60931fe3bf8f24e0a15ee4f51528770f1d64c48768ab66571334d95b0" "checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" "checksum usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f70329e2cbe45d6c97a5112daad40c34cd9a4e18edb5a2a18fefeb584d8d25e5" "checksum ux 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "88dfeb711b61ce620c0cb6fd9f8e3e678622f0c971da2a63c4b3e25e88ed012f" diff --git a/Cargo.toml b/Cargo.toml index 4e17de9a..c5987010 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,7 @@ bootloader = "0.6.0" volatile = "0.2.3" spin = "0.4.9" x86_64 = "0.5.2" +uart_16550 = "0.2.0" [dependencies.lazy_static] version = "1.0" @@ -22,5 +23,7 @@ panic = "abort" [package.metadata.bootimage] default-target = "x86_64-blog_os.json" -test-args = ["-device", "isa-debug-exit,iobase=0xf4,iosize=0x04"] +test-args = [ + "-device", "isa-debug-exit,iobase=0xf4,iosize=0x04", "-serial", "mon:stdio" +] test-success-exit-code = 33 # (0x10 << 1) | 1 diff --git a/src/main.rs b/src/main.rs index 7180308a..4798dec4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,6 +6,7 @@ use core::panic::PanicInfo; +mod serial; mod vga_buffer; #[no_mangle] @@ -20,7 +21,7 @@ pub extern "C" fn _start() -> ! { #[cfg(test)] fn test_runner(tests: &[&dyn Fn()]) { - println!("Running {} tests", tests.len()); + serial_println!("Running {} tests", tests.len()); for test in tests { test(); } @@ -50,7 +51,7 @@ pub unsafe fn exit_qemu(exit_code: QemuExitCode) { #[test_case] fn trivial_assertion() { - print!("trivial assertion... "); + serial_print!("trivial assertion... "); assert_eq!(1, 1); - println!("[ok]"); + serial_println!("[ok]"); } diff --git a/src/serial.rs b/src/serial.rs new file mode 100644 index 00000000..e8807df8 --- /dev/null +++ b/src/serial.rs @@ -0,0 +1,37 @@ +use lazy_static::lazy_static; +use spin::Mutex; +use uart_16550::SerialPort; + +lazy_static! { + pub static ref SERIAL1: Mutex = { + let mut serial_port = unsafe { SerialPort::new(0x3F8) }; + 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("Printing to serial failed"); +} + +/// Prints to the host through the serial interface. +#[macro_export] +macro_rules! serial_print { + ($($arg:tt)*) => { + $crate::serial::_print(format_args!($($arg)*)); + }; +} + +/// Prints to the host through the serial interface, appending a newline. +#[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)*)); +}