feat: refactor kernel/plat: add generate_driver macro for static dispatch

This commit is contained in:
Paul Pan 2024-08-23 09:54:32 +08:00
parent a3b70e1c49
commit f03800f35e
8 changed files with 107 additions and 75 deletions

View File

@ -6,14 +6,28 @@ impl ConsoleDevice for EarlyConsole {
fn read(&mut self) -> u8 { fn read(&mut self) -> u8 {
let uart = super::UART0_BASE as *mut u8; let uart = super::UART0_BASE as *mut u8;
let line_sts = super::UART0_LSR as *mut u8; let line_sts = super::UART0_LSR as *mut u8;
while unsafe { line_sts.read_volatile() } & 0x01 == 0 {} while unsafe { line_sts.read_volatile() } & 0x01 == 0 {}
unsafe { uart.read_volatile() } unsafe { uart.read_volatile() }
} }
fn try_read(&mut self) -> Option<u8> {
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) { fn write(&mut self, ch: u8) {
let uart = super::UART0_BASE as *mut u8; let uart = super::UART0_BASE as *mut u8;
unsafe { uart.write_volatile(ch) } 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() { pub fn init_early_console() {

View File

@ -171,6 +171,12 @@ impl ConsoleDevice for UartSifive {
self.tx_write(n); self.tx_write(n);
} }
fn write_str(&mut self, s: &str) -> () {
for ch in s.bytes() {
self.write(ch);
}
}
} }
impl SerialDriver for UartSifive {} impl SerialDriver for UartSifive {}

View File

@ -2,6 +2,7 @@ use crate::arch::layout::mmap_phys_to_virt;
use crate::drivers::serial::SerialDriver; use crate::drivers::serial::SerialDriver;
use crate::drivers::Driver; use crate::drivers::Driver;
use crate::plat::console::ConsoleDevice; use crate::plat::console::ConsoleDevice;
use core::fmt::Write;
use fdt::node::FdtNode; use fdt::node::FdtNode;
use fdt::Fdt; use fdt::Fdt;
use uart_16550::MmioSerialPort; use uart_16550::MmioSerialPort;
@ -32,9 +33,17 @@ impl ConsoleDevice for Uart16550 {
self.port.receive() self.port.receive()
} }
fn try_read(&mut self) -> Option<u8> {
Some(self.read())
}
fn write(&mut self, byte: u8) { fn write(&mut self, byte: u8) {
self.port.send(byte); self.port.send(byte);
} }
fn write_str(&mut self, s: &str) -> () {
self.port.write_str(s).unwrap()
}
} }
impl SerialDriver for Uart16550 {} impl SerialDriver for Uart16550 {}

View File

@ -2,10 +2,10 @@
#![no_std] #![no_std]
#![no_main] #![no_main]
// Features // Features
#![feature(cell_update)]
#![feature(concat_idents)] #![feature(concat_idents)]
#![feature(iter_array_chunks)] #![feature(iter_array_chunks)]
#![feature(let_chains)] #![feature(let_chains)]
#![feature(macro_metavar_expr)]
#![feature(naked_functions)] #![feature(naked_functions)]
#![feature(thread_local)] #![feature(thread_local)]
// Test Infrastructure // Test Infrastructure

View File

@ -1,3 +1,4 @@
use super::utils::generate_driver;
use crate::arch::EarlyConsole; use crate::arch::EarlyConsole;
use crate::drivers::serial::{Uart16550, UartSifive}; use crate::drivers::serial::{Uart16550, UartSifive};
use crate::drivers::Driver; use crate::drivers::Driver;
@ -5,64 +6,17 @@ use fdt::{node::FdtNode, Fdt};
use log::debug; use log::debug;
use spin::Mutex; use spin::Mutex;
macro_rules! create_console_driver { generate_driver!(
(($($dynamic_driver:ident),+), ($($static_driver:ident),+)) => { ConsoleDriver {
// A VERY DIRTY hack to work around dynamic dispatch (Uart16550, UartSifive),
pub enum ConsoleDriver { (SilenceConsole, EarlyConsole)
$($dynamic_driver($dynamic_driver),)+ } : ConsoleDevice {
$($static_driver($static_driver),)+ fn read(&mut self) -> u8;
fn try_read(&mut self) -> Option<u8>;
fn write(&mut self, ch: u8) -> ();
fn write_str(&mut self, s: &str) -> ();
} }
);
impl ConsoleDriver {
pub fn new(node: FdtNode, fdt: &Fdt) -> Option<Self> {
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<u8> {
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));
impl core::fmt::Write for ConsoleDriver { impl core::fmt::Write for ConsoleDriver {
fn write_str(&mut self, s: &str) -> core::fmt::Result { fn write_str(&mut self, s: &str) -> core::fmt::Result {
@ -78,25 +32,13 @@ impl ConsoleDevice for SilenceConsole {
0 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<u8> { fn try_read(&mut self) -> Option<u8> {
Some(self.read()) None
} }
/// Write a byte fn write(&mut self, _: u8) {}
fn write(&mut self, _: u8);
/// Write a str fn write_str(&mut self, _: &str) -> () {}
fn write_str(&mut self, s: &str) {
for byte in s.bytes() {
self.write(byte);
}
}
} }
pub static CONSOLE: Mutex<ConsoleDriver> = Mutex::new(ConsoleDriver::SilenceConsole(SilenceConsole)); pub static CONSOLE: Mutex<ConsoleDriver> = Mutex::new(ConsoleDriver::SilenceConsole(SilenceConsole));

View File

@ -4,3 +4,5 @@ pub mod irq;
pub mod lowlevel; pub mod lowlevel;
pub mod timer; pub mod timer;
pub mod trap; pub mod trap;
mod utils;

52
kernel/src/plat/utils.rs Normal file
View File

@ -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<Self> {
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;

View File

@ -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_export]
macro_rules! container_of_offset { macro_rules! container_of_offset {
($ptr:expr, $type:ty, $offset:expr) => { ($ptr:expr, $type:ty, $offset:expr) => {