diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 0cbd7f7..5428958 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -14,7 +14,7 @@ { "label": "Run QEMU", "type": "shell", - "command": "qemu-system-aarch64 -M raspi3b -cpu cortex-a72 -display none -kernel ${workspaceFolder}/target/aarch64-unknown-none/debug/nova -s -S", + "command": "qemu-system-aarch64 -M raspi3b -cpu cortex-a53 -display none -kernel ${workspaceFolder}/target/aarch64-unknown-none/debug/nova -s -S -serial stdio", "isBackground": true } ] diff --git a/kernel.img b/kernel.img new file mode 100755 index 0000000..eecf22d Binary files /dev/null and b/kernel.img differ diff --git a/src/main.rs b/src/main.rs index d1a7d4e..6aee0e2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,15 +13,33 @@ fn panic(_panic: &PanicInfo) -> ! { loop {} } +const BAUD: u32 = 115200; +const UART_CLK: u32 = 48_000_000; + const UART0_DR: u32 = 0x3F20_1000; +const UART0_FR: u32 = 0x3F20_1018; +const UART0_FR_TXFF: u32 = 1 << 5; + +const UART0_IBRD: u32 = 0x3F20_1024; +const UART0_FBRD: u32 = 0x3F20_1028; + +const UART0_CR: u32 = 0x3F20_1030; +const UART0_CR_UARTEN: u32 = 1 << 0; +const UART0_CR_TXE: u32 = 1 << 8; + +const UART0_LCRH: u32 = 0x3F20_102c; +const UART0_LCRH_FEN: u32 = 1 << 4; +const UART0_LCRH_WLEN: u32 = 11 << 5; + struct Uart; impl Write for Uart { fn write_str(&mut self, s: &str) -> fmt::Result { for byte in s.bytes() { unsafe { - core::ptr::write_volatile(UART0_DR as *mut u8, byte); + while core::ptr::read_volatile(UART0_FR as *const u32) & UART0_FR_TXFF != 0 {} + core::ptr::write_volatile(UART0_DR as *mut u32, byte as u32); } } Ok(()) @@ -36,7 +54,77 @@ pub extern "C" fn _start() -> ! { #[no_mangle] fn main() { + configure_uart(); + delay(50000); let mut uart = Uart {}; - writeln!(uart, "Hello World!\n"); - loop {} + loop { + writeln!(uart, "Hello World!"); + } +} + +pub fn configure_uart() { + let baud_div_times_64 = (UART_CLK * 4) / BAUD; + + let ibrd = baud_div_times_64 / 64; + let fbrd = baud_div_times_64 % 64; + + unsafe { + uart_enable(false); + uart_fifo_enable(false); + + core::ptr::write_volatile(UART0_IBRD as *mut u32, ibrd); + core::ptr::write_volatile(UART0_FBRD as *mut u32, fbrd); + + uart_set_lcrh(0b11, true); + + // Enable transmit and uart + let mut cr = core::ptr::read_volatile(UART0_CR as *mut u32); + cr |= UART0_CR_UARTEN | UART0_CR_TXE; + core::ptr::write_volatile(UART0_CR as *mut u32, cr); + } +} + +fn uart_enable(enable: bool) { + unsafe { + let mut cr = core::ptr::read_volatile(UART0_CR as *mut u32); + + if enable { + cr |= UART0_CR_UARTEN; + } else { + cr &= !UART0_CR_UARTEN; + } + + core::ptr::write_volatile(UART0_CR as *mut u32, cr); + } +} + +fn uart_fifo_enable(enable: bool) { + unsafe { + let mut lcrh = core::ptr::read_volatile(UART0_LCRH as *mut u32); + + if enable { + lcrh |= UART0_LCRH_FEN; + } else { + lcrh &= !UART0_LCRH_FEN; + } + + core::ptr::write_volatile(UART0_LCRH as *mut u32, lcrh); + } +} + +fn uart_set_lcrh(wlen: u32, enable_fifo: bool) { + unsafe { + let mut value = (wlen & 0b11) << 5; + if enable_fifo { + value |= UART0_LCRH_FEN; + } + core::ptr::write_volatile(UART0_LCRH as *mut u32, value); + } +} + +fn delay(count: u32) { + for _ in 0..count { + // Prevent compiler optimizing away the loop + core::sync::atomic::spin_loop_hint(); + } }