Browse Source

新增设备驱动模型,为设备和驱动提供高层视图 (#227)

* 添加base mod

* 添加设备驱动模型相关文件

* 删除单独的mod文件,使用mod.rs,修改一些格式上的问题

* 移动驱动错误类型到该文件

* 修改一些格式上的问题
TingHuang 1 year ago
parent
commit
2a7d773d3d

+ 156 - 0
kernel/src/driver/base/device/bus.rs

@@ -0,0 +1,156 @@
+use alloc::{
+    collections::BTreeMap,
+    sync::Arc
+};
+use lazy_static::lazy_static;
+use core::fmt::Debug;
+use crate::libs::spinlock::SpinLock;
+use super::{
+    driver::Driver,
+    DeviceState,
+    IdTable,
+    Device
+};
+
+/// @brief: 总线状态
+#[derive(Debug, Copy, Clone)]
+pub enum BusState {
+    NotInitialized = 0, // 未初始化
+    Initialized = 1,    // 已初始化
+    UnDefined = 2,      // 未定义的
+}
+
+/// @brief: 将u32类型转换为总线状态类型
+impl From<u32> for BusState {
+    fn from(state: u32) -> Self {
+        match state {
+            0 => BusState::NotInitialized,
+            1 => BusState::Initialized,
+            _ => BusState::UnDefined,
+        }
+    }
+}
+
+/// @brief: 将总线状态类型转换为u32类型
+impl From<DeviceState> for BusState {
+    fn from(state: DeviceState) -> Self {
+        match state {
+            DeviceState::Initialized => BusState::Initialized,
+            DeviceState::NotInitialized => BusState::NotInitialized,
+            DeviceState::UnDefined => BusState::UnDefined,
+        }
+    }
+}
+
+/// @brief: 将总线状态类型转换为设备状态类型
+impl From<BusState> for DeviceState {
+    fn from(state: BusState) -> Self {
+        match state {
+            BusState::Initialized => DeviceState::Initialized,
+            BusState::NotInitialized => DeviceState::NotInitialized,
+            BusState::UnDefined => DeviceState::UnDefined,
+        }
+    }
+}
+
+/// @brief: 总线驱动trait,所有总线驱动都应实现该trait
+pub trait BusDriver: Driver {
+    /// @brief: 判断总线是否为空
+    /// @parameter: None
+    /// @return: 如果总线上设备和驱动的数量都为0,则返回true,否则,返回false
+    fn is_empty(&self) -> bool;
+}
+
+/// @brief: 总线设备trait,所有总线都应实现该trait
+pub trait Bus: Device {}
+
+/// @brief: 总线管理结构体
+#[derive(Debug, Clone)]
+pub struct BusManager {
+    buses: BTreeMap<IdTable, Arc<dyn Bus>>,          // 总线设备表
+    bus_drvs: BTreeMap<IdTable, Arc<dyn BusDriver>>, // 总线驱动表
+}
+
+/// @brief: 总线管理结构体加锁
+pub struct BusManagerLock(SpinLock<BusManager>);
+
+/// @brief: 总线管理方法集
+impl BusManagerLock {
+    /// @brief: 创建总线管理实例
+    /// @parameter: None
+    /// @return: 总线管理实例
+    #[inline]
+    #[allow(dead_code)]
+    pub fn new() -> Self {
+        BusManagerLock(SpinLock::new(BusManager {
+            buses: BTreeMap::new(),
+            bus_drvs: BTreeMap::new(),
+        }))
+    }
+
+    /// @brief: 添加总线
+    /// @parameter id_table: 总线标识符,用于唯一标识该总线
+    /// @parameter bus_dev: 总线实例
+    /// @return: None
+    #[inline]
+    #[allow(dead_code)]
+    pub fn add_bus(&self, id_table: IdTable, bus_dev: Arc<dyn Bus>) {
+        let mut bus_manager = self.0.lock();
+        bus_manager.buses.insert(id_table, bus_dev);
+    }
+
+    /// @brief: 添加总线驱动
+    /// @parameter id_table: 总线驱动标识符,用于唯一标识该总线驱动
+    /// @parameter bus_dev: 总线驱动实例
+    /// @return: None
+    #[inline]
+    #[allow(dead_code)]
+    pub fn add_bus_driver(&self, id_table: IdTable, bus_drv: Arc<dyn BusDriver>) {
+        let mut bus_manager = self.0.lock();
+        bus_manager.bus_drvs.insert(id_table, bus_drv);
+    }
+
+    /// @brief: 卸载总线
+    /// @parameter id_table: 总线标识符,用于唯一标识该总线
+    /// @return: None
+    #[inline]
+    #[allow(dead_code)]
+    pub fn remove_bus(&self, id_table: &IdTable) {
+        let mut bus_manager = self.0.lock();
+        bus_manager.buses.remove(id_table);
+    }
+
+    /// @brief: 卸载总线驱动
+    /// @parameter id_table: 总线驱动标识符,用于唯一标识该总线驱动
+    /// @return: None
+    #[inline]
+    #[allow(dead_code)]
+    pub fn remove_bus_driver(&self, id_table: &IdTable) {
+        let mut bus_manager = self.0.lock();
+        bus_manager.bus_drvs.remove(id_table);
+    }
+
+    /// @brief: 获取总线设备
+    /// @parameter id_table: 总线标识符,用于唯一标识该总线
+    /// @return: 总线设备实例
+    #[inline]
+    #[allow(dead_code)]
+    pub fn get_bus(&self, id_table: &IdTable) -> Option<Arc<dyn Bus>> {
+        let bus_manager = self.0.lock();
+        bus_manager.buses.get(id_table).cloned()
+    }
+
+    /// @brief: 获取总线驱动
+    /// @parameter id_table: 总线驱动标识符,用于唯一标识该总线驱动
+    /// @return: 总线驱动实例
+    #[inline]
+    #[allow(dead_code)]
+    pub fn get_bus_driver(&self, id_table: &IdTable) -> Option<Arc<dyn BusDriver>> {
+        let bus_manager = self.0.lock();
+        return bus_manager.bus_drvs.get(id_table).cloned();
+    }
+}
+
+lazy_static! {
+    pub static ref BUS_MANAGER: Arc<BusManagerLock> = Arc::new(BusManagerLock::new());
+}

+ 19 - 0
kernel/src/driver/base/device/driver.rs

@@ -0,0 +1,19 @@
+use super::IdTable;
+use core::{any::Any, fmt::Debug};
+
+/// @brief: Driver error
+#[allow(dead_code)]
+#[derive(Debug)]
+#[derive(PartialEq, Eq)]
+#[derive(Clone, Copy)]
+pub enum DriverError {
+    ProbeError,
+}
+
+/// @brief: 所有设备驱动都应该实现该trait
+pub trait Driver: Any + Send + Sync + Debug {
+    /// @brief: 获取设备驱动标识符
+    /// @parameter: None
+    /// @return: 该设备驱动唯一标识符
+    fn get_id_table(&self) -> IdTable;
+}

+ 92 - 0
kernel/src/driver/base/device/mod.rs

@@ -0,0 +1,92 @@
+use core::{any::Any, fmt::Debug};
+
+pub mod bus;
+pub mod driver;
+
+/// @brief: 设备类型
+#[allow(dead_code)]
+#[derive(Debug, Eq, PartialEq)]
+pub enum DeviceType {
+    Bus,
+    Net,
+    Gpu,
+    Input,
+    Block,
+    Rtc,
+    Serial,
+    Intc,
+    PlatformDev,
+}
+
+/// @brief: 设备标识符类型
+#[derive(Debug)]
+#[derive(Clone)]
+#[derive(Hash)]
+#[derive(PartialOrd, PartialEq)]
+#[derive(Ord, Eq)]
+pub struct IdTable(&'static str, u32);
+
+/// @brief: 设备标识符操作方法集
+impl IdTable {
+    /// @brief: 创建一个新的设备标识符
+    /// @parameter name: 设备名
+    /// @parameter id: 设备id
+    /// @return: 设备标识符
+    pub fn new(name: &'static str, id: u32) -> IdTable {
+        Self(name, id)
+    }
+}
+
+/// @brief: 设备当前状态
+#[derive(Debug)]
+#[derive(Clone, Copy)]
+pub enum DeviceState {
+    NotInitialized = 0,
+    Initialized = 1,
+    UnDefined = 2,
+}
+
+/// @brief: 设备错误类型
+#[derive(Debug, Copy, Clone)]
+pub enum DeviceError {
+    DriverExists,      // 设备已存在
+    DeviceExists,      // 驱动已存在
+    InitializeFailed,  // 初始化错误
+    NoDeviceForDriver, // 没有合适的设备匹配驱动
+    NoDriverForDevice, // 没有合适的驱动匹配设备
+}
+
+/// @brief: 将u32类型转换为设备状态类型
+impl From<u32> for DeviceState {
+    fn from(state: u32) -> Self {
+        match state {
+            0 => DeviceState::NotInitialized,
+            1 => DeviceState::Initialized,
+            _ => todo!(),
+        }
+    }
+}
+
+/// @brief: 将设备状态转换为u32类型
+impl From<DeviceState> for u32 {
+    fn from(state: DeviceState) -> Self {
+        match state {
+            DeviceState::NotInitialized => 0,
+            DeviceState::Initialized => 1,
+            DeviceState::UnDefined => 2,
+        }
+    }
+}
+
+/// @brief: 所有设备都应该实现该trait
+pub trait Device: Any + Send + Sync + Debug {
+    /// @brief: 获取设备类型
+    /// @parameter: None
+    /// @return: 实现该trait的设备所属类型
+    fn get_type(&self) -> DeviceType;
+    
+    /// @brief: 获取设备标识
+    /// @parameter: None
+    /// @return: 该设备唯一标识
+    fn get_id_table(&self) -> IdTable;
+}

+ 2 - 0
kernel/src/driver/base/mod.rs

@@ -0,0 +1,2 @@
+pub mod platform;
+pub mod device;

+ 347 - 0
kernel/src/driver/base/platform/mod.rs

@@ -0,0 +1,347 @@
+use alloc::{
+    collections::{BTreeSet, BTreeMap}, 
+    vec::Vec, sync::Arc
+};
+use lazy_static::lazy_static;
+use core::fmt::Debug;
+use super::device::{
+    bus::{
+        BusDriver, 
+        BusState, 
+        BUS_MANAGER, 
+        Bus
+    },
+    driver::Driver, 
+    IdTable, 
+    DeviceError, 
+    DeviceState, 
+    DeviceType, Device    
+};
+use crate::libs::{rwlock::RwLock, mutex::Mutex};
+use platform_device::PlatformDevice;
+use platform_driver::PlatformDriver;
+
+pub mod platform_device;
+pub mod platform_driver;
+
+/// @brief: platform总线匹配表
+///         总线上的设备和驱动都存在一份匹配表
+///         根据匹配表条目是否匹配来辨识设备和驱动能否进行匹配
+#[derive(Debug)]
+pub struct CompatibleTable(BTreeSet<&'static str>);
+
+/// @brief: 匹配表操作方法集
+impl CompatibleTable {
+    /// @brief: 创建一个新的匹配表
+    /// @parameter id_vec: 匹配条目数组
+    /// @return: 匹配表
+    #[inline]
+    #[allow(dead_code)]
+    pub fn new(id_vec: Vec<&'static str>) -> CompatibleTable {
+        CompatibleTable(BTreeSet::from_iter(id_vec.iter().cloned()))
+    }
+
+    /// @brief: 判断两个匹配表是否能够匹配
+    /// @parameter other: 其他匹配表
+    /// @return: 如果匹配成功,返回true,否则,返回false
+    #[allow(dead_code)]
+    pub fn matches(&self, other: &CompatibleTable) -> bool {
+        for id in &self.0 {
+            if other.0.contains(id) {
+                return true;
+            }
+        }
+        return false;
+    }
+}
+
+/// @brief: platform总线驱动
+#[derive(Debug)]
+pub struct  PlatformBusDriver {
+    drivers: RwLock<BTreeMap<IdTable, Arc<dyn PlatformDriver>>>, // 总线上所有驱动
+    devices: RwLock<BTreeMap<IdTable, Arc<dyn PlatformDevice>>>, // 总线上所有设备
+}
+
+impl PlatformBusDriver {
+    /// @brief: 创建一个platform总线驱动,该驱动用于匹配plaform总线
+    /// @parameter: None
+    /// @return: platfor总线驱动
+    #[inline]
+    #[allow(dead_code)]
+    pub fn new() -> Self {
+        Self {
+            drivers: RwLock::new(BTreeMap::new()),
+            devices: RwLock::new(BTreeMap::new()),
+        }
+    }
+
+    /// @brief: 获取该驱动的匹配表
+    /// @parameter: None
+    /// @return: 驱动的匹配表
+    #[inline]
+    #[allow(dead_code)]
+    fn get_compatible_table(&self) -> CompatibleTable {
+        CompatibleTable::new(vec!["platform"])
+    }
+
+    /// @brief: 根据设备标识符获取platform总线上的设备
+    /// @parameter id_table: 设备标识符
+    /// @return: 总线上的设备
+    #[inline]
+    #[allow(dead_code)]
+    fn get_device(&self, id_table: &IdTable) -> Option<Arc<dyn PlatformDevice>> {
+        let device_map = self.devices.read();
+        return device_map.get(id_table).cloned();
+    }
+
+    /// @brief: 根据设备驱动标识符获取platform总线上的驱动
+    /// @parameter id_table: 设备驱动标识符
+    /// @return: 总线上的驱动
+    #[inline]
+    #[allow(dead_code)]
+    fn get_driver(&self, id_table: &IdTable) -> Option<Arc<dyn PlatformDriver>> {
+        let driver_map = self.drivers.read();
+        return driver_map.get(id_table).cloned();
+    }
+
+    /// @brief: 注册platform类型驱动
+    /// @parameter driver: platform类型驱动,该驱动需要实现PlatformDriver trait
+    /// @return: 注册成功,返回Ok(()),,注册失败,返回BusError类型
+    #[allow(dead_code)]
+    fn register_platform_driver(&mut self, driver: Arc<dyn PlatformDriver>) -> Result<(), DeviceError> {
+        let id_table = driver.get_id_table();
+
+        let mut drivers = self.drivers.write();
+        // 如果存在同类型的驱动,返回错误
+        if drivers.contains_key(&id_table) {
+            return Err(DeviceError::DriverExists);
+        } else {        
+            drivers.insert(id_table.clone(), driver.clone());
+            return Ok(());
+        }
+    }
+
+    /// @brief: 卸载platform类型驱动
+    /// @parameter driver: platform类型驱动,该驱动需挂载在plaform总线之上
+    /// @return: None
+    #[allow(dead_code)]
+    #[inline]
+    fn unregister_platform_driver(&mut self, driver: Arc<dyn PlatformDriver>) {
+        let id_table = driver.get_id_table();
+        self.drivers.write().remove(&id_table);
+    }
+
+    /// @brief: 注册platform类型设备
+    /// @parameter driver: platform类型设备,该驱动需要实现PlatformDevice trait
+    /// @return: 注册成功,返回Ok(()),,注册失败,返回BusError类型
+    #[allow(dead_code)]
+    fn register_platform_device(&mut self, device: Arc<dyn PlatformDevice>) -> Result<(), DeviceError> {
+        let id_table = device.get_id_table();
+
+        let mut devices = self.devices.write();
+        if devices.contains_key(&id_table) {
+            return Err(DeviceError::DeviceExists);
+        } else {
+            devices.insert(id_table.clone(), device.clone());
+            return Ok(());
+        }
+    }
+
+    /// @brief: 卸载platform类型设备
+    /// @parameter device: platform类型设备,该驱设备需挂载在plaform总线之上
+    /// @return: None
+    #[inline]
+    #[allow(dead_code)]
+    fn unregister_platform_device(&mut self, device: Arc<dyn PlatformDevice>) {
+        let id_table = device.get_id_table();
+        self.devices.write().remove(&id_table);
+    }
+
+    /// @brief: 匹配platform类型驱动
+    /// @parameter driver: platform类型驱动
+    /// @return: 如果匹配成功,返回成功驱动的设备数,否则,返回BusError类型
+    #[allow(dead_code)]
+    fn driver_match_device(&self, driver: Arc<dyn PlatformDriver>) -> Result<i32, DeviceError> {
+        let mut num = 0;
+        let devices = self.devices.read();
+
+        for (_dev_id_table, device) in devices.iter() {
+            if device.get_compatible_table().matches(&driver.get_compatible_table()) {              
+                if !device.is_initialized() {
+                    // 设备未初始化,调用驱动probe函数
+                    match driver.probe(device.clone()) {
+                        Ok(()) => {
+                            num = num + 1;
+                            device.set_state(DeviceState::Initialized)
+                        },
+                        // 可以驱动很多设备,一个设备初始化出错即返回
+                        Err(_) => return Err(DeviceError::InitializeFailed),
+                    }
+                }
+            }
+        }
+        if num == 0 {
+            return Err(DeviceError::NoDeviceForDriver);
+        } else {
+            return Ok(num);
+        }
+    }
+
+    /// @brief: 匹配platform上的设备
+    /// @parameter driver: platform类型设备
+    /// @return: 如果匹配成功,返回Ok(()),否则,返回BusError类型
+    #[allow(dead_code)]
+    fn device_match_driver(&self, device: Arc<dyn PlatformDevice>) -> Result<(), DeviceError> {
+        let drivers = self.drivers.read();
+        for (_drv_id_table, driver) in &*drivers {
+            if driver.get_compatible_table().matches(&device.get_compatible_table()) {
+                match driver.probe(device.clone()) {
+                    Ok(_driver) => {                
+                        // 将设备状态置为已初始化
+                        device.set_state(DeviceState::Initialized);
+                        return Ok(());
+                    }
+                    Err(_) => return Err(DeviceError::InitializeFailed),
+                }
+            }
+        }
+        return Err(DeviceError::NoDriverForDevice);
+    }
+}
+
+/// @brief: 为PlatformBusDriver实现Driver trait
+impl Driver for PlatformBusDriver {
+    fn get_id_table(&self) -> IdTable {
+        IdTable::new("PlatformBusDriver", 0)
+    }
+}
+
+/// @brief: 为PlatformBusDriver实现BusDriver trait
+impl BusDriver for PlatformBusDriver {
+    fn is_empty(&self) -> bool {
+        if self.devices.read().is_empty() && self.drivers.read().is_empty() {
+            return true;
+        } else {
+            return false;
+        }
+    }
+}
+
+/// @brief: platform总线
+#[derive(Debug)]
+#[derive(Clone)]
+pub struct Platform { 
+    state: Arc<Mutex<BusState>>, // 总线状态
+    driver: Option<Arc<PlatformBusDriver>>, // 总线驱动
+}
+
+/// @brief: platform方法集
+impl Platform {
+    /// @brief: 创建一个platform总线实例
+    /// @parameter: None
+    /// @return: platform总线实例
+    pub fn new() -> Self {
+        Self {
+            state: Arc::new(Mutex::new(BusState::NotInitialized)),
+            driver: Option::None,
+        }
+    }
+
+    /// @brief: 获取总线的匹配表
+    /// @parameter: None
+    /// @return: platform总线匹配表
+    #[inline]
+    #[allow(dead_code)]
+    fn get_compatible_table(&self) -> CompatibleTable {
+        CompatibleTable::new(vec!["platform"])
+    }
+
+    /// @brief: 判断总线是否初始化
+    /// @parameter: None
+    /// @return: 已初始化,返回true,否则,返回false
+    #[inline]
+    #[allow(dead_code)]
+    fn is_initialized(&self) -> bool {
+        let state = self.state.lock();
+        match *state {
+            BusState::Initialized => true,
+            _ => false,
+        } 
+    }
+
+    /// @brief: 设置总线状态
+    /// @parameter set_state: 总线状态BusState
+    /// @return: None
+    #[inline]
+    fn set_state(&self, set_state: BusState) {
+        let mut state = self.state.lock();
+        *state = set_state;
+    }
+
+    /// @brief: 获取总线状态
+    /// @parameter: None
+    /// @return: 总线状态
+    #[inline]
+    #[allow(dead_code)]
+    fn get_state(&self) -> BusState {
+        let state = self.state.lock();
+        return *state;
+    }
+
+    /// @brief: 
+    /// @parameter: None
+    /// @return: 总线状态
+    #[inline]
+    #[allow(dead_code)]
+    fn set_driver(&mut self, driver: Option<Arc<PlatformBusDriver>>) {
+        self.driver = driver;
+    }
+}
+
+/// @brief: 为Platform实现Device trait,platform总线也是一种设备,属于总线设备类型
+impl Device for Platform {
+    /// @brief: 获取platform设备类型
+    /// @parameter: None
+    /// @return: Bus类型
+    #[inline]
+    #[allow(dead_code)]
+    fn get_type(&self) -> DeviceType {
+        return DeviceType::Bus;
+    }
+
+    /// @brief: 获取platform设备标识符
+    /// @parameter: None
+    /// @return: platform总线设备标识符
+    #[inline]
+    #[allow(dead_code)]
+    fn get_id_table(&self) -> IdTable {
+        IdTable::new("platform", 0)
+    }
+}
+
+/// @brief: 为Platform实现Bus trait,platform总线是一种总线设备
+impl Bus for Platform {}
+
+lazy_static! {
+    pub static ref BUS_PLATFORM_DRIVER: Arc<PlatformBusDriver> = Arc::new(PlatformBusDriver::new());
+    pub static ref BUS_PLATFORM_DEVICE: Arc<Platform> = Arc::new(Platform::new());
+}
+
+/// @brief: 初始化platform总线
+/// @parameter: None
+/// @return: None
+#[allow(dead_code)]
+pub fn platform_bus_init() {
+    BUS_MANAGER.add_bus_driver(BUS_PLATFORM_DRIVER.get_id_table(), BUS_PLATFORM_DRIVER.clone());
+    BUS_MANAGER.add_bus(BUS_PLATFORM_DEVICE.get_id_table(), BUS_PLATFORM_DEVICE.clone());
+    BUS_PLATFORM_DEVICE.set_state(BusState::Initialized);
+}
+
+#[no_mangle]
+extern "C" fn c_platform_bus_init() {
+    BUS_MANAGER.add_bus_driver(BUS_PLATFORM_DRIVER.get_id_table(), BUS_PLATFORM_DRIVER.clone());
+    BUS_MANAGER.add_bus(BUS_PLATFORM_DEVICE.get_id_table(), BUS_PLATFORM_DEVICE.clone());
+    BUS_PLATFORM_DEVICE.set_state(BusState::Initialized);
+}
+
+

+ 38 - 0
kernel/src/driver/base/platform/platform_device.rs

@@ -0,0 +1,38 @@
+use alloc::sync::Arc;
+use super::{
+    super::device::{
+        Device, 
+        DeviceType,
+        DeviceState
+    },
+    CompatibleTable, platform_driver::PlatformDriver
+};
+
+/// @brief: 实现该trait的设备实例应挂载在platform总线上,
+///         同时应该实现Device trait
+pub trait PlatformDevice: Device {
+    fn get_type(&self) -> DeviceType {
+        DeviceType::PlatformDev
+    }
+
+    /// @brief: 获取设备匹配表
+    /// @parameter: None
+    /// @return: 设备匹配表
+    fn get_compatible_table(&self) -> CompatibleTable;
+
+    /// @brief: 判断设备是否初始化
+    /// @parameter: None
+    /// @return: 如果已经初始化,返回true,否则,返回false
+    fn is_initialized(&self) -> bool;
+
+    /// @brief: 设置设备状态
+    /// @parameter set_state: 设备状态
+    /// @return: None
+    fn set_state(&self, set_state: DeviceState);
+
+    /// @brief: 设置platform设备驱动
+    /// @parameter driver: platform设备驱动
+    /// @return: None
+    fn set_driver(&self, driver: Option<Arc<dyn PlatformDriver>>);
+}
+

+ 23 - 0
kernel/src/driver/base/platform/platform_driver.rs

@@ -0,0 +1,23 @@
+use alloc::sync::Arc;
+use super::{
+    super::device::driver::{
+        Driver,
+        DriverError
+    },
+    platform_device::PlatformDevice,
+    CompatibleTable,
+};
+
+/// @brief: 实现该trait的设备驱动实例应挂载在platform总线上,
+///         同时应该实现Driver trait
+pub trait PlatformDriver: Driver {
+    /// @brief: 设备驱动探测函数,此函数在设备和驱动匹配成功后调用
+    /// @parameter device: 匹配成功的设备实例
+    /// @return: 成功驱动设备,返回Ok(()),否则,返回DriverError
+    fn probe(&self, device: Arc<dyn PlatformDevice>) -> Result<(), DriverError>;
+
+    /// @brief: 获取驱动匹配表
+    /// @parameter: None
+    /// @return: 驱动匹配表
+    fn get_compatible_table(&self) -> CompatibleTable;
+}

+ 1 - 0
kernel/src/driver/mod.rs

@@ -6,3 +6,4 @@ pub mod tty;
 pub mod uart;
 pub mod video;
 pub mod virtio;
+pub mod base;