3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: hal/halx86/generic/pic.c
5 * PURPOSE: HAL PIC Management and Control Code
6 * PROGRAMMERS: ReactOS Portable Systems Group
9 /* INCLUDES *******************************************************************/
15 /* GLOBALS ********************************************************************/
19 * This table basically keeps track of level vs edge triggered interrupts.
20 * Windows has 250+ entries, but it seems stupid to replicate that since the PIC
21 * can't actually have that many.
23 * When a level interrupt is registered, the respective pointer in this table is
24 * modified to point to a dimiss routine for level interrupts instead.
26 * The other thing this table does is special case IRQ7, IRQ13 and IRQ15:
28 * - If an IRQ line is deasserted before it is acknowledged due to a noise spike
29 * generated by an expansion device (since the IRQ line is low during the 1st
30 * acknowledge bus cycle), the i8259 will keep the line low for at least 100ns
31 * When the spike passes, a pull-up resistor will return the IRQ line to high.
32 * Since the PIC requires the input be high until the first acknowledge, the
33 * i8259 knows that this was a spurious interrupt, and on the second interrupt
34 * acknowledge cycle, it reports this to the CPU. Since no valid interrupt has
35 * actually happened Intel hardcoded the chip to report IRQ7 on the master PIC
36 * and IRQ15 on the slave PIC (IR7 either way).
38 * "ISA System Architecture", 3rd Edition, states that these cases should be
39 * handled by reading the respective Interrupt Service Request (ISR) bits from
40 * the affected PIC, and validate whether or not IR7 is set. If it isn't, then
41 * the interrupt is spurious and should be ignored.
43 * Note that for a spurious IRQ15, we DO have to send an EOI to the master for
44 * IRQ2 since the line was asserted by the slave when it received the spurious
47 * - When the 80287/80387 math co-processor generates an FPU/NPX trap, this is
48 * connected to IRQ13, so we have to clear the busy latch on the NPX port.
50 PHAL_DISMISS_INTERRUPT HalpSpecialDismissTable
[16] =
52 HalpDismissIrqGeneric
,
53 HalpDismissIrqGeneric
,
54 HalpDismissIrqGeneric
,
55 HalpDismissIrqGeneric
,
56 HalpDismissIrqGeneric
,
57 HalpDismissIrqGeneric
,
58 HalpDismissIrqGeneric
,
60 HalpDismissIrqGeneric
,
61 HalpDismissIrqGeneric
,
62 HalpDismissIrqGeneric
,
63 HalpDismissIrqGeneric
,
64 HalpDismissIrqGeneric
,
66 HalpDismissIrqGeneric
,
71 * These are the level IRQ dismissal functions that get copied in the table
72 * above if the given IRQ is actually level triggered.
74 PHAL_DISMISS_INTERRUPT HalpSpecialDismissLevelTable
[16] =
83 HalpDismissIrq07Level
,
89 HalpDismissIrq13Level
,
94 /* This table contains the static x86 PIC mapping between IRQLs and IRQs */
95 ULONG KiI8259MaskTable
[32] =
97 #if defined(__GNUC__) && \
98 (__GNUC__ * 100 + __GNUC_MINOR__ >= 404)
100 * It Device IRQLs only start at 4 or higher, so these are just software
101 * IRQLs that don't really change anything on the hardware
103 0b00000000000000000000000000000000, /* IRQL 0 */
104 0b00000000000000000000000000000000, /* IRQL 1 */
105 0b00000000000000000000000000000000, /* IRQL 2 */
106 0b00000000000000000000000000000000, /* IRQL 3 */
109 * These next IRQLs are actually useless from the PIC perspective, because
110 * with only 2 PICs, the mask you can send them is only 8 bits each, for 16
111 * bits total, so these IRQLs are masking off a phantom PIC.
113 0b11111111100000000000000000000000, /* IRQL 4 */
114 0b11111111110000000000000000000000, /* IRQL 5 */
115 0b11111111111000000000000000000000, /* IRQL 6 */
116 0b11111111111100000000000000000000, /* IRQL 7 */
117 0b11111111111110000000000000000000, /* IRQL 8 */
118 0b11111111111111000000000000000000, /* IRQL 9 */
119 0b11111111111111100000000000000000, /* IRQL 10 */
120 0b11111111111111110000000000000000, /* IRQL 11 */
123 * Okay, now we're finally starting to mask off IRQs on the slave PIC, from
124 * IRQ15 to IRQ8. This means the higher-level IRQs get less priority in the
127 0b11111111111111111000000000000000, /* IRQL 12 */
128 0b11111111111111111100000000000000, /* IRQL 13 */
129 0b11111111111111111110000000000000, /* IRQL 14 */
130 0b11111111111111111111000000000000, /* IRQL 15 */
131 0b11111111111111111111100000000000, /* IRQL 16 */
132 0b11111111111111111111110000000000, /* IRQL 17 */
133 0b11111111111111111111111000000000, /* IRQL 18 */
134 0b11111111111111111111111000000000, /* IRQL 19 */
137 * Now we mask off the IRQs on the master. Notice the 0 "droplet"? You might
138 * have also seen that IRQL 18 and 19 are essentially equal as far as the
139 * PIC is concerned. That bit is actually IRQ8, which happens to be the RTC.
140 * The RTC will keep firing as long as we don't reach PROFILE_LEVEL which
141 * actually kills it. The RTC clock (unlike the system clock) is used by the
142 * profiling APIs in the HAL, so that explains the logic.
144 0b11111111111111111111111010000000, /* IRQL 20 */
145 0b11111111111111111111111011000000, /* IRQL 21 */
146 0b11111111111111111111111011100000, /* IRQL 22 */
147 0b11111111111111111111111011110000, /* IRQL 23 */
148 0b11111111111111111111111011111000, /* IRQL 24 */
149 0b11111111111111111111111011111000, /* IRQL 25 */
150 0b11111111111111111111111011111010, /* IRQL 26 */
151 0b11111111111111111111111111111010, /* IRQL 27 */
154 * IRQL 24 and 25 are actually identical, so IRQL 28 is actually the last
155 * IRQL to modify a bit on the master PIC. It happens to modify the very
156 * last of the IRQs, IRQ0, which corresponds to the system clock interval
157 * timer that keeps track of time (the Windows heartbeat). We only want to
158 * turn this off at a high-enough IRQL, which is why IRQLs 24 and 25 are the
159 * same to give this guy a chance to come up higher. Note that IRQL 28 is
160 * called CLOCK2_LEVEL, which explains the usage we just explained.
162 0b11111111111111111111111111111011, /* IRQL 28 */
165 * We have finished off with the PIC so there's nothing left to mask at the
166 * level of these IRQLs, making them only logical IRQLs on x86 machines.
167 * Note that we have another 0 "droplet" you might've caught since IRQL 26.
168 * In this case, it's the 2nd bit that never gets turned off, which is IRQ2,
169 * the cascade IRQ that we use to bridge the slave PIC with the master PIC.
170 * We never want to turn it off, so no matter the IRQL, it will be set to 0.
172 0b11111111111111111111111111111011, /* IRQL 29 */
173 0b11111111111111111111111111111011, /* IRQL 30 */
174 0b11111111111111111111111111111011 /* IRQL 31 */
180 0xFF800000, /* IRQL 4 */
181 0xFFC00000, /* IRQL 5 */
182 0xFFE00000, /* IRQL 6 */
183 0xFFF00000, /* IRQL 7 */
184 0xFFF80000, /* IRQL 8 */
185 0xFFFC0000, /* IRQL 9 */
186 0xFFFE0000, /* IRQL 10 */
187 0xFFFF0000, /* IRQL 11 */
188 0xFFFF8000, /* IRQL 12 */
189 0xFFFFC000, /* IRQL 13 */
190 0xFFFFE000, /* IRQL 14 */
191 0xFFFFF000, /* IRQL 15 */
192 0xFFFFF800, /* IRQL 16 */
193 0xFFFFFC00, /* IRQL 17 */
194 0xFFFFFE00, /* IRQL 18 */
195 0xFFFFFE00, /* IRQL 19 */
196 0xFFFFFE80, /* IRQL 20 */
197 0xFFFFFEC0, /* IRQL 21 */
198 0xFFFFFEE0, /* IRQL 22 */
199 0xFFFFFEF0, /* IRQL 23 */
200 0xFFFFFEF8, /* IRQL 24 */
201 0xFFFFFEF8, /* IRQL 25 */
202 0xFFFFFEFA, /* IRQL 26 */
203 0xFFFFFFFA, /* IRQL 27 */
204 0xFFFFFFFB, /* IRQL 28 */
205 0xFFFFFFFB, /* IRQL 29 */
206 0xFFFFFFFB, /* IRQL 30 */
207 0xFFFFFFFB /* IRQL 31 */
211 /* This table indicates which IRQs, if pending, can preempt a given IRQL level */
212 ULONG FindHigherIrqlMask
[32] =
214 #if defined(__GNUC__) && \
215 (__GNUC__ * 100 + __GNUC_MINOR__ >= 404)
217 * Software IRQLs, at these levels all hardware interrupts can preempt.
218 * Each higher IRQL simply enables which software IRQL can preempt the
221 0b11111111111111111111111111111110, /* IRQL 0 */
222 0b11111111111111111111111111111100, /* IRQL 1 */
223 0b11111111111111111111111111111000, /* IRQL 2 */
226 * IRQL3 means only hardware IRQLs can now preempt. These last 4 zeros will
227 * then continue throughout the rest of the list, trickling down.
229 0b11111111111111111111111111110000, /* IRQL 3 */
232 * Just like in the previous list, these masks don't really mean anything
233 * since we've only got two PICs with 16 possible IRQs total
235 0b00000111111111111111111111110000, /* IRQL 4 */
236 0b00000011111111111111111111110000, /* IRQL 5 */
237 0b00000001111111111111111111110000, /* IRQL 6 */
238 0b00000000111111111111111111110000, /* IRQL 7 */
239 0b00000000011111111111111111110000, /* IRQL 8 */
240 0b00000000001111111111111111110000, /* IRQL 9 */
241 0b00000000000111111111111111110000, /* IRQL 10 */
244 * Now we start progressivly limiting which slave PIC interrupts have the
245 * right to preempt us at each level.
247 0b00000000000011111111111111110000, /* IRQL 11 */
248 0b00000000000001111111111111110000, /* IRQL 12 */
249 0b00000000000000111111111111110000, /* IRQL 13 */
250 0b00000000000000011111111111110000, /* IRQL 14 */
251 0b00000000000000001111111111110000, /* IRQL 15 */
252 0b00000000000000000111111111110000, /* IRQL 16 */
253 0b00000000000000000011111111110000, /* IRQL 17 */
254 0b00000000000000000001111111110000, /* IRQL 18 */
255 0b00000000000000000001111111110000, /* IRQL 19 */
258 * Also recall from the earlier table that IRQL 18/19 are treated the same
259 * in order to spread the masks better thoughout the 32 IRQLs and to reflect
260 * the fact that some bits will always stay on until much higher IRQLs since
261 * they are system-critical. One such example is the 1 bit that you start to
262 * see trickling down here. This is IRQ8, the RTC timer used for profiling,
263 * so it will always preempt until we reach PROFILE_LEVEL.
265 0b00000000000000000001011111110000, /* IRQL 20 */
266 0b00000000000000000001001111110000, /* IRQL 20 */
267 0b00000000000000000001000111110000, /* IRQL 22 */
268 0b00000000000000000001000011110000, /* IRQL 23 */
269 0b00000000000000000001000001110000, /* IRQL 24 */
270 0b00000000000000000001000000110000, /* IRQL 25 */
271 0b00000000000000000001000000010000, /* IRQL 26 */
273 /* At this point, only the clock (IRQ0) can still preempt... */
274 0b00000000000000000000000000010000, /* IRQL 27 */
276 /* And any higher than that there's no relation with hardware PICs anymore */
277 0b00000000000000000000000000000000, /* IRQL 28 */
278 0b00000000000000000000000000000000, /* IRQL 29 */
279 0b00000000000000000000000000000000, /* IRQL 30 */
280 0b00000000000000000000000000000000 /* IRQL 31 */
282 0xFFFFFFFE, /* IRQL 0 */
283 0xFFFFFFFC, /* IRQL 1 */
284 0xFFFFFFF8, /* IRQL 2 */
285 0xFFFFFFF0, /* IRQL 3 */
286 0x7FFFFF0, /* IRQL 4 */
287 0x3FFFFF0, /* IRQL 5 */
288 0x1FFFFF0, /* IRQL 6 */
289 0x0FFFFF0, /* IRQL 7 */
290 0x7FFFF0, /* IRQL 8 */
291 0x3FFFF0, /* IRQL 9 */
292 0x1FFFF0, /* IRQL 10 */
293 0x0FFFF0, /* IRQL 11 */
294 0x7FFF0, /* IRQL 12 */
295 0x3FFF0, /* IRQL 13 */
296 0x1FFF0, /* IRQL 14 */
297 0x0FFF0, /* IRQL 15 */
298 0x7FF0, /* IRQL 16 */
299 0x3FF0, /* IRQL 17 */
300 0x1FF0, /* IRQL 18 */
301 0x1FF0, /* IRQL 19 */
302 0x17F0, /* IRQL 20 */
303 0x13F0, /* IRQL 21 */
304 0x11F0, /* IRQL 22 */
305 0x10F0, /* IRQL 23 */
306 0x1070, /* IRQL 24 */
307 0x1030, /* IRQL 25 */
308 0x1010, /* IRQL 26 */
317 /* Denotes minimum required IRQL before we can process pending SW interrupts */
318 KIRQL SWInterruptLookUpTable
[8] =
320 PASSIVE_LEVEL
, /* IRR 0 */
321 PASSIVE_LEVEL
, /* IRR 1 */
322 APC_LEVEL
, /* IRR 2 */
323 APC_LEVEL
, /* IRR 3 */
324 DISPATCH_LEVEL
, /* IRR 4 */
325 DISPATCH_LEVEL
, /* IRR 5 */
326 DISPATCH_LEVEL
, /* IRR 6 */
327 DISPATCH_LEVEL
/* IRR 7 */
330 #if defined(__GNUC__)
332 #define HalpDelayedHardwareInterrupt(x) \
333 VOID __cdecl HalpHardwareInterrupt##x(VOID); \
336 HalpHardwareInterrupt##x(VOID) \
338 asm volatile ("int $%c0\n"::"i"(PRIMARY_VECTOR_BASE + x)); \
341 #elif defined(_MSC_VER)
343 #define HalpDelayedHardwareInterrupt(x) \
344 VOID __cdecl HalpHardwareInterrupt##x(VOID); \
347 HalpHardwareInterrupt##x(VOID) \
351 int PRIMARY_VECTOR_BASE + x \
356 #error Unsupported compiler
359 /* Pending/delayed hardware interrupt handlers */
360 HalpDelayedHardwareInterrupt(0);
361 HalpDelayedHardwareInterrupt(1);
362 HalpDelayedHardwareInterrupt(2);
363 HalpDelayedHardwareInterrupt(3);
364 HalpDelayedHardwareInterrupt(4);
365 HalpDelayedHardwareInterrupt(5);
366 HalpDelayedHardwareInterrupt(6);
367 HalpDelayedHardwareInterrupt(7);
368 HalpDelayedHardwareInterrupt(8);
369 HalpDelayedHardwareInterrupt(9);
370 HalpDelayedHardwareInterrupt(10);
371 HalpDelayedHardwareInterrupt(11);
372 HalpDelayedHardwareInterrupt(12);
373 HalpDelayedHardwareInterrupt(13);
374 HalpDelayedHardwareInterrupt(14);
375 HalpDelayedHardwareInterrupt(15);
377 /* Handlers for pending interrupts */
378 PHAL_SW_INTERRUPT_HANDLER SWInterruptHandlerTable
[20] =
380 (PHAL_SW_INTERRUPT_HANDLER
)KiUnexpectedInterrupt
,
382 HalpDispatchInterrupt2
,
383 (PHAL_SW_INTERRUPT_HANDLER
)KiUnexpectedInterrupt
,
384 HalpHardwareInterrupt0
,
385 HalpHardwareInterrupt1
,
386 HalpHardwareInterrupt2
,
387 HalpHardwareInterrupt3
,
388 HalpHardwareInterrupt4
,
389 HalpHardwareInterrupt5
,
390 HalpHardwareInterrupt6
,
391 HalpHardwareInterrupt7
,
392 HalpHardwareInterrupt8
,
393 HalpHardwareInterrupt9
,
394 HalpHardwareInterrupt10
,
395 HalpHardwareInterrupt11
,
396 HalpHardwareInterrupt12
,
397 HalpHardwareInterrupt13
,
398 HalpHardwareInterrupt14
,
399 HalpHardwareInterrupt15
402 /* Handlers for pending software interrupts when we already have a trap frame*/
403 PHAL_SW_INTERRUPT_HANDLER_2ND_ENTRY SWInterruptHandlerTable2
[3] =
405 (PHAL_SW_INTERRUPT_HANDLER_2ND_ENTRY
)KiUnexpectedInterrupt
,
406 HalpApcInterrupt2ndEntry
,
407 HalpDispatchInterrupt2ndEntry
412 /* FUNCTIONS ******************************************************************/
416 HalpInitializePICs(IN BOOLEAN EnableInterrupts
)
426 /* Save EFlags and disable interrupts */
427 EFlags
= __readeflags();
430 /* Initialize ICW1 for master, interval 8, edge-triggered mode with ICW4 */
431 Icw1
.NeedIcw4
= TRUE
;
432 Icw1
.InterruptMode
= EdgeTriggered
;
433 Icw1
.OperatingMode
= Cascade
;
434 Icw1
.Interval
= Interval8
;
436 Icw1
.InterruptVectorAddress
= 0; /* This is only used in MCS80/85 mode */
437 __outbyte(PIC1_CONTROL_PORT
, Icw1
.Bits
);
439 /* Set interrupt vector base */
440 Icw2
.Bits
= PRIMARY_VECTOR_BASE
;
441 __outbyte(PIC1_DATA_PORT
, Icw2
.Bits
);
443 /* Connect slave to IRQ 2 */
445 Icw3
.SlaveIrq2
= TRUE
;
446 __outbyte(PIC1_DATA_PORT
, Icw3
.Bits
);
448 /* Enable 8086 mode, non-automatic EOI, non-buffered mode, non special fully nested mode */
450 Icw4
.SystemMode
= New8086Mode
;
451 Icw4
.EoiMode
= NormalEoi
;
452 Icw4
.BufferedMode
= NonBuffered
;
453 Icw4
.SpecialFullyNestedMode
= FALSE
;
454 __outbyte(PIC1_DATA_PORT
, Icw4
.Bits
);
456 /* Mask all interrupts */
457 __outbyte(PIC1_DATA_PORT
, 0xFF);
459 /* Initialize ICW1 for master, interval 8, edge-triggered mode with ICW4 */
460 Icw1
.NeedIcw4
= TRUE
;
461 Icw1
.InterruptMode
= EdgeTriggered
;
462 Icw1
.OperatingMode
= Cascade
;
463 Icw1
.Interval
= Interval8
;
465 Icw1
.InterruptVectorAddress
= 0; /* This is only used in MCS80/85 mode */
466 __outbyte(PIC2_CONTROL_PORT
, Icw1
.Bits
);
468 /* Set interrupt vector base */
469 Icw2
.Bits
= PRIMARY_VECTOR_BASE
+ 8;
470 __outbyte(PIC2_DATA_PORT
, Icw2
.Bits
);
475 __outbyte(PIC2_DATA_PORT
, Icw3
.Bits
);
477 /* Enable 8086 mode, non-automatic EOI, non-buffered mode, non special fully nested mode */
479 Icw4
.SystemMode
= New8086Mode
;
480 Icw4
.EoiMode
= NormalEoi
;
481 Icw4
.BufferedMode
= NonBuffered
;
482 Icw4
.SpecialFullyNestedMode
= FALSE
;
483 __outbyte(PIC2_DATA_PORT
, Icw4
.Bits
);
485 /* Mask all interrupts */
486 __outbyte(PIC2_DATA_PORT
, 0xFF);
488 /* Read EISA Edge/Level Register for master and slave */
489 Elcr
.Bits
= (__inbyte(EISA_ELCR_SLAVE
) << 8) | __inbyte(EISA_ELCR_MASTER
);
491 /* IRQs 0, 1, 2, 8, and 13 are system-reserved and must be edge */
492 if (!(Elcr
.Master
.Irq0Level
) && !(Elcr
.Master
.Irq1Level
) && !(Elcr
.Master
.Irq2Level
) &&
493 !(Elcr
.Slave
.Irq8Level
) && !(Elcr
.Slave
.Irq13Level
))
495 /* ELCR is as it's supposed to be, save it */
496 HalpEisaELCR
= Elcr
.Bits
;
498 /* Scan for level interrupts */
499 for (i
= 1, j
= 0; j
< 16; i
<<= 1, j
++)
501 if (HalpEisaELCR
& i
)
503 /* Switch handler to level */
504 SWInterruptHandlerTable
[j
+ 4] = HalpHardwareInterruptLevel
;
506 /* Switch dismiss to level */
507 HalpSpecialDismissTable
[j
] = HalpSpecialDismissLevelTable
[j
];
513 HalpRegisterVector(IDT_INTERNAL
,
514 PRIMARY_VECTOR_BASE
+ 2,
515 PRIMARY_VECTOR_BASE
+ 2,
518 /* Restore interrupt state */
519 if (EnableInterrupts
) EFlags
|= EFLAGS_INTERRUPT_MASK
;
520 __writeeflags(EFlags
);
525 HalpIrqToVector(UCHAR Irq
)
527 return (PRIMARY_VECTOR_BASE
+ Irq
);
532 HalpVectorToIrq(UCHAR Vector
)
534 return (Vector
- PRIMARY_VECTOR_BASE
);
539 HalpVectorToIrql(UCHAR Vector
)
541 return (PROFILE_LEVEL
- (Vector
- PRIMARY_VECTOR_BASE
));
544 /* IRQL MANAGEMENT ************************************************************/
551 KeGetCurrentIrql(VOID
)
553 /* Return the IRQL */
554 return KeGetPcr()->Irql
;
562 KeRaiseIrqlToDpcLevel(VOID
)
564 PKPCR Pcr
= KeGetPcr();
567 /* Save and update IRQL */
568 CurrentIrql
= Pcr
->Irql
;
569 Pcr
->Irql
= DISPATCH_LEVEL
;
572 /* Validate correct raise */
573 if (CurrentIrql
> DISPATCH_LEVEL
) KeBugCheck(IRQL_NOT_GREATER_OR_EQUAL
);
576 /* Return the previous value */
585 KeRaiseIrqlToSynchLevel(VOID
)
587 PKPCR Pcr
= KeGetPcr();
590 /* Save and update IRQL */
591 CurrentIrql
= Pcr
->Irql
;
592 Pcr
->Irql
= SYNCH_LEVEL
;
595 /* Validate correct raise */
596 if (CurrentIrql
> SYNCH_LEVEL
)
599 KeBugCheckEx(IRQL_NOT_GREATER_OR_EQUAL
,
607 /* Return the previous value */
616 KfRaiseIrql(IN KIRQL NewIrql
)
618 PKPCR Pcr
= KeGetPcr();
621 /* Read current IRQL */
622 CurrentIrql
= Pcr
->Irql
;
625 /* Validate correct raise */
626 if (CurrentIrql
> NewIrql
)
629 Pcr
->Irql
= PASSIVE_LEVEL
;
630 KeBugCheck(IRQL_NOT_GREATER_OR_EQUAL
);
637 /* Return old IRQL */
647 KfLowerIrql(IN KIRQL OldIrql
)
650 ULONG PendingIrql
, PendingIrqlMask
;
651 PKPCR Pcr
= KeGetPcr();
655 /* Validate correct lower */
656 if (OldIrql
> Pcr
->Irql
)
659 Pcr
->Irql
= HIGH_LEVEL
;
660 KeBugCheck(IRQL_NOT_LESS_OR_EQUAL
);
664 /* Save EFlags and disable interrupts */
665 EFlags
= __readeflags();
671 /* Check for pending software interrupts and compare with current IRQL */
672 PendingIrqlMask
= Pcr
->IRR
& FindHigherIrqlMask
[OldIrql
];
675 /* Check if pending IRQL affects hardware state */
676 BitScanReverse(&PendingIrql
, PendingIrqlMask
);
677 if (PendingIrql
> DISPATCH_LEVEL
)
679 /* Set new PIC mask */
680 Mask
.Both
= Pcr
->IDR
& 0xFFFF;
681 __outbyte(PIC1_DATA_PORT
, Mask
.Master
);
682 __outbyte(PIC2_DATA_PORT
, Mask
.Slave
);
685 Pcr
->IRR
^= (1 << PendingIrql
);
688 /* Now handle pending interrupt */
689 SWInterruptHandlerTable
[PendingIrql
]();
692 /* Restore interrupt state */
693 __writeeflags(EFlags
);
696 /* SOFTWARE INTERRUPTS ********************************************************/
703 HalRequestSoftwareInterrupt(IN KIRQL Irql
)
706 PKPCR Pcr
= KeGetPcr();
709 /* Save EFlags and disable interrupts */
710 EFlags
= __readeflags();
713 /* Mask out the requested bit */
714 Pcr
->IRR
|= (1 << Irql
);
716 /* Check for pending software interrupts and compare with current IRQL */
717 PendingIrql
= SWInterruptLookUpTable
[Pcr
->IRR
& 3];
718 if (PendingIrql
> Pcr
->Irql
) SWInterruptHandlerTable
[PendingIrql
]();
720 /* Restore interrupt state */
721 __writeeflags(EFlags
);
729 HalClearSoftwareInterrupt(IN KIRQL Irql
)
731 /* Mask out the requested bit */
732 KeGetPcr()->IRR
&= ~(1 << Irql
);
737 HalpEndSoftwareInterrupt(IN KIRQL OldIrql
,
738 IN PKTRAP_FRAME TrapFrame
)
740 ULONG PendingIrql
, PendingIrqlMask
, PendingIrqMask
;
741 PKPCR Pcr
= KeGetPcr();
747 /* Loop checking for pending interrupts */
750 /* Check for pending software interrupts and compare with current IRQL */
751 PendingIrqlMask
= Pcr
->IRR
& FindHigherIrqlMask
[OldIrql
];
752 if (!PendingIrqlMask
) return;
754 /* Check for in-service delayed interrupt */
755 if (Pcr
->IrrActive
& 0xFFFFFFF0) return;
757 /* Check if pending IRQL affects hardware state */
758 BitScanReverse(&PendingIrql
, PendingIrqlMask
);
759 if (PendingIrql
> DISPATCH_LEVEL
)
761 /* Set new PIC mask */
762 Mask
.Both
= Pcr
->IDR
& 0xFFFF;
763 __outbyte(PIC1_DATA_PORT
, Mask
.Master
);
764 __outbyte(PIC2_DATA_PORT
, Mask
.Slave
);
766 /* Set active bit otherwise, and clear it from IRR */
767 PendingIrqMask
= (1 << PendingIrql
);
768 Pcr
->IrrActive
|= PendingIrqMask
;
769 Pcr
->IRR
^= PendingIrqMask
;
771 /* Handle delayed hardware interrupt */
772 SWInterruptHandlerTable
[PendingIrql
]();
774 /* Handling complete */
775 Pcr
->IrrActive
^= PendingIrqMask
;
779 /* No need to loop checking for hardware interrupts */
780 SWInterruptHandlerTable2
[PendingIrql
](TrapFrame
);
786 /* EDGE INTERRUPT DISMISSAL FUNCTIONS *****************************************/
790 _HalpDismissIrqGeneric(IN KIRQL Irql
,
797 PKPCR Pcr
= KeGetPcr();
799 /* First save current IRQL and compare it to the requested one */
800 CurrentIrql
= Pcr
->Irql
;
802 /* Check if this interrupt is really allowed to happen */
803 if (Irql
> CurrentIrql
)
805 /* Set the new IRQL and return the current one */
807 *OldIrql
= CurrentIrql
;
809 /* Prepare OCW2 for EOI */
811 Ocw2
.EoiMode
= SpecificEoi
;
813 /* Check which PIC needs the EOI */
816 /* Send the EOI for the IRQ */
817 __outbyte(PIC2_CONTROL_PORT
, Ocw2
.Bits
| ((Irq
- 8) & 0xFF));
819 /* Send the EOI for IRQ2 on the master because this was cascaded */
820 __outbyte(PIC1_CONTROL_PORT
, Ocw2
.Bits
| 2);
824 /* Send the EOI for the IRQ */
825 __outbyte(PIC1_CONTROL_PORT
, Ocw2
.Bits
| (Irq
&0xFF));
828 /* Enable interrupts and return success */
833 /* Update the IRR so that we deliver this interrupt when the IRQL is proper */
834 Pcr
->IRR
|= (1 << (Irq
+ 4));
836 /* Set new PIC mask to real IRQL level, since the optimization is lost now */
837 Mask
.Both
= (KiI8259MaskTable
[CurrentIrql
] | Pcr
->IDR
) & 0xFFFF;
838 __outbyte(PIC1_DATA_PORT
, Mask
.Master
);
839 __outbyte(PIC2_DATA_PORT
, Mask
.Slave
);
841 /* Now lie and say this was spurious */
847 HalpDismissIrqGeneric(IN KIRQL Irql
,
851 /* Run the inline code */
852 return _HalpDismissIrqGeneric(Irql
, Irq
, OldIrql
);
857 HalpDismissIrq15(IN KIRQL Irql
,
865 /* Request the ISR */
867 Ocw3
.Sbo
= 1; /* This encodes an OCW3 vs. an OCW2 */
868 Ocw3
.ReadRequest
= ReadIsr
;
869 __outbyte(PIC2_CONTROL_PORT
, Ocw3
.Bits
);
872 Isr
.Bits
= __inbyte(PIC2_CONTROL_PORT
);
874 /* Is IRQ15 really active (this is IR7) */
875 if (Isr
.Irq7
== FALSE
)
877 /* It isn't, so we have to EOI IRQ2 because this was cascaded */
879 Ocw2
.EoiMode
= SpecificEoi
;
880 __outbyte(PIC1_CONTROL_PORT
, Ocw2
.Bits
| 2);
882 /* And now fail since this was spurious */
886 /* Do normal interrupt dismiss */
887 return _HalpDismissIrqGeneric(Irql
, Irq
, OldIrql
);
893 HalpDismissIrq13(IN KIRQL Irql
,
897 /* Clear the FPU busy latch */
900 /* Do normal interrupt dismiss */
901 return _HalpDismissIrqGeneric(Irql
, Irq
, OldIrql
);
906 HalpDismissIrq07(IN KIRQL Irql
,
913 /* Request the ISR */
916 Ocw3
.ReadRequest
= ReadIsr
;
917 __outbyte(PIC1_CONTROL_PORT
, Ocw3
.Bits
);
920 Isr
.Bits
= __inbyte(PIC1_CONTROL_PORT
);
922 /* Is IRQ 7 really active? If it isn't, this is spurious so fail */
923 if (Isr
.Irq7
== FALSE
) return FALSE
;
925 /* Do normal interrupt dismiss */
926 return _HalpDismissIrqGeneric(Irql
, Irq
, OldIrql
);
929 /* LEVEL INTERRUPT DISMISSAL FUNCTIONS ****************************************/
933 _HalpDismissIrqLevel(IN KIRQL Irql
,
940 PKPCR Pcr
= KeGetPcr();
943 Mask
.Both
= (KiI8259MaskTable
[Irql
] | Pcr
->IDR
) & 0xFFFF;
944 __outbyte(PIC1_DATA_PORT
, Mask
.Master
);
945 __outbyte(PIC2_DATA_PORT
, Mask
.Slave
);
947 /* Update the IRR so that we clear this interrupt when the IRQL is proper */
948 Pcr
->IRR
|= (1 << (Irq
+ 4));
950 /* Save current IRQL */
951 CurrentIrql
= Pcr
->Irql
;
953 /* Prepare OCW2 for EOI */
955 Ocw2
.EoiMode
= SpecificEoi
;
957 /* Check which PIC needs the EOI */
960 /* Send the EOI for the IRQ */
961 __outbyte(PIC2_CONTROL_PORT
, Ocw2
.Bits
| ((Irq
- 8) & 0xFF));
963 /* Send the EOI for IRQ2 on the master because this was cascaded */
964 __outbyte(PIC1_CONTROL_PORT
, Ocw2
.Bits
| 2);
968 /* Send the EOI for the IRQ */
969 __outbyte(PIC1_CONTROL_PORT
, Ocw2
.Bits
| (Irq
& 0xFF));
972 /* Check if this interrupt should be allowed to happen */
973 if (Irql
> CurrentIrql
)
975 /* Set the new IRQL and return the current one */
977 *OldIrql
= CurrentIrql
;
979 /* Enable interrupts and return success */
984 /* Now lie and say this was spurious */
990 HalpDismissIrqLevel(IN KIRQL Irql
,
994 /* Run the inline code */
995 return _HalpDismissIrqLevel(Irql
, Irq
, OldIrql
);
1000 HalpDismissIrq15Level(IN KIRQL Irql
,
1008 /* Request the ISR */
1010 Ocw3
.Sbo
= 1; /* This encodes an OCW3 vs. an OCW2 */
1011 Ocw3
.ReadRequest
= ReadIsr
;
1012 __outbyte(PIC2_CONTROL_PORT
, Ocw3
.Bits
);
1015 Isr
.Bits
= __inbyte(PIC2_CONTROL_PORT
);
1017 /* Is IRQ15 really active (this is IR7) */
1018 if (Isr
.Irq7
== FALSE
)
1020 /* It isn't, so we have to EOI IRQ2 because this was cascaded */
1022 Ocw2
.EoiMode
= SpecificEoi
;
1023 __outbyte(PIC1_CONTROL_PORT
, Ocw2
.Bits
| 2);
1025 /* And now fail since this was spurious */
1029 /* Do normal interrupt dismiss */
1030 return _HalpDismissIrqLevel(Irql
, Irq
, OldIrql
);
1035 HalpDismissIrq13Level(IN KIRQL Irql
,
1039 /* Clear the FPU busy latch */
1042 /* Do normal interrupt dismiss */
1043 return _HalpDismissIrqLevel(Irql
, Irq
, OldIrql
);
1048 HalpDismissIrq07Level(IN KIRQL Irql
,
1055 /* Request the ISR */
1058 Ocw3
.ReadRequest
= ReadIsr
;
1059 __outbyte(PIC1_CONTROL_PORT
, Ocw3
.Bits
);
1062 Isr
.Bits
= __inbyte(PIC1_CONTROL_PORT
);
1064 /* Is IRQ 7 really active? If it isn't, this is spurious so fail */
1065 if (Isr
.Irq7
== FALSE
) return FALSE
;
1067 /* Do normal interrupt dismiss */
1068 return _HalpDismissIrqLevel(Irql
, Irq
, OldIrql
);
1073 HalpHardwareInterruptLevel(VOID
)
1075 PKPCR Pcr
= KeGetPcr();
1076 ULONG PendingIrqlMask
, PendingIrql
;
1078 /* Check for pending software interrupts and compare with current IRQL */
1079 PendingIrqlMask
= Pcr
->IRR
& FindHigherIrqlMask
[Pcr
->Irql
];
1080 if (PendingIrqlMask
)
1082 /* Check for in-service delayed interrupt */
1083 if (Pcr
->IrrActive
& 0xFFFFFFF0) return;
1085 /* Check if pending IRQL affects hardware state */
1086 BitScanReverse(&PendingIrql
, PendingIrqlMask
);
1089 Pcr
->IRR
^= (1 << PendingIrql
);
1091 /* Now handle pending interrupt */
1092 SWInterruptHandlerTable
[PendingIrql
]();
1096 /* SYSTEM INTERRUPTS **********************************************************/
1103 HalEnableSystemInterrupt(IN ULONG Vector
,
1105 IN KINTERRUPT_MODE InterruptMode
)
1108 PKPCR Pcr
= KeGetPcr();
1111 /* Validate the IRQ */
1112 Irq
= Vector
- PRIMARY_VECTOR_BASE
;
1113 if (Irq
>= CLOCK2_LEVEL
) return FALSE
;
1115 /* Check for level interrupt */
1116 if (InterruptMode
== LevelSensitive
)
1118 /* Switch handler to level */
1119 SWInterruptHandlerTable
[Irq
+ 4] = HalpHardwareInterruptLevel
;
1121 /* Switch dismiss to level */
1122 HalpSpecialDismissTable
[Irq
] = HalpSpecialDismissLevelTable
[Irq
];
1125 /* Disable interrupts */
1128 /* Update software IDR */
1129 Pcr
->IDR
&= ~(1 << Irq
);
1131 /* Set new PIC mask */
1132 PicMask
.Both
= (KiI8259MaskTable
[Pcr
->Irql
] | Pcr
->IDR
) & 0xFFFF;
1133 __outbyte(PIC1_DATA_PORT
, PicMask
.Master
);
1134 __outbyte(PIC2_DATA_PORT
, PicMask
.Slave
);
1136 /* Enable interrupts and exit */
1146 HalDisableSystemInterrupt(IN ULONG Vector
,
1152 /* Compute new combined IRQ mask */
1153 IrqMask
= 1 << (Vector
- PRIMARY_VECTOR_BASE
);
1155 /* Disable interrupts */
1158 /* Update software IDR */
1159 KeGetPcr()->IDR
|= IrqMask
;
1161 /* Read current interrupt mask */
1162 PicMask
.Master
= __inbyte(PIC1_DATA_PORT
);
1163 PicMask
.Slave
= __inbyte(PIC2_DATA_PORT
);
1165 /* Add the new disabled interrupt */
1166 PicMask
.Both
|= IrqMask
;
1168 /* Write new interrupt mask */
1169 __outbyte(PIC1_DATA_PORT
, PicMask
.Master
);
1170 __outbyte(PIC2_DATA_PORT
, PicMask
.Slave
);
1172 /* Bring interrupts back */
1181 HalBeginSystemInterrupt(IN KIRQL Irql
,
1187 /* Get the IRQ and call the proper routine to handle it */
1188 Irq
= Vector
- PRIMARY_VECTOR_BASE
;
1189 return HalpSpecialDismissTable
[Irq
](Irql
, Irq
, OldIrql
);
1197 HalEndSystemInterrupt(IN KIRQL OldIrql
,
1198 IN PKTRAP_FRAME TrapFrame
)
1200 ULONG PendingIrql
, PendingIrqlMask
, PendingIrqMask
;
1201 PKPCR Pcr
= KeGetPcr();
1205 Pcr
->Irql
= OldIrql
;
1207 /* Check for pending software interrupts and compare with current IRQL */
1208 PendingIrqlMask
= Pcr
->IRR
& FindHigherIrqlMask
[OldIrql
];
1209 if (PendingIrqlMask
)
1211 /* Check for in-service delayed interrupt */
1212 if (Pcr
->IrrActive
& 0xFFFFFFF0) return;
1214 /* Loop checking for pending interrupts */
1217 /* Check if pending IRQL affects hardware state */
1218 BitScanReverse(&PendingIrql
, PendingIrqlMask
);
1219 if (PendingIrql
> DISPATCH_LEVEL
)
1221 /* Set new PIC mask */
1222 Mask
.Both
= Pcr
->IDR
& 0xFFFF;
1223 __outbyte(PIC1_DATA_PORT
, Mask
.Master
);
1224 __outbyte(PIC2_DATA_PORT
, Mask
.Slave
);
1226 /* Now check if this specific interrupt is already in-service */
1227 PendingIrqMask
= (1 << PendingIrql
);
1228 if (Pcr
->IrrActive
& PendingIrqMask
) return;
1230 /* Set active bit otherwise, and clear it from IRR */
1231 Pcr
->IrrActive
|= PendingIrqMask
;
1232 Pcr
->IRR
^= PendingIrqMask
;
1234 /* Handle delayed hardware interrupt */
1235 SWInterruptHandlerTable
[PendingIrql
]();
1237 /* Handling complete */
1238 Pcr
->IrrActive
^= PendingIrqMask
;
1240 /* Check if there's still interrupts pending */
1241 PendingIrqlMask
= Pcr
->IRR
& FindHigherIrqlMask
[Pcr
->Irql
];
1242 if (!PendingIrqlMask
) break;
1246 /* Now handle pending software interrupt */
1247 SWInterruptHandlerTable2
[PendingIrql
](TrapFrame
);
1254 /* SOFTWARE INTERRUPT TRAPS ***************************************************/
1259 _HalpApcInterruptHandler(IN PKTRAP_FRAME TrapFrame
)
1262 PKPCR Pcr
= KeGetPcr();
1264 /* Save the current IRQL and update it */
1265 CurrentIrql
= Pcr
->Irql
;
1266 Pcr
->Irql
= APC_LEVEL
;
1268 /* Remove DPC from IRR */
1269 Pcr
->IRR
&= ~(1 << APC_LEVEL
);
1271 /* Enable interrupts and call the kernel's APC interrupt handler */
1273 KiDeliverApc(((KiUserTrap(TrapFrame
)) || (TrapFrame
->EFlags
& EFLAGS_V86_MASK
)) ?
1274 UserMode
: KernelMode
,
1278 /* Disable interrupts and end the interrupt */
1280 HalpEndSoftwareInterrupt(CurrentIrql
, TrapFrame
);
1282 /* Exit the interrupt */
1283 KiEoiHelper(TrapFrame
);
1289 HalpApcInterrupt2ndEntry(IN PKTRAP_FRAME TrapFrame
)
1292 _HalpApcInterruptHandler(TrapFrame
);
1298 HalpApcInterruptHandler(IN PKTRAP_FRAME TrapFrame
)
1300 /* Set up a fake INT Stack */
1301 TrapFrame
->EFlags
= __readeflags();
1302 TrapFrame
->SegCs
= KGDT_R0_CODE
;
1303 TrapFrame
->Eip
= TrapFrame
->Eax
;
1305 /* Build the trap frame */
1306 KiEnterInterruptTrap(TrapFrame
);
1309 _HalpApcInterruptHandler(TrapFrame
);
1314 _HalpDispatchInterruptHandler(VOID
)
1317 PKPCR Pcr
= KeGetPcr();
1319 /* Save the current IRQL and update it */
1320 CurrentIrql
= Pcr
->Irql
;
1321 Pcr
->Irql
= DISPATCH_LEVEL
;
1323 /* Remove DPC from IRR */
1324 Pcr
->IRR
&= ~(1 << DISPATCH_LEVEL
);
1326 /* Enable interrupts and call the kernel's DPC interrupt handler */
1328 KiDispatchInterrupt();
1338 HalpDispatchInterrupt2ndEntry(IN PKTRAP_FRAME TrapFrame
)
1343 CurrentIrql
= _HalpDispatchInterruptHandler();
1345 /* End the interrupt */
1346 HalpEndSoftwareInterrupt(CurrentIrql
, TrapFrame
);
1348 /* Exit the interrupt */
1349 KiEoiHelper(TrapFrame
);
1354 HalpDispatchInterrupt2(VOID
)
1356 ULONG PendingIrqlMask
, PendingIrql
;
1359 PKPCR Pcr
= KeGetPcr();
1362 OldIrql
= _HalpDispatchInterruptHandler();
1365 Pcr
->Irql
= OldIrql
;
1367 /* Check for pending software interrupts and compare with current IRQL */
1368 PendingIrqlMask
= Pcr
->IRR
& FindHigherIrqlMask
[OldIrql
];
1369 if (PendingIrqlMask
)
1371 /* Check if pending IRQL affects hardware state */
1372 BitScanReverse(&PendingIrql
, PendingIrqlMask
);
1373 if (PendingIrql
> DISPATCH_LEVEL
)
1375 /* Set new PIC mask */
1376 Mask
.Both
= Pcr
->IDR
& 0xFFFF;
1377 __outbyte(PIC1_DATA_PORT
, Mask
.Master
);
1378 __outbyte(PIC2_DATA_PORT
, Mask
.Slave
);
1381 Pcr
->IRR
^= (1 << PendingIrql
);
1384 /* Now handle pending interrupt */
1385 SWInterruptHandlerTable
[PendingIrql
]();
1393 KeGetCurrentIrql(VOID
)
1395 return PASSIVE_LEVEL
;