Skip to content

Commit 2e91fa7

Browse files
committed
feat(interrupts): 添加APIC中断注册表管理IRQ处理器
1 parent fafce4a commit 2e91fa7

File tree

5 files changed

+189
-42
lines changed

5 files changed

+189
-42
lines changed

kernel/src/interrupts/apic/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use spin::Mutex;
99
use x86_64::registers::model_specific::Msr;
1010

1111
pub mod ioapic;
12+
pub mod registry;
1213

1314
const APIC_SIVR_ENABLE: u32 = 0x100;
1415
const APIC_BASE_ENABLE: u64 = 1 << 11;
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
use crate::libs::time::time_since_boot;
2+
use spin::Mutex;
3+
use x86_64::structures::idt::InterruptStackFrame;
4+
5+
pub static IRQ_REGISTRY: Mutex<IrqRegistry> = Mutex::new(IrqRegistry::new());
6+
7+
pub type IrqHandler = for<'a> fn(IrqContext<'a>) -> IrqResult;
8+
9+
pub struct IrqRegistry {
10+
handlers: [Option<IrqHandler>; 256],
11+
names: [Option<&'static str>; 256],
12+
stats: [IrqStats; 256],
13+
}
14+
15+
pub struct IrqContext<'a> {
16+
pub vector: u8,
17+
pub irq_number: Option<u8>, // None for exceptions
18+
pub stack_frame: &'a InterruptStackFrame,
19+
pub error_code: Option<u64>,
20+
}
21+
22+
pub enum IrqResult {
23+
/// Continue execution
24+
Continue,
25+
/// Interrupt is handled
26+
Handled,
27+
}
28+
29+
#[derive(Default, Clone, Copy, Debug)]
30+
pub struct IrqStats {
31+
/// Number of interrupts
32+
pub count: u64,
33+
/// Time spent in last interrupt handler
34+
pub last_time: u64,
35+
/// Time of last interrupt
36+
pub interrupt_time: u64,
37+
}
38+
39+
impl IrqStats {
40+
pub const fn new() -> Self {
41+
Self {
42+
count: 0,
43+
last_time: 0,
44+
interrupt_time: 0,
45+
}
46+
}
47+
}
48+
49+
impl IrqRegistry {
50+
pub const fn new() -> Self {
51+
Self {
52+
handlers: [None; 256],
53+
names: [None; 256],
54+
stats: [IrqStats::new(); 256],
55+
}
56+
}
57+
58+
pub fn register(
59+
&mut self,
60+
vector: u8,
61+
name: &'static str,
62+
handler: IrqHandler,
63+
) -> Result<(), &'static str> {
64+
if self.handlers[vector as usize].is_some() {
65+
return Err("Handler already registered");
66+
}
67+
self.handlers[vector as usize] = Some(handler);
68+
self.names[vector as usize] = Some(name);
69+
self.stats[vector as usize] = IrqStats::new();
70+
Ok(())
71+
}
72+
73+
pub fn unregister(&mut self, vector: u8) -> Result<(), &'static str> {
74+
if self.handlers[vector as usize].is_none() {
75+
return Err("Handler not registered");
76+
}
77+
self.handlers[vector as usize] = None;
78+
self.names[vector as usize] = None;
79+
self.stats[vector as usize] = IrqStats::new();
80+
Ok(())
81+
}
82+
83+
pub fn handle(&mut self, context: IrqContext) -> IrqResult {
84+
let vector = context.vector as usize;
85+
self.stats[vector].count += 1;
86+
let st = time_since_boot();
87+
self.stats[vector].interrupt_time = st as u64;
88+
match self.handlers[vector] {
89+
Some(handler) => {
90+
let result = handler(context);
91+
self.stats[vector].last_time = (time_since_boot() - st) as u64;
92+
result
93+
}
94+
None => IrqResult::Continue,
95+
}
96+
}
97+
98+
pub fn get_stats(&self, vector: u8) -> IrqStats {
99+
self.stats[vector as usize]
100+
}
101+
}

kernel/src/interrupts/handler.rs

Lines changed: 56 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#[allow(unused)]
22
use crate::interrupts::apic;
3+
use crate::interrupts::apic::registry::{IrqContext, IRQ_REGISTRY};
4+
use crate::interrupts::idt::IRQ_BASE;
35
use crate::panic::{ExceptionInfo, EXCEPTION_INFO};
46
use crate::serial_println;
57
use x86_64::{
@@ -150,42 +152,70 @@ pub extern "x86-interrupt" fn machine_check_handler(stack_frame: InterruptStackF
150152
panic!("CRITICAL: MACHINE CHECK");
151153
}
152154

153-
pub extern "x86-interrupt" fn timer_interrupt_handler(_stack_frame: InterruptStackFrame) {
154-
// APIC Timer interrupt
155-
// For now just EOI
155+
pub extern "x86-interrupt" fn timer_interrupt_handler(stack_frame: InterruptStackFrame) {
156+
let context = IrqContext {
157+
vector: crate::interrupts::apic::TIMER_VECTOR,
158+
irq_number: None, // APIC timer is not a standard ISA IRQ
159+
stack_frame: &stack_frame,
160+
error_code: None,
161+
};
162+
163+
if let Some(mut registry) = IRQ_REGISTRY.try_lock() {
164+
registry.handle(context);
165+
}
166+
156167
apic::end_of_interrupt();
157168
}
158169

159-
macro_rules! pic_interrupt_handler {
170+
macro_rules! ioapic_interrupt_handler {
160171
($name:ident, $irq_number:expr) => {
161172
#[allow(unused_variables)]
162173
pub extern "x86-interrupt" fn $name(stack_frame: InterruptStackFrame) {
163-
if $irq_number == 1 {
164-
let mut port = x86_64::instructions::port::Port::<u8>::new(0x60);
165-
let scancode = unsafe { port.read() };
166-
crate::drivers::input::keyboard::KEYBOARD.handle_scancode(scancode);
167-
} else {
168-
serial_println!("IRQ {} received!", $irq_number);
174+
let vector = IRQ_BASE + $irq_number;
175+
let context = IrqContext {
176+
vector,
177+
irq_number: Some($irq_number),
178+
stack_frame: &stack_frame,
179+
error_code: None,
180+
};
181+
182+
let mut handled = false;
183+
if let Some(mut registry) = IRQ_REGISTRY.try_lock() {
184+
if let crate::interrupts::apic::registry::IrqResult::Handled =
185+
registry.handle(context)
186+
{
187+
handled = true;
188+
}
189+
}
190+
191+
if !handled {
192+
if $irq_number == 1 {
193+
let mut port = x86_64::instructions::port::Port::<u8>::new(0x60);
194+
let scancode = unsafe { port.read() };
195+
crate::drivers::input::keyboard::KEYBOARD.handle_scancode(scancode);
196+
} else {
197+
serial_println!("IRQ {} received!", $irq_number);
198+
}
169199
}
170200

171201
apic::end_of_interrupt();
172202
}
173203
};
174204
}
175205
// 为所有 16 个 IRQ 定义处理函数
176-
pic_interrupt_handler!(pic_interrupt_handler_0, 0); // Timer Interrupt
177-
pic_interrupt_handler!(pic_interrupt_handler_1, 1); // Keyboard Interrupt
178-
pic_interrupt_handler!(pic_interrupt_handler_2, 2); // Cascade to PIC2
179-
pic_interrupt_handler!(pic_interrupt_handler_3, 3); // Serial COM2
180-
pic_interrupt_handler!(pic_interrupt_handler_4, 4); // Serial COM1
181-
pic_interrupt_handler!(pic_interrupt_handler_5, 5); // Parallel Port LPT2 / Sound Card
182-
pic_interrupt_handler!(pic_interrupt_handler_6, 6); // Floppy Disk Controller
183-
pic_interrupt_handler!(pic_interrupt_handler_7, 7); // Parallel Port LPT1 / Fake Interrupt
184-
pic_interrupt_handler!(pic_interrupt_handler_8, 8); // RTC Real Time Clock
185-
pic_interrupt_handler!(pic_interrupt_handler_9, 9); // Redirect IRQ2
186-
pic_interrupt_handler!(pic_interrupt_handler_10, 10); // Freed / SCSI / Netcard
187-
pic_interrupt_handler!(pic_interrupt_handler_11, 11); // Freed / SCSI / Netcard
188-
pic_interrupt_handler!(pic_interrupt_handler_12, 12); // PS/2 mouse
189-
pic_interrupt_handler!(pic_interrupt_handler_13, 13); // FPU / MPU
190-
pic_interrupt_handler!(pic_interrupt_handler_14, 14); // Primary IDE
191-
pic_interrupt_handler!(pic_interrupt_handler_15, 15); // Secondary IDE
206+
ioapic_interrupt_handler!(ioapic_interrupt_handler_0, 0); // Timer Interrupt
207+
ioapic_interrupt_handler!(ioapic_interrupt_handler_1, 1); // Keyboard Interrupt
208+
ioapic_interrupt_handler!(ioapic_interrupt_handler_2, 2); // Cascade to PIC2
209+
ioapic_interrupt_handler!(ioapic_interrupt_handler_3, 3); // Serial COM2
210+
ioapic_interrupt_handler!(ioapic_interrupt_handler_4, 4); // Serial COM1
211+
ioapic_interrupt_handler!(ioapic_interrupt_handler_5, 5); // Parallel Port LPT2 / Sound Card
212+
ioapic_interrupt_handler!(ioapic_interrupt_handler_6, 6); // Floppy Disk Controller
213+
ioapic_interrupt_handler!(ioapic_interrupt_handler_7, 7); // Parallel Port LPT1 / Fake Interrupt
214+
ioapic_interrupt_handler!(ioapic_interrupt_handler_8, 8); // RTC Real Time Clock
215+
ioapic_interrupt_handler!(ioapic_interrupt_handler_9, 9); // Redirect IRQ2
216+
ioapic_interrupt_handler!(ioapic_interrupt_handler_10, 10); // Freed / SCSI / Netcard
217+
ioapic_interrupt_handler!(ioapic_interrupt_handler_11, 11); // Freed / SCSI / Netcard
218+
ioapic_interrupt_handler!(ioapic_interrupt_handler_12, 12); // PS/2 mouse
219+
ioapic_interrupt_handler!(ioapic_interrupt_handler_13, 13); // FPU / MPU
220+
ioapic_interrupt_handler!(ioapic_interrupt_handler_14, 14); // Primary IDE
221+
ioapic_interrupt_handler!(ioapic_interrupt_handler_15, 15); // Secondary IDE

kernel/src/interrupts/idt.rs

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -44,22 +44,22 @@ lazy_static! {
4444
}
4545
// IOAPIC interrupt handlers
4646
// IRQ0 - Clock Interrupt, IRQ1 - Keyboard Interrupt
47-
idt[IRQ_BASE].set_handler_fn(handler::pic_interrupt_handler_0); // IRQ0
48-
idt[IRQ_BASE + 1].set_handler_fn(handler::pic_interrupt_handler_1); // IRQ1
49-
idt[IRQ_BASE + 2].set_handler_fn(handler::pic_interrupt_handler_2); // IRQ2
50-
idt[IRQ_BASE + 3].set_handler_fn(handler::pic_interrupt_handler_3); // IRQ3
51-
idt[IRQ_BASE + 4].set_handler_fn(handler::pic_interrupt_handler_4); // IRQ4
52-
idt[IRQ_BASE + 5].set_handler_fn(handler::pic_interrupt_handler_5); // IRQ5
53-
idt[IRQ_BASE + 6].set_handler_fn(handler::pic_interrupt_handler_6); // IRQ6
54-
idt[IRQ_BASE + 7].set_handler_fn(handler::pic_interrupt_handler_7); // IRQ7
55-
idt[IRQ_BASE + 8].set_handler_fn(handler::pic_interrupt_handler_8); // IRQ8
56-
idt[IRQ_BASE + 9].set_handler_fn(handler::pic_interrupt_handler_9); // IRQ9
57-
idt[IRQ_BASE + 10].set_handler_fn(handler::pic_interrupt_handler_10); // IRQ10
58-
idt[IRQ_BASE + 11].set_handler_fn(handler::pic_interrupt_handler_11); // IRQ11
59-
idt[IRQ_BASE + 12].set_handler_fn(handler::pic_interrupt_handler_12); // IRQ12
60-
idt[IRQ_BASE + 13].set_handler_fn(handler::pic_interrupt_handler_13); // IRQ13
61-
idt[IRQ_BASE + 14].set_handler_fn(handler::pic_interrupt_handler_14); // IRQ14
62-
idt[IRQ_BASE + 15].set_handler_fn(handler::pic_interrupt_handler_15); // IRQ15
47+
idt[IRQ_BASE].set_handler_fn(handler::ioapic_interrupt_handler_0); // IRQ0
48+
idt[IRQ_BASE + 1].set_handler_fn(handler::ioapic_interrupt_handler_1); // IRQ1
49+
idt[IRQ_BASE + 2].set_handler_fn(handler::ioapic_interrupt_handler_2); // IRQ2
50+
idt[IRQ_BASE + 3].set_handler_fn(handler::ioapic_interrupt_handler_3); // IRQ3
51+
idt[IRQ_BASE + 4].set_handler_fn(handler::ioapic_interrupt_handler_4); // IRQ4
52+
idt[IRQ_BASE + 5].set_handler_fn(handler::ioapic_interrupt_handler_5); // IRQ5
53+
idt[IRQ_BASE + 6].set_handler_fn(handler::ioapic_interrupt_handler_6); // IRQ6
54+
idt[IRQ_BASE + 7].set_handler_fn(handler::ioapic_interrupt_handler_7); // IRQ7
55+
idt[IRQ_BASE + 8].set_handler_fn(handler::ioapic_interrupt_handler_8); // IRQ8
56+
idt[IRQ_BASE + 9].set_handler_fn(handler::ioapic_interrupt_handler_9); // IRQ9
57+
idt[IRQ_BASE + 10].set_handler_fn(handler::ioapic_interrupt_handler_10); // IRQ10
58+
idt[IRQ_BASE + 11].set_handler_fn(handler::ioapic_interrupt_handler_11); // IRQ11
59+
idt[IRQ_BASE + 12].set_handler_fn(handler::ioapic_interrupt_handler_12); // IRQ12
60+
idt[IRQ_BASE + 13].set_handler_fn(handler::ioapic_interrupt_handler_13); // IRQ13
61+
idt[IRQ_BASE + 14].set_handler_fn(handler::ioapic_interrupt_handler_14); // IRQ14
62+
idt[IRQ_BASE + 15].set_handler_fn(handler::ioapic_interrupt_handler_15); // IRQ15
6363
idt
6464
};
6565
}

kernel/src/main.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,21 @@ pub extern "C" fn kernel_main() -> ! {
4949
0,
5050
);
5151

52+
// Register Keyboard Handler via Registry
53+
proka_kernel::interrupts::apic::registry::IRQ_REGISTRY
54+
.lock()
55+
.register(
56+
proka_kernel::interrupts::idt::IRQ_BASE + 1,
57+
"Keyboard",
58+
|_context| {
59+
let mut port = x86_64::instructions::port::Port::<u8>::new(0x60);
60+
let scancode = unsafe { port.read() };
61+
proka_kernel::drivers::input::keyboard::KEYBOARD.handle_scancode(scancode);
62+
proka_kernel::interrupts::apic::registry::IrqResult::Handled
63+
},
64+
)
65+
.expect("Failed to register keyboard handler");
66+
5267
proka_kernel::drivers::init_devices(); // Initialize devices
5368
proka_kernel::libs::time::init(); // Init time system
5469

0 commit comments

Comments
 (0)