16
16
// message.
17
17
// 4. Timer: the timer handler increments the counter in
18
18
// the time module and acknowledges the interrupt.
19
+ //
20
+ // The functionality for the PIC is quite different from
21
+ // the functionality for CPU exceptions. Exceptions are
22
+ // handled directly through the IDT. The PIC's IRQs are
23
+ // instead registered using the register_irq function,
24
+ // making it easier to handle IRQs, without needing to
25
+ // know the details of the PIC.
26
+ //
27
+ // The other big difference with the IRQ handling is that
28
+ // IRQ handlers don't need to acknowledge the PIC, and
29
+ // are passed the IRQ number.
19
30
20
31
use crate :: { gdt, halt_loop, println, time} ;
21
32
use lazy_static:: lazy_static;
@@ -29,6 +40,7 @@ use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame, Pag
29
40
pub fn init ( ) {
30
41
IDT . load ( ) ;
31
42
unsafe { PICS . lock ( ) . initialize ( ) } ;
43
+ register_irq ( 0 , timer_interrupt_handler) ;
32
44
}
33
45
34
46
lazy_static ! {
@@ -41,7 +53,23 @@ lazy_static! {
41
53
. set_handler_fn( double_fault_handler)
42
54
. set_stack_index( gdt:: DOUBLE_FAULT_IST_INDEX ) ;
43
55
}
44
- idt[ InterruptIndex :: Timer . as_usize( ) ] . set_handler_fn( timer_interrupt_handler) ;
56
+
57
+ idt[ PIC_1_OFFSET + 0 ] . set_handler_fn( irq_handler_0) ;
58
+ idt[ PIC_1_OFFSET + 1 ] . set_handler_fn( irq_handler_1) ;
59
+ idt[ PIC_1_OFFSET + 2 ] . set_handler_fn( irq_handler_2) ;
60
+ idt[ PIC_1_OFFSET + 3 ] . set_handler_fn( irq_handler_3) ;
61
+ idt[ PIC_1_OFFSET + 4 ] . set_handler_fn( irq_handler_4) ;
62
+ idt[ PIC_1_OFFSET + 5 ] . set_handler_fn( irq_handler_5) ;
63
+ idt[ PIC_1_OFFSET + 6 ] . set_handler_fn( irq_handler_6) ;
64
+ idt[ PIC_1_OFFSET + 7 ] . set_handler_fn( irq_handler_7) ;
65
+ idt[ PIC_1_OFFSET + 8 ] . set_handler_fn( irq_handler_8) ;
66
+ idt[ PIC_1_OFFSET + 9 ] . set_handler_fn( irq_handler_9) ;
67
+ idt[ PIC_1_OFFSET + 10 ] . set_handler_fn( irq_handler_10) ;
68
+ idt[ PIC_1_OFFSET + 11 ] . set_handler_fn( irq_handler_11) ;
69
+ idt[ PIC_1_OFFSET + 12 ] . set_handler_fn( irq_handler_12) ;
70
+ idt[ PIC_1_OFFSET + 13 ] . set_handler_fn( irq_handler_13) ;
71
+ idt[ PIC_1_OFFSET + 14 ] . set_handler_fn( irq_handler_14) ;
72
+ idt[ PIC_1_OFFSET + 15 ] . set_handler_fn( irq_handler_15) ;
45
73
46
74
idt
47
75
} ;
@@ -71,41 +99,135 @@ extern "x86-interrupt" fn double_fault_handler(
71
99
panic ! ( "EXCEPTION: DOUBLE FAULT\n {:#?}" , stack_frame) ;
72
100
}
73
101
74
- extern "x86-interrupt" fn timer_interrupt_handler ( _stack_frame : InterruptStackFrame ) {
102
+ fn timer_interrupt_handler ( _stack_frame : InterruptStackFrame , _irq : u8 ) {
75
103
time:: tick ( ) ;
104
+ }
105
+
106
+ // PIC code.
107
+
108
+ const PIC_1_OFFSET : usize = 32 ;
109
+ const PIC_2_OFFSET : usize = PIC_1_OFFSET + 8 ;
110
+
111
+ /// PICS is the set of programmable interrupt controllers.
112
+ ///
113
+ /// PICS can be used to acknowledge an interrupt.
114
+ ///
115
+ static PICS : spin:: Mutex < ChainedPics > =
116
+ spin:: Mutex :: new ( unsafe { ChainedPics :: new ( PIC_1_OFFSET as u8 , PIC_2_OFFSET as u8 ) } ) ;
117
+
118
+ /// IrqHandler represents an IRQ handler function.
119
+ ///
120
+ /// The irq argument is an integer between 0 and 15.
121
+ ///
122
+ pub type IrqHandler = fn ( frame : InterruptStackFrame , irq : u8 ) ;
123
+
124
+ /// irq_handler_none is a dummy IRQ handler, which
125
+ /// does nothing.
126
+ ///
127
+ fn irq_handler_none ( _frame : InterruptStackFrame , _irq : u8 ) { }
128
+
129
+ // IRQ handlers.
130
+
131
+ #[ inline]
132
+ fn irq_handler_generic ( frame : InterruptStackFrame , irq : u8 ) {
133
+ let irqs = IRQS . try_lock ( ) ;
134
+ if let Some ( irqs) = irqs {
135
+ let handler = irqs[ irq as usize ] ;
136
+ handler ( frame, irq) ;
137
+ }
76
138
77
139
unsafe {
78
140
PICS . lock ( )
79
- . notify_end_of_interrupt ( InterruptIndex :: Timer . as_u8 ( ) ) ;
141
+ . notify_end_of_interrupt ( irq + PIC_1_OFFSET as u8 ) ;
80
142
}
81
143
}
82
144
83
- // PIC code.
145
+ extern "x86-interrupt" fn irq_handler_0 ( frame : InterruptStackFrame ) {
146
+ irq_handler_generic ( frame, 0u8 ) ;
147
+ }
84
148
85
- #[ doc( hidden) ]
86
- pub const PIC_1_OFFSET : u8 = 32 ;
87
- #[ doc( hidden) ]
88
- pub const PIC_2_OFFSET : u8 = PIC_1_OFFSET + 8 ;
149
+ extern "x86-interrupt" fn irq_handler_1 ( frame : InterruptStackFrame ) {
150
+ irq_handler_generic ( frame, 1u8 ) ;
151
+ }
89
152
90
- static PICS : spin:: Mutex < ChainedPics > =
91
- spin:: Mutex :: new ( unsafe { ChainedPics :: new ( PIC_1_OFFSET , PIC_2_OFFSET ) } ) ;
153
+ extern "x86-interrupt" fn irq_handler_2 ( frame : InterruptStackFrame ) {
154
+ irq_handler_generic ( frame, 2u8 ) ;
155
+ }
156
+
157
+ extern "x86-interrupt" fn irq_handler_3 ( frame : InterruptStackFrame ) {
158
+ irq_handler_generic ( frame, 3u8 ) ;
159
+ }
160
+
161
+ extern "x86-interrupt" fn irq_handler_4 ( frame : InterruptStackFrame ) {
162
+ irq_handler_generic ( frame, 4u8 ) ;
163
+ }
164
+
165
+ extern "x86-interrupt" fn irq_handler_5 ( frame : InterruptStackFrame ) {
166
+ irq_handler_generic ( frame, 5u8 ) ;
167
+ }
168
+
169
+ extern "x86-interrupt" fn irq_handler_6 ( frame : InterruptStackFrame ) {
170
+ irq_handler_generic ( frame, 6u8 ) ;
171
+ }
172
+
173
+ extern "x86-interrupt" fn irq_handler_7 ( frame : InterruptStackFrame ) {
174
+ irq_handler_generic ( frame, 7u8 ) ;
175
+ }
92
176
93
- #[ derive( Debug , Clone , Copy ) ]
94
- #[ repr( u8 ) ]
95
- #[ doc( hidden) ]
96
- pub enum InterruptIndex {
97
- Timer = PIC_1_OFFSET ,
98
- Keyboard ,
177
+ extern "x86-interrupt" fn irq_handler_8 ( frame : InterruptStackFrame ) {
178
+ irq_handler_generic ( frame, 8u8 ) ;
99
179
}
100
180
101
- impl InterruptIndex {
102
- fn as_u8 ( self ) -> u8 {
103
- self as u8
181
+ extern "x86-interrupt" fn irq_handler_9 ( frame : InterruptStackFrame ) {
182
+ irq_handler_generic ( frame, 9u8 ) ;
183
+ }
184
+
185
+ extern "x86-interrupt" fn irq_handler_10 ( frame : InterruptStackFrame ) {
186
+ irq_handler_generic ( frame, 10u8 ) ;
187
+ }
188
+
189
+ extern "x86-interrupt" fn irq_handler_11 ( frame : InterruptStackFrame ) {
190
+ irq_handler_generic ( frame, 11u8 ) ;
191
+ }
192
+
193
+ extern "x86-interrupt" fn irq_handler_12 ( frame : InterruptStackFrame ) {
194
+ irq_handler_generic ( frame, 12u8 ) ;
195
+ }
196
+
197
+ extern "x86-interrupt" fn irq_handler_13 ( frame : InterruptStackFrame ) {
198
+ irq_handler_generic ( frame, 13u8 ) ;
199
+ }
200
+
201
+ extern "x86-interrupt" fn irq_handler_14 ( frame : InterruptStackFrame ) {
202
+ irq_handler_generic ( frame, 14u8 ) ;
203
+ }
204
+
205
+ extern "x86-interrupt" fn irq_handler_15 ( frame : InterruptStackFrame ) {
206
+ irq_handler_generic ( frame, 15u8 ) ;
207
+ }
208
+
209
+ /// IRQS helps us to track which IRQs have been allocated.
210
+ ///
211
+ static IRQS : spin:: Mutex < [ IrqHandler ; 16 ] > = spin:: Mutex :: new ( [ irq_handler_none; 16 ] ) ;
212
+
213
+ /// register_irq sets the handler for the given IRQ.
214
+ ///
215
+ /// The irq parameter must be an integer between 0 and 15.
216
+ ///
217
+ /// If the given IRQ has already been assigned, register_irq
218
+ /// panics.
219
+ ///
220
+ pub fn register_irq ( irq : u8 , handler : IrqHandler ) {
221
+ let mut irqs = IRQS . lock ( ) ;
222
+ if irq > 15 {
223
+ panic ! ( "invalid IRQ {} passed to register_irq" , irq) ;
104
224
}
105
225
106
- fn as_usize ( self ) -> usize {
107
- usize :: from ( self . as_u8 ( ) )
226
+ if irqs [ irq as usize ] != irq_handler_none {
227
+ panic ! ( "IRQ {} has already been registered" , irq ) ;
108
228
}
229
+
230
+ irqs[ irq as usize ] = handler;
109
231
}
110
232
111
233
// Tests
0 commit comments