跳转到内容

驱动接口

OpenOS 的驱动运行在用户空间,通过 IPC 与内核通信。内核提供中断处理和端口 I/O 接口。

┌─────────────────────────────────────────────────────────────┐
│ 用户空间 (Ring 3) │
├─────────────────────────────────────────────────────────────┤
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ 键盘驱动 │ │ 磁盘驱动 │ │ 网卡驱动 │ │ 显示驱动 │ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
│ │ │ │ │ │
│ └──────────────┴──────────────┴──────────────┘ │
│ │ IPC │
├──────────────────────────┼──────────────────────────────────┤
│ 内核空间 (Ring 0) │
├─────────────────────────────────────────────────────────────┤
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ IDT │ │ PIC │ │ 端口 I/O │ │ 中断分发 │ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
├─────────────────────────────────────────────────────────────┤
│ 硬件 │
└─────────────────────────────────────────────────────────────┘
arch/x86_64/interrupts.rs
use x86_64::structures::idt::InterruptDescriptorTable;
static IDT: InterruptDescriptorTable = {
let mut idt = InterruptDescriptorTable::new();
// 异常处理函数
idt.breakpoint.set_handler_fn(breakpoint_handler);
idt.double_fault.set_handler_fn(double_fault_handler);
idt.page_fault.set_handler_fn(page_fault_handler);
idt.general_protection_fault.set_handler_fn(general_protection_fault_handler);
// IRQ 处理函数
idt[InterruptIndex::Timer.as_usize()].set_handler_fn(timer_interrupt_handler);
idt[InterruptIndex::Keyboard.as_usize()].set_handler_fn(keyboard_interrupt_handler);
idt[InterruptIndex::Serial1.as_usize()].set_handler_fn(serial_interrupt_handler);
idt
};
extern "x86-interrupt" fn handler(stack_frame: InterruptStackFrame) {
// 1. 读取硬件数据(端口 I/O 或 MMIO)
let data = unsafe { port.read() };
// 2. 处理数据
process_interrupt_data(data);
// 3. 发送 EOI 到 PIC(必须!)
unsafe {
PICS.lock().notify_end_of_interrupt(InterruptIndex::NewIrq.as_u8());
}
}
约束说明
不得阻塞不得睡眠,不得等待用户输入
必须发送 EOI否则 PIC 将屏蔽 IRQ 线
避免死锁不得获取被中断上下文已持有的自旋锁
快速执行尽量减少中断处理时间
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);
}
端口设备说明
0x20 / 0xA0PIC主/从 PIC 命令端口
0x21 / 0xA1PIC主/从 PIC 数据端口
0x60键盘键盘数据端口
0x64键盘键盘状态/命令端口
0x3F8串口COM1 数据端口
0x3F9串口COM1 中断使能
0x3FA串口COM1 FIFO 控制
0x3FB串口COM1 线路控制
0x3FC串口COM1 调制解调器控制
0x3FD串口COM1 线路状态
0x3FE串口COM1 调制解调器状态
use volatile::Volatile;
/// MMIO 读取
pub fn mmio_read<T: Copy>(addr: *const T) -> T {
unsafe { Volatile::new(addr).read() }
}
/// MMIO 写入
pub fn mmio_write<T: Copy>(addr: *mut T, value: T) {
unsafe { Volatile::new(addr).write(value) }
}
const VGA_BUFFER_ADDR: *mut u16 = 0xB8000 as *mut u16;
/// 写入 VGA 字符
pub fn vga_write_char(x: usize, y: usize, ch: u8, color: u8) {
let offset = y * 80 + x;
let value = (color as u16) << 8 | ch as u16;
unsafe {
mmio_write(VGA_BUFFER_ADDR.add(offset), value);
}
}
use pic8259::ChainedPics;
use spin::Mutex;
/// PIC 端口地址
pub const PIC_1_OFFSET: u8 = 32;
pub const PIC_2_OFFSET: u8 = PIC_1_OFFSET + 8;
/// 全局 PIC 实例
pub static PICS: Mutex<ChainedPics> =
Mutex::new(unsafe { ChainedPics::new(PIC_1_OFFSET, PIC_2_OFFSET) });
/// 初始化 PIC
pub fn init() {
unsafe {
PICS.lock().initialize();
}
}
原始 IRQ 重映射后 INT
IRQ 0 → INT 32 (定时器)
IRQ 1 → INT 33 (键盘)
IRQ 2 → INT 34 (级联)
IRQ 3 → INT 35 (COM2)
IRQ 4 → INT 36 (COM1)
IRQ 5 → INT 37 (LPT2)
IRQ 6 → INT 38 (软盘)
IRQ 7 → INT 39 (LPT1)
IRQ 8 → INT 40 (CMOS)
IRQ 9 → INT 41 (自由)
IRQ 10 → INT 42 (自由)
IRQ 11 → INT 43 (自由)
IRQ 12 → INT 44 (PS/2 鼠标)
IRQ 13 → INT 45 (FPU)
IRQ 14 → INT 46 (主 ATA)
IRQ 15 → INT 47 (从 ATA)
/// 发送中断结束信号
pub fn end_of_interrupt(interrupt_id: u8) {
unsafe {
PICS.lock().notify_end_of_interrupt(interrupt_id);
}
}
/// 注册 IRQ 处理函数
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);
}
/// 驱动初始化
pub fn init() {
// 1. 检测硬件
let hardware = detect_hardware();
// 2. 配置硬件
configure_hardware(&hardware);
// 3. 注册中断处理函数
register_irq_handler(hardware.irq, interrupt_handler);
// 4. 启用中断
enable_irq(hardware.irq);
// 5. 创建 IPC 端口
let port_id = sys_port_create().unwrap();
// 6. 注册服务
register_service("driver.name", port_id);
}
drivers/serial.rs
use uart_16550::SerialPort;
use spin::Mutex;
/// COM1 串口
static SERIAL1: Mutex<SerialPort> = Mutex::new(unsafe { SerialPort::new(0x3F8) });
/// 初始化串口
pub fn init() {
SERIAL1.lock().init();
}
/// 读取字节
pub fn read_byte() -> u8 {
SERIAL1.lock().receive()
}
/// 写入字节
pub fn write_byte(byte: u8) {
SERIAL1.lock().send(byte);
}
/// 写入字符串
pub fn write_string(s: &str) {
for byte in s.bytes() {
write_byte(byte);
}
}
drivers/vga.rs
use volatile::Volatile;
use spin::Mutex;
/// VGA 颜色
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum Color {
Black = 0,
Blue = 1,
Green = 2,
// ... 其他颜色
White = 15,
}
/// VGA 缓冲区
const BUFFER_HEIGHT: usize = 25;
const BUFFER_WIDTH: usize = 80;
const VGA_BUFFER: *mut Volatile<u16> = 0xB8000 as *mut _;
/// VGA 驱动
pub struct VgaDriver {
column: usize,
color_code: u8,
buffer: &'static mut [[Volatile<u16>; BUFFER_WIDTH]; BUFFER_HEIGHT],
}
impl VgaDriver {
pub fn new() -> Self {
VgaDriver {
column: 0,
color_code: Color::White as u8 | (Color::Black as u8) << 4,
buffer: unsafe { &mut *(VGA_BUFFER as *mut _) },
}
}
pub fn write_byte(&mut self, byte: u8) {
match byte {
b'\n' => self.new_line(),
byte => {
if self.column >= BUFFER_WIDTH {
self.new_line();
}
let row = BUFFER_HEIGHT - 1;
let col = self.column;
let color_code = self.color_code;
let char = (color_code as u16) << 8 | byte as u16;
self.buffer[row][col].write(char);
self.column += 1;
}
}
}
fn new_line(&mut self) {
// 滚动屏幕
for row in 1..BUFFER_HEIGHT {
for col in 0..BUFFER_WIDTH {
let char = self.buffer[row][col].read();
self.buffer[row - 1][col].write(char);
}
}
self.clear_row(BUFFER_HEIGHT - 1);
self.column = 0;
}
}
Terminal window
mkdir kernel/src/drivers/my_driver
touch kernel/src/drivers/my_driver/mod.rs
kernel/src/drivers/my_driver/mod.rs
use x86_64::instructions::port::Port;
/// 驱动状态
pub struct MyDriver {
port: Port<u8>,
initialized: bool,
}
impl MyDriver {
pub fn new(port_base: u16) -> Self {
MyDriver {
port: Port::new(port_base),
initialized: false,
}
}
pub fn init(&mut self) {
// 初始化硬件
unsafe {
self.port.write(0x01); // 发送初始化命令
}
self.initialized = true;
}
pub fn read_data(&mut self) -> u8 {
if !self.initialized {
return 0;
}
unsafe { self.port.read() }
}
pub fn write_data(&mut self, data: u8) {
if !self.initialized {
return;
}
unsafe {
self.port.write(data);
}
}
}
kernel/src/drivers/mod.rs
pub mod my_driver;
/// 初始化所有驱动
pub fn init_all() {
my_driver::MY_DRIVER.lock().init();
}
kernel/src/arch/x86_64/interrupts.rs
extern "x86-interrupt" fn my_driver_handler(_stack_frame: InterruptStackFrame) {
// 处理中断
let data = drivers::my_driver::MY_DRIVER.lock().read_data();
process_data(data);
// 发送 EOI
unsafe {
PICS.lock().notify_end_of_interrupt(InterruptIndex::MyDriver.as_u8());
}
}
// 使用串口输出调试信息
serial_println!("[DRIVER] Initializing...");
serial_println!("[DRIVER] Port: 0x{:X}", port_base);
serial_println!("[DRIVER] IRQ: {}", irq);

问题:中断不触发

  • 检查 PIC 初始化
  • 检查 IRQ 使能
  • 检查 IDT 注册

问题:数据丢失

  • 检查 FIFO 缓冲区
  • 增加中断处理速度
  • 使用 DMA

问题:死锁

  • 避免在中断处理中获取锁
  • 使用 without_interrupts() 保护共享数据