mirror of
https://github.com/panpaul/tiny_os
synced 2024-09-20 09:45:19 +08:00
feat: refactor kernel/plat: add generate_driver
macro for static dispatch
This commit is contained in:
parent
a3b70e1c49
commit
f03800f35e
@ -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<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) {
|
||||
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() {
|
||||
|
@ -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 {}
|
||||
|
@ -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<u8> {
|
||||
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 {}
|
||||
|
@ -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
|
||||
|
@ -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<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));
|
||||
generate_driver!(
|
||||
ConsoleDriver {
|
||||
(Uart16550, UartSifive),
|
||||
(SilenceConsole, EarlyConsole)
|
||||
} : ConsoleDevice {
|
||||
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 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<u8> {
|
||||
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<ConsoleDriver> = Mutex::new(ConsoleDriver::SilenceConsole(SilenceConsole));
|
||||
|
@ -4,3 +4,5 @@ pub mod irq;
|
||||
pub mod lowlevel;
|
||||
pub mod timer;
|
||||
pub mod trap;
|
||||
|
||||
mod utils;
|
||||
|
52
kernel/src/plat/utils.rs
Normal file
52
kernel/src/plat/utils.rs
Normal 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;
|
@ -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) => {
|
||||
|
Loading…
Reference in New Issue
Block a user