3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: hal/halx86/up/pic.c
5 * PURPOSE: HAL PIC Management and Control Code
6 * PROGRAMMERS: ReactOS Portable Systems Group
9 /* INCLUDES *******************************************************************/
17 HalpEndSoftwareInterrupt(IN KIRQL OldIrql
,
18 IN PKTRAP_FRAME TrapFrame
);
20 /* GLOBALS ********************************************************************/
24 * This table basically keeps track of level vs edge triggered interrupts.
25 * Windows has 250+ entries, but it seems stupid to replicate that since the PIC
26 * can't actually have that many.
28 * When a level interrupt is registered, the respective pointer in this table is
29 * modified to point to a dimiss routine for level interrupts instead.
31 * The other thing this table does is special case IRQ7, IRQ13 and IRQ15:
33 * - If an IRQ line is deasserted before it is acknowledged due to a noise spike
34 * generated by an expansion device (since the IRQ line is low during the 1st
35 * acknowledge bus cycle), the i8259 will keep the line low for at least 100ns
36 * When the spike passes, a pull-up resistor will return the IRQ line to high.
37 * Since the PIC requires the input be high until the first acknowledge, the
38 * i8259 knows that this was a spurious interrupt, and on the second interrupt
39 * acknowledge cycle, it reports this to the CPU. Since no valid interrupt has
40 * actually happened Intel hardcoded the chip to report IRQ7 on the master PIC
41 * and IRQ15 on the slave PIC (IR7 either way).
43 * "ISA System Architecture", 3rd Edition, states that these cases should be
44 * handled by reading the respective Interrupt Service Request (ISR) bits from
45 * the affected PIC, and validate whether or not IR7 is set. If it isn't, then
46 * the interrupt is spurious and should be ignored.
48 * Note that for a spurious IRQ15, we DO have to send an EOI to the master for
49 * IRQ2 since the line was asserted by the slave when it received the spurious
52 * - When the 80287/80387 math co-processor generates an FPU/NPX trap, this is
53 * connected to IRQ13, so we have to clear the busy latch on the NPX port.
55 PHAL_DISMISS_INTERRUPT HalpSpecialDismissTable
[16] =
57 HalpDismissIrqGeneric
,
58 HalpDismissIrqGeneric
,
59 HalpDismissIrqGeneric
,
60 HalpDismissIrqGeneric
,
61 HalpDismissIrqGeneric
,
62 HalpDismissIrqGeneric
,
63 HalpDismissIrqGeneric
,
65 HalpDismissIrqGeneric
,
66 HalpDismissIrqGeneric
,
67 HalpDismissIrqGeneric
,
68 HalpDismissIrqGeneric
,
69 HalpDismissIrqGeneric
,
71 HalpDismissIrqGeneric
,
76 * These are the level IRQ dismissal functions that get copied in the table
77 * above if the given IRQ is actually level triggered.
79 PHAL_DISMISS_INTERRUPT HalpSpecialDismissLevelTable
[16] =
88 HalpDismissIrq07Level
,
94 HalpDismissIrq13Level
,
99 /* This table contains the static x86 PIC mapping between IRQLs and IRQs */
100 ULONG KiI8259MaskTable
[32] =
102 #if defined(__GNUC__) || defined(__clang__) || (defined(_MSC_VER) && _MSC_VER >= 1900)
104 * It Device IRQLs only start at 4 or higher, so these are just software
105 * IRQLs that don't really change anything on the hardware
107 0b00000000000000000000000000000000, /* IRQL 0 */
108 0b00000000000000000000000000000000, /* IRQL 1 */
109 0b00000000000000000000000000000000, /* IRQL 2 */
110 0b00000000000000000000000000000000, /* IRQL 3 */
113 * These next IRQLs are actually useless from the PIC perspective, because
114 * with only 2 PICs, the mask you can send them is only 8 bits each, for 16
115 * bits total, so these IRQLs are masking off a phantom PIC.
117 0b11111111100000000000000000000000, /* IRQL 4 */
118 0b11111111110000000000000000000000, /* IRQL 5 */
119 0b11111111111000000000000000000000, /* IRQL 6 */
120 0b11111111111100000000000000000000, /* IRQL 7 */
121 0b11111111111110000000000000000000, /* IRQL 8 */
122 0b11111111111111000000000000000000, /* IRQL 9 */
123 0b11111111111111100000000000000000, /* IRQL 10 */
124 0b11111111111111110000000000000000, /* IRQL 11 */
127 * Okay, now we're finally starting to mask off IRQs on the slave PIC, from
128 * IRQ15 to IRQ8. This means the higher-level IRQs get less priority in the
131 0b11111111111111111000000000000000, /* IRQL 12 */
132 0b11111111111111111100000000000000, /* IRQL 13 */
133 0b11111111111111111110000000000000, /* IRQL 14 */
134 0b11111111111111111111000000000000, /* IRQL 15 */
135 0b11111111111111111111100000000000, /* IRQL 16 */
136 0b11111111111111111111110000000000, /* IRQL 17 */
137 0b11111111111111111111111000000000, /* IRQL 18 */
138 0b11111111111111111111111000000000, /* IRQL 19 */
141 * Now we mask off the IRQs on the master. Notice the 0 "droplet"? You might
142 * have also seen that IRQL 18 and 19 are essentially equal as far as the
143 * PIC is concerned. That bit is actually IRQ8, which happens to be the RTC.
144 * The RTC will keep firing as long as we don't reach PROFILE_LEVEL which
145 * actually kills it. The RTC clock (unlike the system clock) is used by the
146 * profiling APIs in the HAL, so that explains the logic.
148 0b11111111111111111111111010000000, /* IRQL 20 */
149 0b11111111111111111111111011000000, /* IRQL 21 */
150 0b11111111111111111111111011100000, /* IRQL 22 */
151 0b11111111111111111111111011110000, /* IRQL 23 */
152 0b11111111111111111111111011111000, /* IRQL 24 */
153 0b11111111111111111111111011111000, /* IRQL 25 */
154 0b11111111111111111111111011111010, /* IRQL 26 */
155 0b11111111111111111111111111111010, /* IRQL 27 */
158 * IRQL 24 and 25 are actually identical, so IRQL 28 is actually the last
159 * IRQL to modify a bit on the master PIC. It happens to modify the very
160 * last of the IRQs, IRQ0, which corresponds to the system clock interval
161 * timer that keeps track of time (the Windows heartbeat). We only want to
162 * turn this off at a high-enough IRQL, which is why IRQLs 24 and 25 are the
163 * same to give this guy a chance to come up higher. Note that IRQL 28 is
164 * called CLOCK2_LEVEL, which explains the usage we just explained.
166 0b11111111111111111111111111111011, /* IRQL 28 */
169 * We have finished off with the PIC so there's nothing left to mask at the
170 * level of these IRQLs, making them only logical IRQLs on x86 machines.
171 * Note that we have another 0 "droplet" you might've caught since IRQL 26.
172 * In this case, it's the 2nd bit that never gets turned off, which is IRQ2,
173 * the cascade IRQ that we use to bridge the slave PIC with the master PIC.
174 * We never want to turn it off, so no matter the IRQL, it will be set to 0.
176 0b11111111111111111111111111111011, /* IRQL 29 */
177 0b11111111111111111111111111111011, /* IRQL 30 */
178 0b11111111111111111111111111111011 /* IRQL 31 */
184 0xFF800000, /* IRQL 4 */
185 0xFFC00000, /* IRQL 5 */
186 0xFFE00000, /* IRQL 6 */
187 0xFFF00000, /* IRQL 7 */
188 0xFFF80000, /* IRQL 8 */
189 0xFFFC0000, /* IRQL 9 */
190 0xFFFE0000, /* IRQL 10 */
191 0xFFFF0000, /* IRQL 11 */
192 0xFFFF8000, /* IRQL 12 */
193 0xFFFFC000, /* IRQL 13 */
194 0xFFFFE000, /* IRQL 14 */
195 0xFFFFF000, /* IRQL 15 */
196 0xFFFFF800, /* IRQL 16 */
197 0xFFFFFC00, /* IRQL 17 */
198 0xFFFFFE00, /* IRQL 18 */
199 0xFFFFFE00, /* IRQL 19 */
200 0xFFFFFE80, /* IRQL 20 */
201 0xFFFFFEC0, /* IRQL 21 */
202 0xFFFFFEE0, /* IRQL 22 */
203 0xFFFFFEF0, /* IRQL 23 */
204 0xFFFFFEF8, /* IRQL 24 */
205 0xFFFFFEF8, /* IRQL 25 */
206 0xFFFFFEFA, /* IRQL 26 */
207 0xFFFFFFFA, /* IRQL 27 */
208 0xFFFFFFFB, /* IRQL 28 */
209 0xFFFFFFFB, /* IRQL 29 */
210 0xFFFFFFFB, /* IRQL 30 */
211 0xFFFFFFFB /* IRQL 31 */
215 /* This table indicates which IRQs, if pending, can preempt a given IRQL level */
216 ULONG FindHigherIrqlMask
[32] =
218 #if defined(__GNUC__) || defined(__clang__) || (defined(_MSC_VER) && _MSC_VER >= 1900)
220 * Software IRQLs, at these levels all hardware interrupts can preempt.
221 * Each higher IRQL simply enables which software IRQL can preempt the
224 0b11111111111111111111111111111110, /* IRQL 0 */
225 0b11111111111111111111111111111100, /* IRQL 1 */
226 0b11111111111111111111111111111000, /* IRQL 2 */
229 * IRQL3 means only hardware IRQLs can now preempt. These last 4 zeros will
230 * then continue throughout the rest of the list, trickling down.
232 0b11111111111111111111111111110000, /* IRQL 3 */
235 * Just like in the previous list, these masks don't really mean anything
236 * since we've only got two PICs with 16 possible IRQs total
238 0b00000111111111111111111111110000, /* IRQL 4 */
239 0b00000011111111111111111111110000, /* IRQL 5 */
240 0b00000001111111111111111111110000, /* IRQL 6 */
241 0b00000000111111111111111111110000, /* IRQL 7 */
242 0b00000000011111111111111111110000, /* IRQL 8 */
243 0b00000000001111111111111111110000, /* IRQL 9 */
244 0b00000000000111111111111111110000, /* IRQL 10 */
247 * Now we start progressivly limiting which slave PIC interrupts have the
248 * right to preempt us at each level.
250 0b00000000000011111111111111110000, /* IRQL 11 */
251 0b00000000000001111111111111110000, /* IRQL 12 */
252 0b00000000000000111111111111110000, /* IRQL 13 */
253 0b00000000000000011111111111110000, /* IRQL 14 */
254 0b00000000000000001111111111110000, /* IRQL 15 */
255 0b00000000000000000111111111110000, /* IRQL 16 */
256 0b00000000000000000011111111110000, /* IRQL 17 */
257 0b00000000000000000001111111110000, /* IRQL 18 */
258 0b00000000000000000001111111110000, /* IRQL 19 */
261 * Also recall from the earlier table that IRQL 18/19 are treated the same
262 * in order to spread the masks better thoughout the 32 IRQLs and to reflect
263 * the fact that some bits will always stay on until much higher IRQLs since
264 * they are system-critical. One such example is the 1 bit that you start to
265 * see trickling down here. This is IRQ8, the RTC timer used for profiling,
266 * so it will always preempt until we reach PROFILE_LEVEL.
268 0b00000000000000000001011111110000, /* IRQL 20 */
269 0b00000000000000000001001111110000, /* IRQL 21 */
270 0b00000000000000000001000111110000, /* IRQL 22 */
271 0b00000000000000000001000011110000, /* IRQL 23 */
272 0b00000000000000000001000001110000, /* IRQL 24 */
273 0b00000000000000000001000000110000, /* IRQL 25 */
274 0b00000000000000000001000000010000, /* IRQL 26 */
276 /* At this point, only the clock (IRQ0) can still preempt... */
277 0b00000000000000000000000000010000, /* IRQL 27 */
279 /* And any higher than that there's no relation with hardware PICs anymore */
280 0b00000000000000000000000000000000, /* IRQL 28 */
281 0b00000000000000000000000000000000, /* IRQL 29 */
282 0b00000000000000000000000000000000, /* IRQL 30 */
283 0b00000000000000000000000000000000 /* IRQL 31 */
285 0xFFFFFFFE, /* IRQL 0 */
286 0xFFFFFFFC, /* IRQL 1 */
287 0xFFFFFFF8, /* IRQL 2 */
288 0xFFFFFFF0, /* IRQL 3 */
289 0x7FFFFF0, /* IRQL 4 */
290 0x3FFFFF0, /* IRQL 5 */
291 0x1FFFFF0, /* IRQL 6 */
292 0x0FFFFF0, /* IRQL 7 */
293 0x7FFFF0, /* IRQL 8 */
294 0x3FFFF0, /* IRQL 9 */
295 0x1FFFF0, /* IRQL 10 */
296 0x0FFFF0, /* IRQL 11 */
297 0x7FFF0, /* IRQL 12 */
298 0x3FFF0, /* IRQL 13 */
299 0x1FFF0, /* IRQL 14 */
300 0x0FFF0, /* IRQL 15 */
301 0x7FF0, /* IRQL 16 */
302 0x3FF0, /* IRQL 17 */
303 0x1FF0, /* IRQL 18 */
304 0x1FF0, /* IRQL 19 */
305 0x17F0, /* IRQL 20 */
306 0x13F0, /* IRQL 21 */
307 0x11F0, /* IRQL 22 */
308 0x10F0, /* IRQL 23 */
309 0x1070, /* IRQL 24 */
310 0x1030, /* IRQL 25 */
311 0x1010, /* IRQL 26 */
320 /* Denotes minimum required IRQL before we can process pending SW interrupts */
321 KIRQL SWInterruptLookUpTable
[8] =
323 PASSIVE_LEVEL
, /* IRR 0 */
324 PASSIVE_LEVEL
, /* IRR 1 */
325 APC_LEVEL
, /* IRR 2 */
326 APC_LEVEL
, /* IRR 3 */
327 DISPATCH_LEVEL
, /* IRR 4 */
328 DISPATCH_LEVEL
, /* IRR 5 */
329 DISPATCH_LEVEL
, /* IRR 6 */
330 DISPATCH_LEVEL
/* IRR 7 */
333 #if defined(__GNUC__)
335 #define HalpDelayedHardwareInterrupt(x) \
336 VOID __cdecl HalpHardwareInterrupt##x(VOID); \
339 HalpHardwareInterrupt##x(VOID) \
341 asm volatile ("int $%c0\n"::"i"(PRIMARY_VECTOR_BASE + x)); \
344 #elif defined(_MSC_VER)
346 #define HalpDelayedHardwareInterrupt(x) \
347 VOID __cdecl HalpHardwareInterrupt##x(VOID); \
350 HalpHardwareInterrupt##x(VOID) \
354 int PRIMARY_VECTOR_BASE + x \
359 #error Unsupported compiler
362 /* Pending/delayed hardware interrupt handlers */
363 HalpDelayedHardwareInterrupt(0);
364 HalpDelayedHardwareInterrupt(1);
365 HalpDelayedHardwareInterrupt(2);
366 HalpDelayedHardwareInterrupt(3);
367 HalpDelayedHardwareInterrupt(4);
368 HalpDelayedHardwareInterrupt(5);
369 HalpDelayedHardwareInterrupt(6);
370 HalpDelayedHardwareInterrupt(7);
371 HalpDelayedHardwareInterrupt(8);
372 HalpDelayedHardwareInterrupt(9);
373 HalpDelayedHardwareInterrupt(10);
374 HalpDelayedHardwareInterrupt(11);
375 HalpDelayedHardwareInterrupt(12);
376 HalpDelayedHardwareInterrupt(13);
377 HalpDelayedHardwareInterrupt(14);
378 HalpDelayedHardwareInterrupt(15);
380 /* Handlers for pending interrupts */
381 PHAL_SW_INTERRUPT_HANDLER SWInterruptHandlerTable
[20] =
383 (PHAL_SW_INTERRUPT_HANDLER
)KiUnexpectedInterrupt
,
385 HalpDispatchInterrupt2
,
386 (PHAL_SW_INTERRUPT_HANDLER
)KiUnexpectedInterrupt
,
387 HalpHardwareInterrupt0
,
388 HalpHardwareInterrupt1
,
389 HalpHardwareInterrupt2
,
390 HalpHardwareInterrupt3
,
391 HalpHardwareInterrupt4
,
392 HalpHardwareInterrupt5
,
393 HalpHardwareInterrupt6
,
394 HalpHardwareInterrupt7
,
395 HalpHardwareInterrupt8
,
396 HalpHardwareInterrupt9
,
397 HalpHardwareInterrupt10
,
398 HalpHardwareInterrupt11
,
399 HalpHardwareInterrupt12
,
400 HalpHardwareInterrupt13
,
401 HalpHardwareInterrupt14
,
402 HalpHardwareInterrupt15
405 /* Handlers for pending software interrupts when we already have a trap frame*/
406 PHAL_SW_INTERRUPT_HANDLER_2ND_ENTRY SWInterruptHandlerTable2
[3] =
408 (PHAL_SW_INTERRUPT_HANDLER_2ND_ENTRY
)KiUnexpectedInterrupt
,
409 HalpApcInterrupt2ndEntry
,
410 HalpDispatchInterrupt2ndEntry
415 /* FUNCTIONS ******************************************************************/
419 HalpInitializePICs(IN BOOLEAN EnableInterrupts
)
425 /* Save EFlags and disable interrupts */
426 EFlags
= __readeflags();
429 /* Initialize and mask the PIC */
430 HalpInitializeLegacyPICs();
432 /* Read EISA Edge/Level Register for master and slave */
433 Elcr
.Bits
= (__inbyte(EISA_ELCR_SLAVE
) << 8) | __inbyte(EISA_ELCR_MASTER
);
435 /* IRQs 0, 1, 2, 8, and 13 are system-reserved and must be edge */
436 if (!(Elcr
.Master
.Irq0Level
) && !(Elcr
.Master
.Irq1Level
) && !(Elcr
.Master
.Irq2Level
) &&
437 !(Elcr
.Slave
.Irq8Level
) && !(Elcr
.Slave
.Irq13Level
))
439 /* ELCR is as it's supposed to be, save it */
440 HalpEisaELCR
= Elcr
.Bits
;
442 /* Scan for level interrupts */
443 for (i
= 1, j
= 0; j
< 16; i
<<= 1, j
++)
445 if (HalpEisaELCR
& i
)
447 /* Switch handler to level */
448 SWInterruptHandlerTable
[j
+ 4] = HalpHardwareInterruptLevel
;
450 /* Switch dismiss to level */
451 HalpSpecialDismissTable
[j
] = HalpSpecialDismissLevelTable
[j
];
457 HalpRegisterVector(IDT_INTERNAL
,
458 PRIMARY_VECTOR_BASE
+ 2,
459 PRIMARY_VECTOR_BASE
+ 2,
462 /* Restore interrupt state */
463 if (EnableInterrupts
) EFlags
|= EFLAGS_INTERRUPT_MASK
;
464 __writeeflags(EFlags
);
469 HalpIrqToVector(UCHAR Irq
)
471 return (PRIMARY_VECTOR_BASE
+ Irq
);
476 HalpVectorToIrq(UCHAR Vector
)
478 return (Vector
- PRIMARY_VECTOR_BASE
);
483 HalpVectorToIrql(UCHAR Vector
)
485 return (PROFILE_LEVEL
- (Vector
- PRIMARY_VECTOR_BASE
));
488 /* IRQL MANAGEMENT ************************************************************/
495 KeGetCurrentIrql(VOID
)
497 /* Return the IRQL */
498 return KeGetPcr()->Irql
;
506 KeRaiseIrqlToDpcLevel(VOID
)
508 PKPCR Pcr
= KeGetPcr();
511 /* Save and update IRQL */
512 CurrentIrql
= Pcr
->Irql
;
513 Pcr
->Irql
= DISPATCH_LEVEL
;
516 /* Validate correct raise */
517 if (CurrentIrql
> DISPATCH_LEVEL
) KeBugCheck(IRQL_NOT_GREATER_OR_EQUAL
);
520 /* Return the previous value */
529 KeRaiseIrqlToSynchLevel(VOID
)
531 PKPCR Pcr
= KeGetPcr();
534 /* Save and update IRQL */
535 CurrentIrql
= Pcr
->Irql
;
536 Pcr
->Irql
= SYNCH_LEVEL
;
539 /* Validate correct raise */
540 if (CurrentIrql
> SYNCH_LEVEL
)
543 KeBugCheckEx(IRQL_NOT_GREATER_OR_EQUAL
,
551 /* Return the previous value */
560 KfRaiseIrql(IN KIRQL NewIrql
)
562 PKPCR Pcr
= KeGetPcr();
565 /* Read current IRQL */
566 CurrentIrql
= Pcr
->Irql
;
569 /* Validate correct raise */
570 if (CurrentIrql
> NewIrql
)
573 Pcr
->Irql
= PASSIVE_LEVEL
;
574 KeBugCheck(IRQL_NOT_GREATER_OR_EQUAL
);
581 /* Return old IRQL */
591 KfLowerIrql(IN KIRQL OldIrql
)
594 ULONG PendingIrql
, PendingIrqlMask
;
595 PKPCR Pcr
= KeGetPcr();
599 /* Validate correct lower */
600 if (OldIrql
> Pcr
->Irql
)
603 Pcr
->Irql
= HIGH_LEVEL
;
604 KeBugCheck(IRQL_NOT_LESS_OR_EQUAL
);
608 /* Save EFlags and disable interrupts */
609 EFlags
= __readeflags();
615 /* Check for pending software interrupts and compare with current IRQL */
616 PendingIrqlMask
= Pcr
->IRR
& FindHigherIrqlMask
[OldIrql
];
619 /* Check if pending IRQL affects hardware state */
620 BitScanReverse(&PendingIrql
, PendingIrqlMask
);
621 if (PendingIrql
> DISPATCH_LEVEL
)
623 /* Set new PIC mask */
624 Mask
.Both
= Pcr
->IDR
& 0xFFFF;
625 __outbyte(PIC1_DATA_PORT
, Mask
.Master
);
626 __outbyte(PIC2_DATA_PORT
, Mask
.Slave
);
629 Pcr
->IRR
^= (1 << PendingIrql
);
632 /* Now handle pending interrupt */
633 SWInterruptHandlerTable
[PendingIrql
]();
636 /* Restore interrupt state */
637 __writeeflags(EFlags
);
640 /* SOFTWARE INTERRUPTS ********************************************************/
647 HalRequestSoftwareInterrupt(IN KIRQL Irql
)
650 PKPCR Pcr
= KeGetPcr();
653 /* Save EFlags and disable interrupts */
654 EFlags
= __readeflags();
657 /* Mask out the requested bit */
658 Pcr
->IRR
|= (1 << Irql
);
660 /* Check for pending software interrupts and compare with current IRQL */
661 PendingIrql
= SWInterruptLookUpTable
[Pcr
->IRR
& 3];
662 if (PendingIrql
> Pcr
->Irql
) SWInterruptHandlerTable
[PendingIrql
]();
664 /* Restore interrupt state */
665 __writeeflags(EFlags
);
673 HalClearSoftwareInterrupt(IN KIRQL Irql
)
675 /* Mask out the requested bit */
676 KeGetPcr()->IRR
&= ~(1 << Irql
);
679 PHAL_SW_INTERRUPT_HANDLER_2ND_ENTRY
681 HalpEndSoftwareInterrupt2(IN KIRQL OldIrql
,
682 IN PKTRAP_FRAME TrapFrame
)
684 ULONG PendingIrql
, PendingIrqlMask
, PendingIrqMask
;
685 PKPCR Pcr
= KeGetPcr();
688 UNREFERENCED_PARAMETER(TrapFrame
);
693 /* Loop checking for pending interrupts */
696 /* Check for pending software interrupts and compare with current IRQL */
697 PendingIrqlMask
= Pcr
->IRR
& FindHigherIrqlMask
[OldIrql
];
698 if (!PendingIrqlMask
) return NULL
;
700 /* Check for in-service delayed interrupt */
701 if (Pcr
->IrrActive
& 0xFFFFFFF0) return NULL
;
703 /* Check if pending IRQL affects hardware state */
704 BitScanReverse(&PendingIrql
, PendingIrqlMask
);
705 if (PendingIrql
> DISPATCH_LEVEL
)
707 /* Set new PIC mask */
708 Mask
.Both
= Pcr
->IDR
& 0xFFFF;
709 __outbyte(PIC1_DATA_PORT
, Mask
.Master
);
710 __outbyte(PIC2_DATA_PORT
, Mask
.Slave
);
712 /* Set active bit otherwise, and clear it from IRR */
713 PendingIrqMask
= (1 << PendingIrql
);
714 Pcr
->IrrActive
|= PendingIrqMask
;
715 Pcr
->IRR
^= PendingIrqMask
;
717 /* Handle delayed hardware interrupt */
718 SWInterruptHandlerTable
[PendingIrql
]();
720 /* Handling complete */
721 Pcr
->IrrActive
^= PendingIrqMask
;
725 /* No need to loop checking for hardware interrupts */
726 return SWInterruptHandlerTable2
[PendingIrql
];
733 /* EDGE INTERRUPT DISMISSAL FUNCTIONS *****************************************/
737 _HalpDismissIrqGeneric(IN KIRQL Irql
,
744 PKPCR Pcr
= KeGetPcr();
746 /* First save current IRQL and compare it to the requested one */
747 CurrentIrql
= Pcr
->Irql
;
749 /* Check if this interrupt is really allowed to happen */
750 if (Irql
> CurrentIrql
)
752 /* Set the new IRQL and return the current one */
754 *OldIrql
= CurrentIrql
;
756 /* Prepare OCW2 for EOI */
758 Ocw2
.EoiMode
= SpecificEoi
;
760 /* Check which PIC needs the EOI */
763 /* Send the EOI for the IRQ */
764 __outbyte(PIC2_CONTROL_PORT
, Ocw2
.Bits
| ((Irq
- 8) & 0xFF));
766 /* Send the EOI for IRQ2 on the master because this was cascaded */
767 __outbyte(PIC1_CONTROL_PORT
, Ocw2
.Bits
| 2);
771 /* Send the EOI for the IRQ */
772 __outbyte(PIC1_CONTROL_PORT
, Ocw2
.Bits
| (Irq
&0xFF));
775 /* Enable interrupts and return success */
780 /* Update the IRR so that we deliver this interrupt when the IRQL is proper */
781 Pcr
->IRR
|= (1 << (Irq
+ 4));
783 /* Set new PIC mask to real IRQL level, since the optimization is lost now */
784 Mask
.Both
= (KiI8259MaskTable
[CurrentIrql
] | Pcr
->IDR
) & 0xFFFF;
785 __outbyte(PIC1_DATA_PORT
, Mask
.Master
);
786 __outbyte(PIC2_DATA_PORT
, Mask
.Slave
);
788 /* Now lie and say this was spurious */
794 HalpDismissIrqGeneric(IN KIRQL Irql
,
798 /* Run the inline code */
799 return _HalpDismissIrqGeneric(Irql
, Irq
, OldIrql
);
804 HalpDismissIrq15(IN KIRQL Irql
,
812 /* Request the ISR */
814 Ocw3
.Sbo
= 1; /* This encodes an OCW3 vs. an OCW2 */
815 Ocw3
.ReadRequest
= ReadIsr
;
816 __outbyte(PIC2_CONTROL_PORT
, Ocw3
.Bits
);
819 Isr
.Bits
= __inbyte(PIC2_CONTROL_PORT
);
821 /* Is IRQ15 really active (this is IR7) */
822 if (Isr
.Irq7
== FALSE
)
824 /* It isn't, so we have to EOI IRQ2 because this was cascaded */
826 Ocw2
.EoiMode
= SpecificEoi
;
827 __outbyte(PIC1_CONTROL_PORT
, Ocw2
.Bits
| 2);
829 /* And now fail since this was spurious */
833 /* Do normal interrupt dismiss */
834 return _HalpDismissIrqGeneric(Irql
, Irq
, OldIrql
);
840 HalpDismissIrq13(IN KIRQL Irql
,
844 /* Clear the FPU busy latch */
847 /* Do normal interrupt dismiss */
848 return _HalpDismissIrqGeneric(Irql
, Irq
, OldIrql
);
853 HalpDismissIrq07(IN KIRQL Irql
,
860 /* Request the ISR */
863 Ocw3
.ReadRequest
= ReadIsr
;
864 __outbyte(PIC1_CONTROL_PORT
, Ocw3
.Bits
);
867 Isr
.Bits
= __inbyte(PIC1_CONTROL_PORT
);
869 /* Is IRQ 7 really active? If it isn't, this is spurious so fail */
870 if (Isr
.Irq7
== FALSE
) return FALSE
;
872 /* Do normal interrupt dismiss */
873 return _HalpDismissIrqGeneric(Irql
, Irq
, OldIrql
);
876 /* LEVEL INTERRUPT DISMISSAL FUNCTIONS ****************************************/
880 _HalpDismissIrqLevel(IN KIRQL Irql
,
887 PKPCR Pcr
= KeGetPcr();
890 Mask
.Both
= (KiI8259MaskTable
[Irql
] | Pcr
->IDR
) & 0xFFFF;
891 __outbyte(PIC1_DATA_PORT
, Mask
.Master
);
892 __outbyte(PIC2_DATA_PORT
, Mask
.Slave
);
894 /* Update the IRR so that we clear this interrupt when the IRQL is proper */
895 Pcr
->IRR
|= (1 << (Irq
+ 4));
897 /* Save current IRQL */
898 CurrentIrql
= Pcr
->Irql
;
900 /* Prepare OCW2 for EOI */
902 Ocw2
.EoiMode
= SpecificEoi
;
904 /* Check which PIC needs the EOI */
907 /* Send the EOI for the IRQ */
908 __outbyte(PIC2_CONTROL_PORT
, Ocw2
.Bits
| ((Irq
- 8) & 0xFF));
910 /* Send the EOI for IRQ2 on the master because this was cascaded */
911 __outbyte(PIC1_CONTROL_PORT
, Ocw2
.Bits
| 2);
915 /* Send the EOI for the IRQ */
916 __outbyte(PIC1_CONTROL_PORT
, Ocw2
.Bits
| (Irq
& 0xFF));
919 /* Check if this interrupt should be allowed to happen */
920 if (Irql
> CurrentIrql
)
922 /* Set the new IRQL and return the current one */
924 *OldIrql
= CurrentIrql
;
926 /* Enable interrupts and return success */
931 /* Now lie and say this was spurious */
937 HalpDismissIrqLevel(IN KIRQL Irql
,
941 /* Run the inline code */
942 return _HalpDismissIrqLevel(Irql
, Irq
, OldIrql
);
947 HalpDismissIrq15Level(IN KIRQL Irql
,
955 /* Request the ISR */
957 Ocw3
.Sbo
= 1; /* This encodes an OCW3 vs. an OCW2 */
958 Ocw3
.ReadRequest
= ReadIsr
;
959 __outbyte(PIC2_CONTROL_PORT
, Ocw3
.Bits
);
962 Isr
.Bits
= __inbyte(PIC2_CONTROL_PORT
);
964 /* Is IRQ15 really active (this is IR7) */
965 if (Isr
.Irq7
== FALSE
)
967 /* It isn't, so we have to EOI IRQ2 because this was cascaded */
969 Ocw2
.EoiMode
= SpecificEoi
;
970 __outbyte(PIC1_CONTROL_PORT
, Ocw2
.Bits
| 2);
972 /* And now fail since this was spurious */
976 /* Do normal interrupt dismiss */
977 return _HalpDismissIrqLevel(Irql
, Irq
, OldIrql
);
982 HalpDismissIrq13Level(IN KIRQL Irql
,
986 /* Clear the FPU busy latch */
989 /* Do normal interrupt dismiss */
990 return _HalpDismissIrqLevel(Irql
, Irq
, OldIrql
);
995 HalpDismissIrq07Level(IN KIRQL Irql
,
1002 /* Request the ISR */
1005 Ocw3
.ReadRequest
= ReadIsr
;
1006 __outbyte(PIC1_CONTROL_PORT
, Ocw3
.Bits
);
1009 Isr
.Bits
= __inbyte(PIC1_CONTROL_PORT
);
1011 /* Is IRQ 7 really active? If it isn't, this is spurious so fail */
1012 if (Isr
.Irq7
== FALSE
) return FALSE
;
1014 /* Do normal interrupt dismiss */
1015 return _HalpDismissIrqLevel(Irql
, Irq
, OldIrql
);
1020 HalpHardwareInterruptLevel(VOID
)
1022 PKPCR Pcr
= KeGetPcr();
1023 ULONG PendingIrqlMask
, PendingIrql
;
1025 /* Check for pending software interrupts and compare with current IRQL */
1026 PendingIrqlMask
= Pcr
->IRR
& FindHigherIrqlMask
[Pcr
->Irql
];
1027 if (PendingIrqlMask
)
1029 /* Check for in-service delayed interrupt */
1030 if (Pcr
->IrrActive
& 0xFFFFFFF0) return;
1032 /* Check if pending IRQL affects hardware state */
1033 BitScanReverse(&PendingIrql
, PendingIrqlMask
);
1036 Pcr
->IRR
^= (1 << PendingIrql
);
1038 /* Now handle pending interrupt */
1039 SWInterruptHandlerTable
[PendingIrql
]();
1043 /* SYSTEM INTERRUPTS **********************************************************/
1050 HalEnableSystemInterrupt(IN ULONG Vector
,
1052 IN KINTERRUPT_MODE InterruptMode
)
1055 PKPCR Pcr
= KeGetPcr();
1058 /* Validate the IRQ */
1059 Irq
= Vector
- PRIMARY_VECTOR_BASE
;
1060 if (Irq
>= CLOCK2_LEVEL
) return FALSE
;
1062 /* Check for level interrupt */
1063 if (InterruptMode
== LevelSensitive
)
1065 /* Switch handler to level */
1066 SWInterruptHandlerTable
[Irq
+ 4] = HalpHardwareInterruptLevel
;
1068 /* Switch dismiss to level */
1069 HalpSpecialDismissTable
[Irq
] = HalpSpecialDismissLevelTable
[Irq
];
1072 /* Disable interrupts */
1075 /* Update software IDR */
1076 Pcr
->IDR
&= ~(1 << Irq
);
1078 /* Set new PIC mask */
1079 PicMask
.Both
= (KiI8259MaskTable
[Pcr
->Irql
] | Pcr
->IDR
) & 0xFFFF;
1080 __outbyte(PIC1_DATA_PORT
, PicMask
.Master
);
1081 __outbyte(PIC2_DATA_PORT
, PicMask
.Slave
);
1083 /* Enable interrupts and exit */
1093 HalDisableSystemInterrupt(IN ULONG Vector
,
1099 /* Compute new combined IRQ mask */
1100 IrqMask
= 1 << (Vector
- PRIMARY_VECTOR_BASE
);
1102 /* Disable interrupts */
1105 /* Update software IDR */
1106 KeGetPcr()->IDR
|= IrqMask
;
1108 /* Read current interrupt mask */
1109 PicMask
.Master
= __inbyte(PIC1_DATA_PORT
);
1110 PicMask
.Slave
= __inbyte(PIC2_DATA_PORT
);
1112 /* Add the new disabled interrupt */
1113 PicMask
.Both
|= IrqMask
;
1115 /* Write new interrupt mask */
1116 __outbyte(PIC1_DATA_PORT
, PicMask
.Master
);
1117 __outbyte(PIC2_DATA_PORT
, PicMask
.Slave
);
1119 /* Bring interrupts back */
1128 HalBeginSystemInterrupt(IN KIRQL Irql
,
1134 /* Get the IRQ and call the proper routine to handle it */
1135 Irq
= Vector
- PRIMARY_VECTOR_BASE
;
1136 return HalpSpecialDismissTable
[Irq
](Irql
, Irq
, OldIrql
);
1144 HalEndSystemInterrupt(IN KIRQL OldIrql
,
1145 IN PKTRAP_FRAME TrapFrame
)
1147 ULONG PendingIrql
, PendingIrqlMask
, PendingIrqMask
;
1148 PKPCR Pcr
= KeGetPcr();
1152 Pcr
->Irql
= OldIrql
;
1154 /* Check for pending software interrupts and compare with current IRQL */
1155 PendingIrqlMask
= Pcr
->IRR
& FindHigherIrqlMask
[OldIrql
];
1156 if (PendingIrqlMask
)
1158 /* Check for in-service delayed interrupt */
1159 if (Pcr
->IrrActive
& 0xFFFFFFF0) return;
1161 /* Loop checking for pending interrupts */
1164 /* Check if pending IRQL affects hardware state */
1165 BitScanReverse(&PendingIrql
, PendingIrqlMask
);
1166 if (PendingIrql
> DISPATCH_LEVEL
)
1168 /* Set new PIC mask */
1169 Mask
.Both
= Pcr
->IDR
& 0xFFFF;
1170 __outbyte(PIC1_DATA_PORT
, Mask
.Master
);
1171 __outbyte(PIC2_DATA_PORT
, Mask
.Slave
);
1173 /* Now check if this specific interrupt is already in-service */
1174 PendingIrqMask
= (1 << PendingIrql
);
1175 if (Pcr
->IrrActive
& PendingIrqMask
) return;
1177 /* Set active bit otherwise, and clear it from IRR */
1178 Pcr
->IrrActive
|= PendingIrqMask
;
1179 Pcr
->IRR
^= PendingIrqMask
;
1181 /* Handle delayed hardware interrupt */
1182 SWInterruptHandlerTable
[PendingIrql
]();
1184 /* Handling complete */
1185 Pcr
->IrrActive
^= PendingIrqMask
;
1187 /* Check if there's still interrupts pending */
1188 PendingIrqlMask
= Pcr
->IRR
& FindHigherIrqlMask
[Pcr
->Irql
];
1189 if (!PendingIrqlMask
) break;
1193 /* Now handle pending software interrupt */
1194 SWInterruptHandlerTable2
[PendingIrql
](TrapFrame
);
1201 /* SOFTWARE INTERRUPT TRAPS ***************************************************/
1206 _HalpApcInterruptHandler(IN PKTRAP_FRAME TrapFrame
)
1209 PKPCR Pcr
= KeGetPcr();
1211 /* Save the current IRQL and update it */
1212 CurrentIrql
= Pcr
->Irql
;
1213 Pcr
->Irql
= APC_LEVEL
;
1215 /* Remove DPC from IRR */
1216 Pcr
->IRR
&= ~(1 << APC_LEVEL
);
1218 /* Enable interrupts and call the kernel's APC interrupt handler */
1220 KiDeliverApc(((KiUserTrap(TrapFrame
)) || (TrapFrame
->EFlags
& EFLAGS_V86_MASK
)) ?
1221 UserMode
: KernelMode
,
1225 /* Disable interrupts and end the interrupt */
1227 HalpEndSoftwareInterrupt(CurrentIrql
, TrapFrame
);
1229 /* Exit the interrupt */
1230 KiEoiHelper(TrapFrame
);
1236 HalpApcInterrupt2ndEntry(IN PKTRAP_FRAME TrapFrame
)
1239 _HalpApcInterruptHandler(TrapFrame
);
1245 HalpApcInterruptHandler(IN PKTRAP_FRAME TrapFrame
)
1247 /* Set up a fake INT Stack */
1248 TrapFrame
->EFlags
= __readeflags();
1249 TrapFrame
->SegCs
= KGDT_R0_CODE
;
1250 TrapFrame
->Eip
= TrapFrame
->Eax
;
1252 /* Build the trap frame */
1253 KiEnterInterruptTrap(TrapFrame
);
1256 _HalpApcInterruptHandler(TrapFrame
);
1261 _HalpDispatchInterruptHandler(VOID
)
1264 PKPCR Pcr
= KeGetPcr();
1266 /* Save the current IRQL and update it */
1267 CurrentIrql
= Pcr
->Irql
;
1268 Pcr
->Irql
= DISPATCH_LEVEL
;
1270 /* Remove DPC from IRR */
1271 Pcr
->IRR
&= ~(1 << DISPATCH_LEVEL
);
1273 /* Enable interrupts and call the kernel's DPC interrupt handler */
1275 KiDispatchInterrupt();
1285 HalpDispatchInterrupt2ndEntry(IN PKTRAP_FRAME TrapFrame
)
1290 CurrentIrql
= _HalpDispatchInterruptHandler();
1292 /* End the interrupt */
1293 HalpEndSoftwareInterrupt(CurrentIrql
, TrapFrame
);
1295 /* Exit the interrupt */
1296 KiEoiHelper(TrapFrame
);
1301 HalpDispatchInterrupt2(VOID
)
1303 ULONG PendingIrqlMask
, PendingIrql
;
1306 PKPCR Pcr
= KeGetPcr();
1309 OldIrql
= _HalpDispatchInterruptHandler();
1312 Pcr
->Irql
= OldIrql
;
1314 /* Check for pending software interrupts and compare with current IRQL */
1315 PendingIrqlMask
= Pcr
->IRR
& FindHigherIrqlMask
[OldIrql
];
1316 if (PendingIrqlMask
)
1318 /* Check if pending IRQL affects hardware state */
1319 BitScanReverse(&PendingIrql
, PendingIrqlMask
);
1320 if (PendingIrql
> DISPATCH_LEVEL
)
1322 /* Set new PIC mask */
1323 Mask
.Both
= Pcr
->IDR
& 0xFFFF;
1324 __outbyte(PIC1_DATA_PORT
, Mask
.Master
);
1325 __outbyte(PIC2_DATA_PORT
, Mask
.Slave
);
1328 Pcr
->IRR
^= (1 << PendingIrql
);
1331 /* Now handle pending interrupt */
1332 SWInterruptHandlerTable
[PendingIrql
]();
1340 KeGetCurrentIrql(VOID
)
1342 return PASSIVE_LEVEL
;