From 403c53fd6c7059c159db1604eb178251239fc4bf Mon Sep 17 00:00:00 2001 From: Dennis Kobert Date: Mon, 4 Nov 2019 03:25:16 +0100 Subject: Implement serial connection and basic testing --- kernel/.cargo/config | 4 ++++ kernel/Cargo.toml | 2 ++ kernel/run | 39 +++++++++++++++++++++++++--------- kernel/src/io/mod.rs | 2 +- kernel/src/io/qemu.rs | 15 ++++++++++++++ kernel/src/io/serial.rs | 53 +++++++++++++++++++++++++++++++---------------- kernel/src/io/vga_text.rs | 1 + kernel/src/lib.rs | 16 ++++++++------ 8 files changed, 97 insertions(+), 35 deletions(-) create mode 100644 kernel/src/io/qemu.rs diff --git a/kernel/.cargo/config b/kernel/.cargo/config index a0b86ef..b74f97c 100644 --- a/kernel/.cargo/config +++ b/kernel/.cargo/config @@ -1,2 +1,6 @@ [build] target = "x86_64-uff.json" +rustflags = ["-Clink-arg=-r","-Clink-dead-code"] + +[target.'cfg(target_os = "none")'] +runner = "./run test -test" diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index e14865e..660cb80 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -13,6 +13,8 @@ sysroot_path = "target/sysroot" [dependencies] x86_64 = "0.7.5" +uart_16550 = "0.2.1" +spin = "0.5" [dependencies.compiler_builtins] version = "0.1.19" diff --git a/kernel/run b/kernel/run index d8aa011..c18450b 100755 --- a/kernel/run +++ b/kernel/run @@ -16,6 +16,7 @@ function define_vars() { target_name="$target-$name" target_path="target/" rust_target_path="$target_path/$target_name/$build_mode/" + kernel_libary="$rust_target_path/libkernel.a" iso_path="$target_path/iso/" obj_path="$iso_path/obj/" src_path="src/" @@ -42,11 +43,12 @@ print_help() { } get_rust_bin() { - if $test_mode; then - echo "$rust_target_path/$(ls -t1 $rust_target_path | grep -P '^kernel-[a-fA-F0-9]+$' | head -n1)" - else - echo "$rust_target_path/libkernel.a" - fi + #if $test_mode; then + # echo "$rust_target_path/$(ls -t1 $rust_target_path | grep -P '^kernel-[a-fA-F0-9]+$' | head -n1)" + #else + # echo "$rust_target_path/libkernel.a" + #fi + echo "$kernel_libary" } prepare_iso() { @@ -64,16 +66,20 @@ prepare_iso() { build_iso() { ld -n -o "$iso_path/isofiles/boot/kernel.bin" -gc-sections -T "$link_script" "$obj_path"/*.o "$(get_rust_bin)" - grub-mkrescue -d /usr/lib/grub/i386-pc -o "$iso_path/$name.iso" "$iso_path/isofiles" + grub-mkrescue -d /usr/lib/grub/i386-pc -o "$iso_path/$name.iso" "$iso_path/isofiles" &> /dev/null + echo "$kernel_libary" } build() { if test ! -d "$iso_path/isofiles"; then prepare_iso fi - if $test_mode; then - RUSTFLAGS="-Clink-arg=-r -Clink-dead-code" cargo xtest --no-run - else + #if $test_mode; then + # RUSTFLAGS="-Clink-arg=-r -Clink-dead-code" cargo xtest --no-run + #else + # cargo xbuild + #fi + if ! $test_mode; then cargo xbuild fi build_iso @@ -82,7 +88,18 @@ build() { run() { case "$target" in "x86_64") - qemu-system-x86_64 -cdrom "$iso_path/$name.iso";; + qemu="qemu-system-x86_64 -cdrom $iso_path/$name.iso" + if $test_mode; then + qemu="$qemu -device isa-debug-exit,iobase=0xf4,iosize=0x04 -serial stdio -display none" + fi + $qemu + case "$?" in + 33) exit 0;; + 35) exit 1;; + *) + echo "qemu exited unexpectedly $?"; + exit 1;; + esac;; *) echo "error: no laucher defined for target '$target'";; esac @@ -98,6 +115,8 @@ for arg in "$@"; do target="$(echo $arg | sed "s/^-target=//")"; define_vars;; -test) test_mode=true; define_vars;; + /*kernel-*) + kernel_libary=$arg;; "run") action=run;; "build") action=build;; "test") action=test;; diff --git a/kernel/src/io/mod.rs b/kernel/src/io/mod.rs index 8a0652e..9ac924a 100644 --- a/kernel/src/io/mod.rs +++ b/kernel/src/io/mod.rs @@ -1,3 +1,3 @@ +pub mod qemu; pub mod serial; pub mod vga_text; - diff --git a/kernel/src/io/qemu.rs b/kernel/src/io/qemu.rs new file mode 100644 index 0000000..8b01885 --- /dev/null +++ b/kernel/src/io/qemu.rs @@ -0,0 +1,15 @@ +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[repr(u32)] +pub enum QemuExitCode { + Success = 0x10, // The actual exit code is (value << 1) | 1. + 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); + } +} diff --git a/kernel/src/io/serial.rs b/kernel/src/io/serial.rs index e1d4660..2a3bae8 100644 --- a/kernel/src/io/serial.rs +++ b/kernel/src/io/serial.rs @@ -1,25 +1,42 @@ -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -#[repr(u32)] -pub enum QemuExitCode { - Success = 0x10, // The actual exit code is (value << 1) | 1. - Failed = 0x11, +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) + }; +}*/ +const SERIAL_IO_PORT: u16 = 0x3F8; + +static CONNECTION: Mutex = Mutex::new(Serial { + initialized: false, + port: unsafe { SerialPort::new(SERIAL_IO_PORT) }, +}); + +struct Serial { + pub initialized: bool, + pub port: SerialPort, } -pub fn exit_qemu(exit_code: QemuExitCode) { - use x86_64::instructions::port::Port; +pub struct SerialStream {} - unsafe { - let mut port = Port::new(0xf4); - port.write(exit_code as u32); +impl SerialStream { + pub fn new() -> Self { + SerialStream {} } } -fn trivial_assertion() { - use crate::io::vga_text::OStream; - let mut stdout = OStream::new(); - stdout.clear(); - - stdout.print(b"trivial assertion... "); - assert_eq!(0, 1); - stdout.print(b"[ok]"); +impl core::fmt::Write for SerialStream { + fn write_str(&mut self, s: &str) -> core::fmt::Result { + let mut guard = CONNECTION.lock(); + if !guard.initialized { + unsafe { + guard.port.init(); + } + guard.initialized = true; + } + guard.port.write_str(s) + } } diff --git a/kernel/src/io/vga_text.rs b/kernel/src/io/vga_text.rs index 34f13a8..fddb3e1 100644 --- a/kernel/src/io/vga_text.rs +++ b/kernel/src/io/vga_text.rs @@ -1,3 +1,4 @@ +#[allow(dead_code)] #[repr(u8)] pub enum Color { Black = 0, diff --git a/kernel/src/lib.rs b/kernel/src/lib.rs index 74daa8a..8d967ad 100644 --- a/kernel/src/lib.rs +++ b/kernel/src/lib.rs @@ -10,8 +10,8 @@ extern crate compiler_builtins; mod io; use core::fmt::Write; -use io::vga_text; use io::vga_text::OStream; +use io::{qemu, serial, vga_text}; #[cfg(test)] pub fn test_runner(tests: &[&dyn Fn(&mut OStream)]) { @@ -26,6 +26,8 @@ pub fn test_runner(tests: &[&dyn Fn(&mut OStream)]) { #[test_case] fn test01(stdout: &mut OStream) { write!(stdout, "running test01 . . . OK"); + write!(serial::SerialStream::new(), "running test01 . . . OK\n"); + assert_eq!(0, 1); } #[no_mangle] @@ -33,16 +35,14 @@ pub extern "C" fn _start() -> ! { if cfg!(test) { #[cfg(test)] test_main(); - loop {} + qemu::exit_qemu(qemu::QemuExitCode::Success); } - let mut stdout = vga_text::OStream::new(); + let mut stdout = OStream::new(); stdout.clear(); write!(&mut stdout, "hello world!"); - // panic!("i has panicing"); - core::iter::successors(Some(0), |n| Some(n + 1)) .for_each(|n| write!(&mut stdout, "hello world {}!", n).unwrap()); @@ -52,7 +52,7 @@ pub extern "C" fn _start() -> ! { #[panic_handler] #[no_mangle] pub extern "C" fn panic_handler(_info: &core::panic::PanicInfo) -> ! { - let mut stderr = vga_text::OStream::new(); + let mut stderr = OStream::new(); stderr.set_state(vga_text::CharState::from_colors( vga_text::Color::LightRed, vga_text::Color::Red, @@ -75,5 +75,9 @@ pub extern "C" fn panic_handler(_info: &core::panic::PanicInfo) -> ! { vga_text::Color::Red, )); stderr.print_centered(text.as_bytes()); + if cfg!(test) { + write!(serial::SerialStream::new(), "Testing failed\n"); + qemu::exit_qemu(qemu::QemuExitCode::Failed); + } loop {} } -- cgit v1.2.3-54-g00ecf