Add rx ability to uart

This commit is contained in:
gil 2024-05-13 22:59:41 -05:00
parent 5490a2ffd6
commit 41a450393e
4 changed files with 112 additions and 6 deletions

34
Cargo.lock generated
View file

@ -2,6 +2,40 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "autocfg"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
[[package]]
name = "lock_api"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
dependencies = [
"autocfg",
"scopeguard",
]
[[package]]
name = "riscv-uefi"
version = "0.1.0"
dependencies = [
"spinning_top",
]
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "spinning_top"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d96d2d1d716fb500937168cc09353ffdc7a012be8475ac7308e1bdf0e3923300"
dependencies = [
"lock_api",
]

View file

@ -4,3 +4,4 @@ version = "0.1.0"
edition = "2021"
[dependencies]
spinning_top = "0.3.0"

View file

@ -22,6 +22,19 @@ unsafe extern "C" fn _start() -> ! {
// set the stack pointer
"la sp, _init_stack_top",
"la sp, _init_stack_top",
// clear the BSS
"la t0, _bss_start",
"la t1, _bss_end",
"bgeu t0, t1, 2f",
"1:",
"sb zero, 0(t0)",
"addi t0, t0, 1",
"bne t0, t1, 1b",
"2:",
// BSS is clear!
// "tail-call" to {entry} (call without saving a return address)
"tail {entry}",
entry = sym entry, // {entry} refers to the function [entry] below
@ -30,13 +43,16 @@ unsafe extern "C" fn _start() -> ! {
}
extern "C" fn entry() -> ! {
// 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);
}
println!("This should not print because the console is not initialised.");
unsafe { uart::init_console(0x1000_0000) };
println!("Hello, world!");
loop {}
loop {
let c = uart::CONSOLE.lock().as_mut().and_then(uart::Device::get);
if let Some(c) = c {
print!("{}", c as char);
}
}
}
#[panic_handler]

View file

@ -1,5 +1,9 @@
//! This module provides access to the UART console.
use spinning_top::Spinlock;
pub static CONSOLE: Spinlock<Option<Device>> = Spinlock::new(None);
/// Represents an initialised UART device.
pub struct Device {
base: usize,
@ -29,4 +33,55 @@ impl Device {
core::ptr::write_volatile(ptr, character);
}
}
/// Gets a character from the UART input.
pub fn get(&mut self) -> Option<u8> {
const READY: u8 = 0b1;
let ptr = self.base as *mut u8;
// SAFETY: Fine as long as base is correct.
let lsr = unsafe { ptr.offset(5) };
unsafe {
if core::ptr::read_volatile(lsr) & READY == READY {
Some(core::ptr::read_volatile(ptr))
} else {
None
}
}
}
}
impl core::fmt::Write for Device {
fn write_str(&mut self, s: &str) -> core::fmt::Result {
for c in s.bytes() {
self.put(c);
}
Ok(()) // there are never errors writing to UART :)
}
}
/// Initialise the UART debugging console.
/// # Safety
/// `base` must point to the base address of a UART device.
pub unsafe fn init_console(base: usize) {
let mut console = CONSOLE.lock();
*console = Some(unsafe { Device::new(base) });
}
/// Prints a formatted string to the [CONSOLE].
#[macro_export]
macro_rules! print {
($($arg:tt)*) => ({
use core::fmt::Write;
$crate::uart::CONSOLE.lock().as_mut().map(|writer| {
writer.write_fmt(format_args!($($arg)*)).unwrap()
});
});
}
/// println prints a formatted string to the [CONSOLE] with a trailing newline character.
#[macro_export]
macro_rules! println {
($fmt:expr) => ($crate::print!(concat!($fmt, "\n")));
($fmt:expr, $($arg:tt)*) => ($crate::print!(concat!($fmt, "\n"), $($arg)*));
}