diff --git a/kernel/src/arch/mipsel/io.rs b/kernel/src/arch/mipsel/io.rs index ca99ad3..e14c4ec 100644 --- a/kernel/src/arch/mipsel/io.rs +++ b/kernel/src/arch/mipsel/io.rs @@ -1,6 +1,7 @@ use core::fmt::{Write, Result, Arguments}; +use core::ptr::{read_volatile, write_volatile}; -struct SerialPort; +struct SerialPort {}; impl Write for SerialPort { fn write_str(&mut self, s: &str) -> Result { @@ -17,26 +18,40 @@ impl Write for SerialPort { } } +fn write(addr: usize, content: T) { + let cell = (addr) as *mut T; + write_volatile(cell, content); +} + +fn read(addr: usize) -> T { + let cell = (addr) as *const T; + read_volatile(cell); +} + +/// non-blocking version of putchar() fn putchar(c: u8) { - // TODO: output to uart + write(COM1 + COM_TX, c); } +/// blocking version of getchar() pub fn getchar() -> char { - // TODO: get char from uart - let c = 0 as u8; - + loop { + if (read::(COM1 + COM_LSR) & COM_LSR_DATA) == 0 { + break; + } + } + let c = read::(COM1 + COM_RX); match c { 255 => '\0', // null c => c as char, } } +/// non-blocking version of getchar() pub fn getchar_option() -> Option { - // TODO: get char from uart - let c = 0 as u8; - match c { - -1 => None, - c => Some(c as u8 as char), + match read::(COM1 + COM_LSR) & COM_LSR_DATA { + 0 => None, + else => Some(read::(COM1 + COM_RX) as u8 as char), } } @@ -44,5 +59,42 @@ pub fn putfmt(fmt: Arguments) { SerialPort.write_fmt(fmt).unwrap(); } -const TXDATA: *mut u32 = 0x38000000 as *mut u32; -const RXDATA: *mut u32 = 0x38000004 as *mut u32; +pub fn init(serial_base_addr: usize) { + COM1 = serial_base_addr; + // Turn off the FIFO + write(COM1 + COM_FCR, 0 as u8); + // Set speed; requires DLAB latch + write(COM1 + COM_LCR, COM_LCR_DLAB); + write(COM1 + COM_DLL, (115200 / 9600) as u8); + write(COM1 + COM_DLM, 0 as u8); + + // 8 data bits, 1 stop bit, parity off; turn off DLAB latch + write(COM1 + COM_LCR, COM_LCR_WLEN8 & !COM_LCR_DLAB); + + // No modem controls + write(COM1 + COM_MCR, 0 as u8); + // Enable rcv interrupts + write(COM1 + COM_IER, COM_IER_RDI); +} + +static mut COM1: usize = 0; + +const COM_RX :usize = 0; // In: Receive buffer (DLAB=0) +const COM_TX :usize = 0; // Out: Transmit buffer (DLAB=0) +const COM_DLL :usize = 0; // Out: Divisor Latch Low (DLAB=1) +const COM_DLM :usize = 1; // Out: Divisor Latch High (DLAB=1) +const COM_IER :usize = 1; // Out: Interrupt Enable Register +const COM_IER_RDI :u8 = 0x01; // Enable receiver data interrupt +const COM_IIR :usize = 2; // In: Interrupt ID Register +const COM_FCR :usize = 2; // Out: FIFO Control Register +const COM_LCR :usize = 3; // Out: Line Control Register +const COM_LCR_DLAB :u8 = 0x80; // Divisor latch access bit +const COM_LCR_WLEN8 :u8 = 0x03; // Wordlength: 8 bits +const COM_MCR :usize = 4; // Out: Modem Control Register +const COM_MCR_RTS :u8 = 0x02; // RTS complement +const COM_MCR_DTR :u8 = 0x01; // DTR complement +const COM_MCR_OUT2 :u8 = 0x08; // Out2 complement +const COM_LSR :usize = 5; // In: Line Status Register +const COM_LSR_DATA :u8 = 0x01; // Data available +const COM_LSR_TXRDY :u8 = 0x20; // Transmit buffer avail +const COM_LSR_TSRE :u8 = 0x40; // Transmitter off diff --git a/kernel/src/arch/mipsel/mod.rs b/kernel/src/arch/mipsel/mod.rs index bb3d87f..9681b06 100644 --- a/kernel/src/arch/mipsel/mod.rs +++ b/kernel/src/arch/mipsel/mod.rs @@ -38,6 +38,8 @@ pub extern fn rust_main() -> ! { unsafe { memory::clear_bss(); } + crate::io::init(); + println!("Hello MIPS 32 from CPU {}, dtb @ {:#x}", cpu_id, dtb_start); crate::logging::init();