diff --git a/src/main.rs b/src/main.rs index b5d269c..e43a6f0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,8 @@ use core::panic::PanicInfo; +mod uart; + #[naked] #[no_mangle] #[link_section = ".text.init"] @@ -28,20 +30,10 @@ unsafe extern "C" fn _start() -> ! { } extern "C" fn entry() -> ! { - use core::ptr::write_volatile; - let addr = 0x1000_0000 as *mut u8; - { - // Set data size to 8 bits. - unsafe { write_volatile(addr.offset(3), 0b11) }; - // Enable FIFO. - unsafe { write_volatile(addr.offset(2), 0b1) }; - // Enable receiver buffer interrupts. - unsafe { write_volatile(addr.offset(1), 0b1) }; - } - - // UART is now set up! Let's print a message. - for byte in "Hello, world!\n".bytes() { - unsafe { write_volatile(addr, byte) }; + // UNSAFE: correct address for QEMU virt device + let mut console = unsafe { uart::Device::new(0x1000_0000) }; + for byte in "Hello, world!".bytes() { + console.put(byte); } loop {} diff --git a/src/uart.rs b/src/uart.rs new file mode 100644 index 0000000..da536c3 --- /dev/null +++ b/src/uart.rs @@ -0,0 +1,32 @@ +//! This module provides access to the UART console. + +/// Represents an initialised UART device. +pub struct Device { + base: usize, +} + +impl Device { + /// Create a new UART device. + /// # Safety + /// `base` must be the base address of a UART device. + pub unsafe fn new(base: usize) -> Self { + use core::ptr::write_volatile; + let addr = base as *mut u8; + // Set data size to 8 bits. + unsafe { write_volatile(addr.offset(3), 0b11) }; + // Enable FIFO. + unsafe { write_volatile(addr.offset(2), 0b1) }; + // Enable receiver buffer interrupts. + unsafe { write_volatile(addr.offset(1), 0b1) }; + // Return a new, initialised UART device. + Device { base } + } + + pub fn put(&mut self, character: u8) { + let ptr = self.base as *mut u8; + // UNSAFE: fine as long as self.base is valid + unsafe { + core::ptr::write_volatile(ptr, character); + } + } +}