From f03800f35edbc3dccaad99294b6f1187d8eceb07 Mon Sep 17 00:00:00 2001 From: Paul Pan Date: Fri, 23 Aug 2024 09:54:32 +0800 Subject: [PATCH] feat: refactor kernel/plat: add `generate_driver` macro for static dispatch --- kernel/src/arch/riscv/board/virt/console.rs | 14 ++++ kernel/src/drivers/serial/sifive.rs | 6 ++ kernel/src/drivers/serial/uart16550.rs | 9 +++ kernel/src/main.rs | 2 +- kernel/src/plat/console.rs | 90 ++++----------------- kernel/src/plat/mod.rs | 2 + kernel/src/plat/utils.rs | 52 ++++++++++++ lib/utils/src/container_of.rs | 7 ++ 8 files changed, 107 insertions(+), 75 deletions(-) create mode 100644 kernel/src/plat/utils.rs diff --git a/kernel/src/arch/riscv/board/virt/console.rs b/kernel/src/arch/riscv/board/virt/console.rs index ecbc926..17eb6eb 100644 --- a/kernel/src/arch/riscv/board/virt/console.rs +++ b/kernel/src/arch/riscv/board/virt/console.rs @@ -6,14 +6,28 @@ impl ConsoleDevice for EarlyConsole { fn read(&mut self) -> u8 { let uart = super::UART0_BASE as *mut u8; let line_sts = super::UART0_LSR as *mut u8; + while unsafe { line_sts.read_volatile() } & 0x01 == 0 {} unsafe { uart.read_volatile() } } + fn try_read(&mut self) -> Option { + let uart = super::UART0_BASE as *mut u8; + let line_sts = super::UART0_LSR as *mut u8; + + (unsafe { line_sts.read_volatile() } & 0x01 != 0).then(|| unsafe { uart.read_volatile() }) + } + fn write(&mut self, ch: u8) { let uart = super::UART0_BASE as *mut u8; unsafe { uart.write_volatile(ch) } } + + fn write_str(&mut self, s: &str) -> () { + for ch in s.bytes() { + self.write(ch); + } + } } pub fn init_early_console() { diff --git a/kernel/src/drivers/serial/sifive.rs b/kernel/src/drivers/serial/sifive.rs index db9211f..7b43bf8 100644 --- a/kernel/src/drivers/serial/sifive.rs +++ b/kernel/src/drivers/serial/sifive.rs @@ -171,6 +171,12 @@ impl ConsoleDevice for UartSifive { self.tx_write(n); } + + fn write_str(&mut self, s: &str) -> () { + for ch in s.bytes() { + self.write(ch); + } + } } impl SerialDriver for UartSifive {} diff --git a/kernel/src/drivers/serial/uart16550.rs b/kernel/src/drivers/serial/uart16550.rs index c2f53f8..34c55e1 100644 --- a/kernel/src/drivers/serial/uart16550.rs +++ b/kernel/src/drivers/serial/uart16550.rs @@ -2,6 +2,7 @@ use crate::arch::layout::mmap_phys_to_virt; use crate::drivers::serial::SerialDriver; use crate::drivers::Driver; use crate::plat::console::ConsoleDevice; +use core::fmt::Write; use fdt::node::FdtNode; use fdt::Fdt; use uart_16550::MmioSerialPort; @@ -32,9 +33,17 @@ impl ConsoleDevice for Uart16550 { self.port.receive() } + fn try_read(&mut self) -> Option { + Some(self.read()) + } + fn write(&mut self, byte: u8) { self.port.send(byte); } + + fn write_str(&mut self, s: &str) -> () { + self.port.write_str(s).unwrap() + } } impl SerialDriver for Uart16550 {} diff --git a/kernel/src/main.rs b/kernel/src/main.rs index 7c06b66..8fd3125 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -2,10 +2,10 @@ #![no_std] #![no_main] // Features -#![feature(cell_update)] #![feature(concat_idents)] #![feature(iter_array_chunks)] #![feature(let_chains)] +#![feature(macro_metavar_expr)] #![feature(naked_functions)] #![feature(thread_local)] // Test Infrastructure diff --git a/kernel/src/plat/console.rs b/kernel/src/plat/console.rs index d1e40d4..a4e3884 100644 --- a/kernel/src/plat/console.rs +++ b/kernel/src/plat/console.rs @@ -1,3 +1,4 @@ +use super::utils::generate_driver; use crate::arch::EarlyConsole; use crate::drivers::serial::{Uart16550, UartSifive}; use crate::drivers::Driver; @@ -5,64 +6,17 @@ use fdt::{node::FdtNode, Fdt}; use log::debug; use spin::Mutex; -macro_rules! create_console_driver { - (($($dynamic_driver:ident),+), ($($static_driver:ident),+)) => { - // A VERY DIRTY hack to work around dynamic dispatch - pub enum ConsoleDriver { - $($dynamic_driver($dynamic_driver),)+ - $($static_driver($static_driver),)+ - } - - impl ConsoleDriver { - pub fn new(node: FdtNode, fdt: &Fdt) -> Option { - if let Some(compatible) = node.compatible() { - $( - if compatible - .all() - .any(|s| $dynamic_driver::compatible().contains(&s)) - { - debug!("Console: Using driver: {}", stringify!($dynamic_driver)); - return Some(ConsoleDriver::$dynamic_driver($dynamic_driver::setup(node, fdt))); - } - )+ - } - None - } - } - - impl ConsoleDevice for ConsoleDriver { - fn read(&mut self) -> u8 { - match self { - $(ConsoleDriver::$dynamic_driver(driver) => driver.read(),)+ - $(ConsoleDriver::$static_driver(driver) => driver.read(),)+ - } - } - - fn try_read(&mut self) -> Option { - match self { - $(ConsoleDriver::$dynamic_driver(driver) => driver.try_read(),)+ - $(ConsoleDriver::$static_driver(driver) => driver.try_read(),)+ - } - } - - fn write(&mut self, n: u8) { - match self { - $(ConsoleDriver::$dynamic_driver(driver) => driver.write(n),)+ - $(ConsoleDriver::$static_driver(driver) => driver.write(n),)+ - } - } - - fn write_str(&mut self, s: &str) { - match self { - $(ConsoleDriver::$dynamic_driver(driver) => driver.write_str(s),)+ - $(ConsoleDriver::$static_driver(driver) => driver.write_str(s),)+ - } - } - } - }; -} - -create_console_driver!((Uart16550, UartSifive), (SilenceConsole, EarlyConsole)); +generate_driver!( + ConsoleDriver { + (Uart16550, UartSifive), + (SilenceConsole, EarlyConsole) + } : ConsoleDevice { + fn read(&mut self) -> u8; + fn try_read(&mut self) -> Option; + fn write(&mut self, ch: u8) -> (); + fn write_str(&mut self, s: &str) -> (); + } +); impl core::fmt::Write for ConsoleDriver { fn write_str(&mut self, s: &str) -> core::fmt::Result { @@ -78,25 +32,13 @@ impl ConsoleDevice for SilenceConsole { 0 } - fn write(&mut self, _: u8) {} -} - -pub trait ConsoleDevice { - /// Blocking read - fn read(&mut self) -> u8; - /// Non-blocking read fn try_read(&mut self) -> Option { - Some(self.read()) + None } - /// Write a byte - fn write(&mut self, _: u8); - /// Write a str - fn write_str(&mut self, s: &str) { - for byte in s.bytes() { - self.write(byte); - } - } + fn write(&mut self, _: u8) {} + + fn write_str(&mut self, _: &str) -> () {} } pub static CONSOLE: Mutex = Mutex::new(ConsoleDriver::SilenceConsole(SilenceConsole)); diff --git a/kernel/src/plat/mod.rs b/kernel/src/plat/mod.rs index dbf842a..1710ddd 100644 --- a/kernel/src/plat/mod.rs +++ b/kernel/src/plat/mod.rs @@ -4,3 +4,5 @@ pub mod irq; pub mod lowlevel; pub mod timer; pub mod trap; + +mod utils; diff --git a/kernel/src/plat/utils.rs b/kernel/src/plat/utils.rs new file mode 100644 index 0000000..0adedb8 --- /dev/null +++ b/kernel/src/plat/utils.rs @@ -0,0 +1,52 @@ +macro_rules! generate_driver { + ( + $name:ident { + ($($dynamic_driver:ident),+),($($static_driver:ident),+) + } : $trait:ident { + $(fn $fn_name:ident (&mut self $(, $arg_name:ident : $arg_ty:ty)*) -> $ret_ty:ty;)+ + } + ) => { + pub enum $name { + $($dynamic_driver($dynamic_driver),)+ + $($static_driver($static_driver),)+ + } + + pub trait $trait { + $(fn $fn_name(&mut self $(, $arg_name: $arg_ty)*) -> $ret_ty;)+ + } + + impl $name { + pub fn new(node: FdtNode, fdt: &Fdt) -> Option { + if let Some(compatible) = node.compatible() { + $( + if compatible + .all() + .any(|s| $dynamic_driver::compatible().contains(&s)) + { + debug!("{}: using driver: {}", stringify!($name), stringify!($dynamic_driver)); + return Some($name::$dynamic_driver($dynamic_driver::setup(node, fdt))); + } + )+ + } + None + } + } + + macro_rules! expand_driver { + ($$self:ident, $$fn_name:ident, $$($$arg:ident),*) => { + match $$self { + $(Self::$dynamic_driver(driver) => driver.$$fn_name($$($$arg),*),)+ + $(Self::$static_driver(driver) => driver.$$fn_name($$($$arg),*),)+ + } + }; + } + + impl $trait for $name { + $(fn $fn_name(&mut self $(, $arg_name: $arg_ty)*) -> $ret_ty { + expand_driver!(self, $fn_name, $($arg_name),*) + })+ + } + }; +} + +pub(super) use generate_driver; diff --git a/lib/utils/src/container_of.rs b/lib/utils/src/container_of.rs index 32cb2c4..e228b7b 100644 --- a/lib/utils/src/container_of.rs +++ b/lib/utils/src/container_of.rs @@ -7,6 +7,13 @@ macro_rules! container_of { }; } +#[macro_export] +macro_rules! container_of_mut { + ($ptr:expr, $type:ty, $field:ident) => { + ($ptr as *const _ as *mut u8).sub(core::mem::offset_of!($type, $field) as usize) as *mut $type + }; +} + #[macro_export] macro_rules! container_of_offset { ($ptr:expr, $type:ty, $offset:expr) => {