添加驱动
本指南介绍如何为 OpenOS 添加新的设备驱动。
驱动开发步骤
Section titled “驱动开发步骤”1. 创建驱动文件
Section titled “1. 创建驱动文件”mkdir kernel/src/drivers/my_drivertouch kernel/src/drivers/my_driver/mod.rs2. 定义驱动结构
Section titled “2. 定义驱动结构”use x86_64::instructions::port::Port;use spin::Mutex;
/// I/O 端口常量const DATA_PORT: u16 = 0x100;const STATUS_PORT: u16 = 0x101;const COMMAND_PORT: u16 = 0x102;
/// 驱动状态pub struct MyDriver { data_port: Port<u8>, status_port: Port<u8>, command_port: Port<u8>, initialized: bool,}
/// 全局驱动实例pub static MY_DRIVER: Mutex<MyDriver> = Mutex::new(MyDriver::new());
impl MyDriver { pub const fn new() -> Self { MyDriver { data_port: Port::new(DATA_PORT), status_port: Port::new(STATUS_PORT), command_port: Port::new(COMMAND_PORT), initialized: false, } }
pub fn init(&mut self) { unsafe { self.command_port.write(0xFF); while self.status_port.read() & 0x01 == 0 { core::hint::spin_loop(); } self.command_port.write(0x01); } self.initialized = true; }
pub fn read_data(&mut self) -> Option<u8> { if !self.initialized { return None; } unsafe { if self.status_port.read() & 0x01 != 0 { Some(self.data_port.read()) } else { None } } }
pub fn write_data(&mut self, data: u8) -> Result<(), Error> { if !self.initialized { return Err(Error::NotInitialized); } unsafe { while self.status_port.read() & 0x02 == 0 { core::hint::spin_loop(); } self.data_port.write(data); } Ok(()) }}3. 注册驱动模块
Section titled “3. 注册驱动模块”pub mod my_driver;
/// 初始化所有驱动pub fn init_all() { my_driver::MY_DRIVER.lock().init();}4. 添加中断处理
Section titled “4. 添加中断处理”extern "x86-interrupt" fn my_driver_handler(_stack_frame: InterruptStackFrame) { drivers::my_driver::MY_DRIVER.lock().handle_interrupt();
unsafe { PICS.lock().notify_end_of_interrupt(InterruptIndex::MyDriver.as_u8()); }}
// 在 IDT 初始化中注册pub fn init() { let mut idt = IDT.lock(); idt[InterruptIndex::MyDriver.as_usize()].set_handler_fn(my_driver_handler);}5. 在启动序列中调用
Section titled “5. 在启动序列中调用”#[no_mangle]pub extern "C" fn _start() -> ! { // ... 其他初始化 ...
// 初始化驱动 drivers::init_all();
// ... 其他初始化 ...}字符设备驱动
Section titled “字符设备驱动”处理字符流的设备(串口、键盘):
pub trait CharDevice { fn read_byte(&mut self) -> Option<u8>; fn write_byte(&mut self, byte: u8) -> Result<(), Error>; fn has_data(&self) -> bool;}处理数据块的设备(磁盘、SSD):
pub trait BlockDevice { fn read_block(&mut self, block: u64, buf: &mut [u8]) -> Result<(), Error>; fn write_block(&mut self, block: u64, buf: &[u8]) -> Result<(), Error>; fn block_size(&self) -> usize;}注册中断处理函数
Section titled “注册中断处理函数”pub fn register_irq_handler( irq: u8, handler: extern "x86-interrupt" fn(InterruptStackFrame),) { let mut idt = IDT.lock(); idt[(PIC_1_OFFSET + irq) as usize].set_handler_fn(handler);}中断处理最佳实践
Section titled “中断处理最佳实践”- 快速处理 - 中断处理函数应该尽快完成
- 避免阻塞 - 不要等待 I/O 或获取可能被持有的锁
- 发送 EOI - 必须发送中断结束信号
- 使用下半部 - 将复杂处理推迟到线程
端口 I/O
Section titled “端口 I/O”use x86_64::instructions::port::Port;
pub unsafe fn port_read(port: u16) -> u8 { let mut port = Port::new(port); port.read()}
pub unsafe fn port_write(port: u16, value: u8) { let mut port = Port::new(port); port.write(value);}串口调试输出
Section titled “串口调试输出”serial_println!("[DRIVER] Initializing...");serial_println!("[DRIVER] Port: 0x{:X}", port_base);serial_println!("[DRIVER] IRQ: {}", irq);问题:中断不触发
- 检查 PIC 初始化
- 检查 IRQ 使能
- 检查 IDT 注册
问题:数据丢失
- 检查 FIFO 缓冲区
- 增加中断处理速度
- 使用 DMA
问题:死锁
- 避免在中断处理中获取锁
- 使用
without_interrupts()保护共享数据