diff --git a/Cargo.lock b/Cargo.lock index 32abb9fcd73ca6960922090e2cc36e3edfda0889..8ad2739498c3ca05f968e9984d7b74778be6e17c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -83,18 +83,18 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.2" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" +checksum = "dc948ebb96241bb40ab73effeb80d9f93afaad49359d159a5e61be51619fe813" dependencies = [ "libc", ] [[package]] name = "crypto-common" -version = "0.1.3" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", "typenum", @@ -113,9 +113,9 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.14.5" +version = "0.14.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" +checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" dependencies = [ "typenum", "version_check", @@ -123,9 +123,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.121" +version = "0.2.132" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efaa7b300f3b5fe8eb6bf21ce3895e1751d9665086af2d64b42f19701015ff4f" +checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5" [[package]] name = "linked_list_allocator" @@ -148,9 +148,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.16" +version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6389c490849ff5bc16be905ae24bc913a9c8892e19b2341dbc175e14c341c2b8" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" dependencies = [ "cfg-if", ] @@ -163,9 +163,9 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "raw-cpuid" -version = "10.3.0" +version = "10.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "738bc47119e3eeccc7e94c4a506901aea5e7b4944ecd0829cbebf4af04ceda12" +checksum = "6aa2540135b6a94f74c7bc90ad4b794f822026a894f3d7bcd185c100d13d4ad6" dependencies = [ "bitflags", ] @@ -174,6 +174,7 @@ dependencies = [ name = "redox_bootloader" version = "1.0.0" dependencies = [ + "bitflags", "linked_list_allocator", "log", "redox_syscall", @@ -192,9 +193,9 @@ checksum = "c4e4404b4e54e59e7bb5f5236b61d8e822c2a77b2e955be8072002ff7ff8d69c" [[package]] name = "redox_syscall" -version = "0.2.13" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ "bitflags", ] @@ -254,9 +255,9 @@ checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" [[package]] name = "spin" -version = "0.9.2" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "511254be0c5bcf062b019a6c89c01a664aa359ded62f78aa72c6fc137c0590e5" +checksum = "7f6002a767bff9e83f8eeecf883ecb8011875a21ae8da43bffb817a57e78cc09" dependencies = [ "lock_api", ] diff --git a/Cargo.toml b/Cargo.toml index 34848d2a73f417cb79ca8775a2182b3661a1653d..6f9a00fe6a8c7e401eef02d04c8f1e821f2a9daf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,9 +15,10 @@ path = "src/main.rs" crate-type = ["staticlib"] [dependencies] +bitflags = "1.3.2" linked_list_allocator = "0.9.1" log = "0.4.14" -redox_syscall = "0.2.13" +redox_syscall = "0.2.16" spin = "0.9.2" [dependencies.redoxfs] @@ -35,3 +36,4 @@ x86 = "0.47.0" [features] default = [] live = [] +serial_debug = [] diff --git a/src/main.rs b/src/main.rs index 4bedad79dd14280fed91e5fac76165da8b862a6f..8135ad8dee50525264042a840f3f8601c695c05f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -35,6 +35,7 @@ mod os; mod arch; mod logger; +mod serial_16550; const KIBI: usize = 1024; const MIBI: usize = KIBI * KIBI; diff --git a/src/os/bios/macros.rs b/src/os/bios/macros.rs index a8d28d471ca0c69046902180d6157c62cb9f885e..38f4a313ffe228fd9f7f9967be1f446bee4436c9 100644 --- a/src/os/bios/macros.rs +++ b/src/os/bios/macros.rs @@ -3,6 +3,10 @@ macro_rules! print { ($($arg:tt)*) => ({ use core::fmt::Write; + #[cfg(feature = "serial_debug")] + { + let _ = write!($crate::os::serial::COM1.lock(), $($arg)*); + } let _ = write!($crate::os::VGA.lock(), $($arg)*); }); } diff --git a/src/os/bios/mod.rs b/src/os/bios/mod.rs index efc2c5ee11d0d3284eb0c1cbe463dc9334a03b55..9dd929607fac0f2d56b2774beca52ea9775ba585 100644 --- a/src/os/bios/mod.rs +++ b/src/os/bios/mod.rs @@ -22,6 +22,7 @@ mod macros; mod disk; mod memory_map; mod panic; +pub(crate) mod serial; mod thunk; mod vbe; mod vga; @@ -184,6 +185,13 @@ pub unsafe extern "C" fn start( thunk15: extern "C" fn(), thunk16: extern "C" fn(), ) -> ! { + #[cfg(feature = "serial_debug")] + { + let mut com1 = serial::COM1.lock(); + com1.init(); + com1.write(b"SERIAL\n"); + } + { // Make sure we are in mode 3 (80x25 text mode) let mut data = ThunkData::new(); diff --git a/src/os/bios/serial.rs b/src/os/bios/serial.rs new file mode 100644 index 0000000000000000000000000000000000000000..60505a00d2d35d339365df202be58aec7f96644d --- /dev/null +++ b/src/os/bios/serial.rs @@ -0,0 +1,9 @@ +use spin::Mutex; +use syscall::{Io, Pio}; + +use crate::serial_16550::SerialPort; + +pub static COM1: Mutex<SerialPort<Pio<u8>>> = Mutex::new(SerialPort::<Pio<u8>>::new(0x3F8)); +pub static COM2: Mutex<SerialPort<Pio<u8>>> = Mutex::new(SerialPort::<Pio<u8>>::new(0x2F8)); +pub static COM3: Mutex<SerialPort<Pio<u8>>> = Mutex::new(SerialPort::<Pio<u8>>::new(0x3E8)); +pub static COM4: Mutex<SerialPort<Pio<u8>>> = Mutex::new(SerialPort::<Pio<u8>>::new(0x2E8)); diff --git a/src/serial_16550.rs b/src/serial_16550.rs new file mode 100644 index 0000000000000000000000000000000000000000..c255abc18107c4e9c5d0640db89a79ef8bbc3f21 --- /dev/null +++ b/src/serial_16550.rs @@ -0,0 +1,140 @@ +use bitflags::bitflags; +use core::convert::TryInto; +use core::fmt; +use syscall::io::{Io, Mmio, ReadOnly}; +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +use syscall::io::Pio; + +bitflags! { + /// Interrupt enable flags + struct IntEnFlags: u8 { + const RECEIVED = 1; + const SENT = 1 << 1; + const ERRORED = 1 << 2; + const STATUS_CHANGE = 1 << 3; + // 4 to 7 are unused + } +} + +bitflags! { + /// Line status flags + struct LineStsFlags: u8 { + const INPUT_FULL = 1; + // 1 to 4 unknown + const OUTPUT_EMPTY = 1 << 5; + // 6 and 7 unknown + } +} + +#[allow(dead_code)] +#[repr(packed)] +pub struct SerialPort<T: Io> { + /// Data register, read to receive, write to send + data: T, + /// Interrupt enable + int_en: T, + /// FIFO control + fifo_ctrl: T, + /// Line control + line_ctrl: T, + /// Modem control + modem_ctrl: T, + /// Line status + line_sts: ReadOnly<T>, + /// Modem status + modem_sts: ReadOnly<T>, +} + +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +impl SerialPort<Pio<u8>> { + pub const fn new(base: u16) -> SerialPort<Pio<u8>> { + SerialPort { + data: Pio::new(base), + int_en: Pio::new(base + 1), + fifo_ctrl: Pio::new(base + 2), + line_ctrl: Pio::new(base + 3), + modem_ctrl: Pio::new(base + 4), + line_sts: ReadOnly::new(Pio::new(base + 5)), + modem_sts: ReadOnly::new(Pio::new(base + 6)), + } + } +} + +impl SerialPort<Mmio<u32>> { + pub unsafe fn new(base: usize) -> &'static mut SerialPort<Mmio<u32>> { + &mut *(base as *mut Self) + } +} + +impl<T: Io> SerialPort<T> +where + T::Value: From<u8> + TryInto<u8>, +{ + pub fn init(&mut self) { + // Disable all interrupts + self.int_en.write(0x00.into()); + // Use DLAB register + self.line_ctrl.write(0x80.into()); + // Set divisor to 1 (115200 baud) + self.data.write(0x01.into()); + self.int_en.write(0x00.into()); + // 8 bits, no parity, one stop bit + self.line_ctrl.write(0x03.into()); + // Enable FIFO, clear FIFO, 14-byte threshold + self.fifo_ctrl.write(0xC7.into()); + // Enable IRQs and set RTS/DSR + self.modem_ctrl.write(0x0B.into()); + } + + fn line_sts(&self) -> LineStsFlags { + LineStsFlags::from_bits_truncate( + (self.line_sts.read() & 0xFF.into()) + .try_into() + .unwrap_or(0), + ) + } + + pub fn receive(&mut self) -> Option<u8> { + if self.line_sts().contains(LineStsFlags::INPUT_FULL) { + Some( + (self.data.read() & 0xFF.into()) + .try_into() + .unwrap_or(0), + ) + } else { + None + } + } + + pub fn send(&mut self, data: u8) { + while !self.line_sts().contains(LineStsFlags::OUTPUT_EMPTY) {} + self.data.write(data.into()) + } + + pub fn write(&mut self, buf: &[u8]) { + for &b in buf { + match b { + 8 | 0x7F => { + self.send(8); + self.send(b' '); + self.send(8); + } + b'\n' => { + self.send(b'\r'); + self.send(b'\n'); + } + _ => { + self.send(b); + } + } + } + } +} + +impl<T: Io> fmt::Write for SerialPort<T> +where T::Value: From<u8> + TryInto<u8> { + fn write_str(&mut self, s: &str) -> fmt::Result { + self.write(s.as_bytes()); + Ok(()) + } +} \ No newline at end of file