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__) && \
103 (__GNUC__ * 100 + __GNUC_MINOR__ >= 404)
105 * It Device IRQLs only start at 4 or higher, so these are just software
106 * IRQLs that don't really change anything on the hardware
108 0b00000000000000000000000000000000, /* IRQL 0 */
109 0b00000000000000000000000000000000, /* IRQL 1 */
110 0b00000000000000000000000000000000, /* IRQL 2 */
111 0b00000000000000000000000000000000, /* IRQL 3 */
114 * These next IRQLs are actually useless from the PIC perspective, because
115 * with only 2 PICs, the mask you can send them is only 8 bits each, for 16
116 * bits total, so these IRQLs are masking off a phantom PIC.
118 0b11111111100000000000000000000000, /* IRQL 4 */
119 0b11111111110000000000000000000000, /* IRQL 5 */
120 0b11111111111000000000000000000000, /* IRQL 6 */
121 0b11111111111100000000000000000000, /* IRQL 7 */
122 0b11111111111110000000000000000000, /* IRQL 8 */
123 0b11111111111111000000000000000000, /* IRQL 9 */
124 0b11111111111111100000000000000000, /* IRQL 10 */
125 0b11111111111111110000000000000000, /* IRQL 11 */
128 * Okay, now we're finally starting to mask off IRQs on the slave PIC, from
129 * IRQ15 to IRQ8. This means the higher-level IRQs get less priority in the
132 0b11111111111111111000000000000000, /* IRQL 12 */
133 0b11111111111111111100000000000000, /* IRQL 13 */
134 0b11111111111111111110000000000000, /* IRQL 14 */
135 0b11111111111111111111000000000000, /* IRQL 15 */
136 0b11111111111111111111100000000000, /* IRQL 16 */
137 0b11111111111111111111110000000000, /* IRQL 17 */
138 0b11111111111111111111111000000000, /* IRQL 18 */
139 0b11111111111111111111111000000000, /* IRQL 19 */
142 * Now we mask off the IRQs on the master. Notice the 0 "droplet"? You might
143 * have also seen that IRQL 18 and 19 are essentially equal as far as the
144 * PIC is concerned. That bit is actually IRQ8, which happens to be the RTC.
145 * The RTC will keep firing as long as we don't reach PROFILE_LEVEL which
146 * actually kills it. The RTC clock (unlike the system clock) is used by the
147 * profiling APIs in the HAL, so that explains the logic.
149 0b11111111111111111111111010000000, /* IRQL 20 */
150 0b11111111111111111111111011000000, /* IRQL 21 */
151 0b11111111111111111111111011100000, /* IRQL 22 */
152 0b11111111111111111111111011110000, /* IRQL 23 */
153 0b11111111111111111111111011111000, /* IRQL 24 */
154 0b11111111111111111111111011111000, /* IRQL 25 */
155 0b11111111111111111111111011111010, /* IRQL 26 */
156 0b11111111111111111111111111111010, /* IRQL 27 */
159 * IRQL 24 and 25 are actually identical, so IRQL 28 is actually the last
160 * IRQL to modify a bit on the master PIC. It happens to modify the very
161 * last of the IRQs, IRQ0, which corresponds to the system clock interval
162 * timer that keeps track of time (the Windows heartbeat). We only want to
163 * turn this off at a high-enough IRQL, which is why IRQLs 24 and 25 are the
164 * same to give this guy a chance to come up higher. Note that IRQL 28 is
165 * called CLOCK2_LEVEL, which explains the usage we just explained.
167 0b11111111111111111111111111111011, /* IRQL 28 */
170 * We have finished off with the PIC so there's nothing left to mask at the
171 * level of these IRQLs, making them only logical IRQLs on x86 machines.
172 * Note that we have another 0 "droplet" you might've caught since IRQL 26.
173 * In this case, it's the 2nd bit that never gets turned off, which is IRQ2,
174 * the cascade IRQ that we use to bridge the slave PIC with the master PIC.
175 * We never want to turn it off, so no matter the IRQL, it will be set to 0.
177 0b11111111111111111111111111111011, /* IRQL 29 */
178 0b11111111111111111111111111111011, /* IRQL 30 */
179 0b11111111111111111111111111111011 /* IRQL 31 */
185 0xFF800000, /* IRQL 4 */
186 0xFFC00000, /* IRQL 5 */
187 0xFFE00000, /* IRQL 6 */
188 0xFFF00000, /* IRQL 7 */
189 0xFFF80000, /* IRQL 8 */
190 0xFFFC0000, /* IRQL 9 */
191 0xFFFE0000, /* IRQL 10 */
192 0xFFFF0000, /* IRQL 11 */
193 0xFFFF8000, /* IRQL 12 */
194 0xFFFFC000, /* IRQL 13 */
195 0xFFFFE000, /* IRQL 14 */
196 0xFFFFF000, /* IRQL 15 */
197 0xFFFFF800, /* IRQL 16 */
198 0xFFFFFC00, /* IRQL 17 */
199 0xFFFFFE00, /* IRQL 18 */
200 0xFFFFFE00, /* IRQL 19 */
201 0xFFFFFE80, /* IRQL 20 */
202 0xFFFFFEC0, /* IRQL 21 */
203 0xFFFFFEE0, /* IRQL 22 */
204 0xFFFFFEF0, /* IRQL 23 */
205 0xFFFFFEF8, /* IRQL 24 */
206 0xFFFFFEF8, /* IRQL 25 */
207 0xFFFFFEFA, /* IRQL 26 */
208 0xFFFFFFFA, /* IRQL 27 */
209 0xFFFFFFFB, /* IRQL 28 */
210 0xFFFFFFFB, /* IRQL 29 */
211 0xFFFFFFFB, /* IRQL 30 */
212 0xFFFFFFFB /* IRQL 31 */
216 /* This table indicates which IRQs, if pending, can preempt a given IRQL level */
217 ULONG FindHigherIrqlMask
[32] =
219 #if defined(__GNUC__) && \
220 (__GNUC__ * 100 + __GNUC_MINOR__ >= 404)
222 * Software IRQLs, at these levels all hardware interrupts can preempt.
223 * Each higher IRQL simply enables which software IRQL can preempt the
226 0b11111111111111111111111111111110, /* IRQL 0 */
227 0b11111111111111111111111111111100, /* IRQL 1 */
228 0b11111111111111111111111111111000, /* IRQL 2 */
231 * IRQL3 means only hardware IRQLs can now preempt. These last 4 zeros will
232 * then continue throughout the rest of the list, trickling down.
234 0b11111111111111111111111111110000, /* IRQL 3 */
237 * Just like in the previous list, these masks don't really mean anything
238 * since we've only got two PICs with 16 possible IRQs total
240 0b00000111111111111111111111110000, /* IRQL 4 */
241 0b00000011111111111111111111110000, /* IRQL 5 */
242 0b00000001111111111111111111110000, /* IRQL 6 */
243 0b00000000111111111111111111110000, /* IRQL 7 */
244 0b00000000011111111111111111110000, /* IRQL 8 */
245 0b00000000001111111111111111110000, /* IRQL 9 */
246 0b00000000000111111111111111110000, /* IRQL 10 */
249 * Now we start progressivly limiting which slave PIC interrupts have the
250 * right to preempt us at each level.
252 0b00000000000011111111111111110000, /* IRQL 11 */
253 0b00000000000001111111111111110000, /* IRQL 12 */
254 0b00000000000000111111111111110000, /* IRQL 13 */
255 0b00000000000000011111111111110000, /* IRQL 14 */
256 0b00000000000000001111111111110000, /* IRQL 15 */
257 0b00000000000000000111111111110000, /* IRQL 16 */
258 0b00000000000000000011111111110000, /* IRQL 17 */
259 0b00000000000000000001111111110000, /* IRQL 18 */
260 0b00000000000000000001111111110000, /* IRQL 19 */
263 * Also recall from the earlier table that IRQL 18/19 are treated the same
264 * in order to spread the masks better thoughout the 32 IRQLs and to reflect
265 * the fact that some bits will always stay on until much higher IRQLs since
266 * they are system-critical. One such example is the 1 bit that you start to
267 * see trickling down here. This is IRQ8, the RTC timer used for profiling,
268 * so it will always preempt until we reach PROFILE_LEVEL.
270 0b00000000000000000001011111110000, /* IRQL 20 */
271 0b00000000000000000001001111110000, /* IRQL 21 */
272 0b00000000000000000001000111110000, /* IRQL 22 */
273 0b00000000000000000001000011110000, /* IRQL 23 */
274 0b00000000000000000001000001110000, /* IRQL 24 */
275 0b00000000000000000001000000110000, /* IRQL 25 */
276 0b00000000000000000001000000010000, /* IRQL 26 */
278 /* At this point, only the clock (IRQ0) can still preempt... */
279 0b00000000000000000000000000010000, /* IRQL 27 */
281 /* And any higher than that there's no relation with hardware PICs anymore */
282 0b00000000000000000000000000000000, /* IRQL 28 */
283 0b00000000000000000000000000000000, /* IRQL 29 */
284 0b00000000000000000000000000000000, /* IRQL 30 */
285 0b00000000000000000000000000000000 /* IRQL 31 */
287 0xFFFFFFFE, /* IRQL 0 */
288 0xFFFFFFFC, /* IRQL 1 */
289 0xFFFFFFF8, /* IRQL 2 */
290 0xFFFFFFF0, /* IRQL 3 */
291 0x7FFFFF0, /* IRQL 4 */
292 0x3FFFFF0, /* IRQL 5 */
293 0x1FFFFF0, /* IRQL 6 */
294 0x0FFFFF0, /* IRQL 7 */
295 0x7FFFF0, /* IRQL 8 */
296 0x3FFFF0, /* IRQL 9 */
297 0x1FFFF0, /* IRQL 10 */
298 0x0FFFF0, /* IRQL 11 */
299 0x7FFF0, /* IRQL 12 */
300 0x3FFF0, /* IRQL 13 */
301 0x1FFF0, /* IRQL 14 */
302 0x0FFF0, /* IRQL 15 */
303 0x7FF0, /* IRQL 16 */
304 0x3FF0, /* IRQL 17 */
305 0x1FF0, /* IRQL 18 */
306 0x1FF0, /* IRQL 19 */
307 0x17F0, /* IRQL 20 */
308 0x13F0, /* IRQL 21 */
309 0x11F0, /* IRQL 22 */
310 0x10F0, /* IRQL 23 */
311 0x1070, /* IRQL 24 */
312 0x1030, /* IRQL 25 */
313 0x1010, /* IRQL 26 */
322 /* Denotes minimum required IRQL before we can process pending SW interrupts */
323 KIRQL SWInterruptLookUpTable
[8] =
325 PASSIVE_LEVEL
, /* IRR 0 */
326 PASSIVE_LEVEL
, /* IRR 1 */
327 APC_LEVEL
, /* IRR 2 */
328 APC_LEVEL
, /* IRR 3 */
329 DISPATCH_LEVEL
, /* IRR 4 */
330 DISPATCH_LEVEL
, /* IRR 5 */
331 DISPATCH_LEVEL
, /* IRR 6 */
332 DISPATCH_LEVEL
/* IRR 7 */
335 #if defined(__GNUC__)
337 #define HalpDelayedHardwareInterrupt(x) \
338 VOID __cdecl HalpHardwareInterrupt##x(VOID); \
341 HalpHardwareInterrupt##x(VOID) \
343 asm volatile ("int $%c0\n"::"i"(PRIMARY_VECTOR_BASE + x)); \
346 #elif defined(_MSC_VER)
348 #define HalpDelayedHardwareInterrupt(x) \
349 VOID __cdecl HalpHardwareInterrupt##x(VOID); \
352 HalpHardwareInterrupt##x(VOID) \
356 int PRIMARY_VECTOR_BASE + x \
361 #error Unsupported compiler
364 /* Pending/delayed hardware interrupt handlers */
365 HalpDelayedHardwareInterrupt(0);
366 HalpDelayedHardwareInterrupt(1);
367 HalpDelayedHardwareInterrupt(2);
368 HalpDelayedHardwareInterrupt(3);
369 HalpDelayedHardwareInterrupt(4);
370 HalpDelayedHardwareInterrupt(5);
371 HalpDelayedHardwareInterrupt(6);
372 HalpDelayedHardwareInterrupt(7);
373 HalpDelayedHardwareInterrupt(8);
374 HalpDelayedHardwareInterrupt(9);
375 HalpDelayedHardwareInterrupt(10);
376 HalpDelayedHardwareInterrupt(11);
377 HalpDelayedHardwareInterrupt(12);
378 HalpDelayedHardwareInterrupt(13);
379 HalpDelayedHardwareInterrupt(14);
380 HalpDelayedHardwareInterrupt(15);
382 /* Handlers for pending interrupts */
383 PHAL_SW_INTERRUPT_HANDLER SWInterruptHandlerTable
[20] =
385 (PHAL_SW_INTERRUPT_HANDLER
)KiUnexpectedInterrupt
,
387 HalpDispatchInterrupt2
,
388 (PHAL_SW_INTERRUPT_HANDLER
)KiUnexpectedInterrupt
,
389 HalpHardwareInterrupt0
,
390 HalpHardwareInterrupt1
,
391 HalpHardwareInterrupt2
,
392 HalpHardwareInterrupt3
,
393 HalpHardwareInterrupt4
,
394 HalpHardwareInterrupt5
,
395 HalpHardwareInterrupt6
,
396 HalpHardwareInterrupt7
,
397 HalpHardwareInterrupt8
,
398 HalpHardwareInterrupt9
,
399 HalpHardwareInterrupt10
,
400 HalpHardwareInterrupt11
,
401 HalpHardwareInterrupt12
,
402 HalpHardwareInterrupt13
,
403 HalpHardwareInterrupt14
,
404 HalpHardwareInterrupt15
407 /* Handlers for pending software interrupts when we already have a trap frame*/
408 PHAL_SW_INTERRUPT_HANDLER_2ND_ENTRY SWInterruptHandlerTable2
[3] =
410 (PHAL_SW_INTERRUPT_HANDLER_2ND_ENTRY
)KiUnexpectedInterrupt
,
411 HalpApcInterrupt2ndEntry
,
412 HalpDispatchInterrupt2ndEntry
417 /* FUNCTIONS ******************************************************************/
421 HalpInitializePICs(IN BOOLEAN EnableInterrupts
)
431 /* Save EFlags and disable interrupts */
432 EFlags
= __readeflags();
435 /* Initialize ICW1 for master, interval 8, edge-triggered mode with ICW4 */
436 Icw1
.NeedIcw4
= TRUE
;
437 Icw1
.InterruptMode
= EdgeTriggered
;
438 Icw1
.OperatingMode
= Cascade
;
439 Icw1
.Interval
= Interval8
;
441 Icw1
.InterruptVectorAddress
= 0; /* This is only used in MCS80/85 mode */
442 __outbyte(PIC1_CONTROL_PORT
, Icw1
.Bits
);
444 /* Set interrupt vector base */
445 Icw2
.Bits
= PRIMARY_VECTOR_BASE
;
446 __outbyte(PIC1_DATA_PORT
, Icw2
.Bits
);
448 /* Connect slave to IRQ 2 */
450 Icw3
.SlaveIrq2
= TRUE
;
451 __outbyte(PIC1_DATA_PORT
, Icw3
.Bits
);
453 /* Enable 8086 mode, non-automatic EOI, non-buffered mode, non special fully nested mode */
455 Icw4
.SystemMode
= New8086Mode
;
456 Icw4
.EoiMode
= NormalEoi
;
457 Icw4
.BufferedMode
= NonBuffered
;
458 Icw4
.SpecialFullyNestedMode
= FALSE
;
459 __outbyte(PIC1_DATA_PORT
, Icw4
.Bits
);
461 /* Mask all interrupts */
462 __outbyte(PIC1_DATA_PORT
, 0xFF);
464 /* Initialize ICW1 for master, interval 8, edge-triggered mode with ICW4 */
465 Icw1
.NeedIcw4
= TRUE
;
466 Icw1
.InterruptMode
= EdgeTriggered
;
467 Icw1
.OperatingMode
= Cascade
;
468 Icw1
.Interval
= Interval8
;
470 Icw1
.InterruptVectorAddress
= 0; /* This is only used in MCS80/85 mode */
471 __outbyte(PIC2_CONTROL_PORT
, Icw1
.Bits
);
473 /* Set interrupt vector base */
474 Icw2
.Bits
= PRIMARY_VECTOR_BASE
+ 8;
475 __outbyte(PIC2_DATA_PORT
, Icw2
.Bits
);
480 __outbyte(PIC2_DATA_PORT
, Icw3
.Bits
);
482 /* Enable 8086 mode, non-automatic EOI, non-buffered mode, non special fully nested mode */
484 Icw4
.SystemMode
= New8086Mode
;
485 Icw4
.EoiMode
= NormalEoi
;
486 Icw4
.BufferedMode
= NonBuffered
;
487 Icw4
.SpecialFullyNestedMode
= FALSE
;
488 __outbyte(PIC2_DATA_PORT
, Icw4
.Bits
);
490 /* Mask all interrupts */
491 __outbyte(PIC2_DATA_PORT
, 0xFF);
493 /* Read EISA Edge/Level Register for master and slave */
494 Elcr
.Bits
= (__inbyte(EISA_ELCR_SLAVE
) << 8) | __inbyte(EISA_ELCR_MASTER
);
496 /* IRQs 0, 1, 2, 8, and 13 are system-reserved and must be edge */
497 if (!(Elcr
.Master
.Irq0Level
) && !(Elcr
.Master
.Irq1Level
) && !(Elcr
.Master
.Irq2Level
) &&
498 !(Elcr
.Slave
.Irq8Level
) && !(Elcr
.Slave
.Irq13Level
))
500 /* ELCR is as it's supposed to be, save it */
501 HalpEisaELCR
= Elcr
.Bits
;
503 /* Scan for level interrupts */
504 for (i
= 1, j
= 0; j
< 16; i
<<= 1, j
++)
506 if (HalpEisaELCR
& i
)
508 /* Switch handler to level */
509 SWInterruptHandlerTable
[j
+ 4] = HalpHardwareInterruptLevel
;
511 /* Switch dismiss to level */
512 HalpSpecialDismissTable
[j
] = HalpSpecialDismissLevelTable
[j
];
518 HalpRegisterVector(IDT_INTERNAL
,
519 PRIMARY_VECTOR_BASE
+ 2,
520 PRIMARY_VECTOR_BASE
+ 2,
523 /* Restore interrupt state */
524 if (EnableInterrupts
) EFlags
|= EFLAGS_INTERRUPT_MASK
;
525 __writeeflags(EFlags
);
530 HalpIrqToVector(UCHAR Irq
)
532 return (PRIMARY_VECTOR_BASE
+ Irq
);
537 HalpVectorToIrq(UCHAR Vector
)
539 return (Vector
- PRIMARY_VECTOR_BASE
);
544 HalpVectorToIrql(UCHAR Vector
)
546 return (PROFILE_LEVEL
- (Vector
- PRIMARY_VECTOR_BASE
));
549 /* IRQL MANAGEMENT ************************************************************/
556 KeGetCurrentIrql(VOID
)
558 /* Return the IRQL */
559 return KeGetPcr()->Irql
;
567 KeRaiseIrqlToDpcLevel(VOID
)
569 PKPCR Pcr
= KeGetPcr();
572 /* Save and update IRQL */
573 CurrentIrql
= Pcr
->Irql
;
574 Pcr
->Irql
= DISPATCH_LEVEL
;
577 /* Validate correct raise */
578 if (CurrentIrql
> DISPATCH_LEVEL
) KeBugCheck(IRQL_NOT_GREATER_OR_EQUAL
);
581 /* Return the previous value */
590 KeRaiseIrqlToSynchLevel(VOID
)
592 PKPCR Pcr
= KeGetPcr();
595 /* Save and update IRQL */
596 CurrentIrql
= Pcr
->Irql
;
597 Pcr
->Irql
= SYNCH_LEVEL
;
600 /* Validate correct raise */
601 if (CurrentIrql
> SYNCH_LEVEL
)
604 KeBugCheckEx(IRQL_NOT_GREATER_OR_EQUAL
,
612 /* Return the previous value */
621 KfRaiseIrql(IN KIRQL NewIrql
)
623 PKPCR Pcr
= KeGetPcr();
626 /* Read current IRQL */
627 CurrentIrql
= Pcr
->Irql
;
630 /* Validate correct raise */
631 if (CurrentIrql
> NewIrql
)
634 Pcr
->Irql
= PASSIVE_LEVEL
;
635 KeBugCheck(IRQL_NOT_GREATER_OR_EQUAL
);
642 /* Return old IRQL */
652 KfLowerIrql(IN KIRQL OldIrql
)
655 ULONG PendingIrql
, PendingIrqlMask
;
656 PKPCR Pcr
= KeGetPcr();
660 /* Validate correct lower */
661 if (OldIrql
> Pcr
->Irql
)
664 Pcr
->Irql
= HIGH_LEVEL
;
665 KeBugCheck(IRQL_NOT_LESS_OR_EQUAL
);
669 /* Save EFlags and disable interrupts */
670 EFlags
= __readeflags();
676 /* Check for pending software interrupts and compare with current IRQL */
677 PendingIrqlMask
= Pcr
->IRR
& FindHigherIrqlMask
[OldIrql
];
680 /* Check if pending IRQL affects hardware state */
681 BitScanReverse(&PendingIrql
, PendingIrqlMask
);
682 if (PendingIrql
> DISPATCH_LEVEL
)
684 /* Set new PIC mask */
685 Mask
.Both
= Pcr
->IDR
& 0xFFFF;
686 __outbyte(PIC1_DATA_PORT
, Mask
.Master
);
687 __outbyte(PIC2_DATA_PORT
, Mask
.Slave
);
690 Pcr
->IRR
^= (1 << PendingIrql
);
693 /* Now handle pending interrupt */
694 SWInterruptHandlerTable
[PendingIrql
]();
697 /* Restore interrupt state */
698 __writeeflags(EFlags
);
701 /* SOFTWARE INTERRUPTS ********************************************************/
708 HalRequestSoftwareInterrupt(IN KIRQL Irql
)
711 PKPCR Pcr
= KeGetPcr();
714 /* Save EFlags and disable interrupts */
715 EFlags
= __readeflags();
718 /* Mask out the requested bit */
719 Pcr
->IRR
|= (1 << Irql
);
721 /* Check for pending software interrupts and compare with current IRQL */
722 PendingIrql
= SWInterruptLookUpTable
[Pcr
->IRR
& 3];
723 if (PendingIrql
> Pcr
->Irql
) SWInterruptHandlerTable
[PendingIrql
]();
725 /* Restore interrupt state */
726 __writeeflags(EFlags
);
734 HalClearSoftwareInterrupt(IN KIRQL Irql
)
736 /* Mask out the requested bit */
737 KeGetPcr()->IRR
&= ~(1 << Irql
);
740 PHAL_SW_INTERRUPT_HANDLER_2ND_ENTRY
742 HalpEndSoftwareInterrupt2(IN KIRQL OldIrql
,
743 IN PKTRAP_FRAME TrapFrame
)
745 ULONG PendingIrql
, PendingIrqlMask
, PendingIrqMask
;
746 PKPCR Pcr
= KeGetPcr();
749 UNREFERENCED_PARAMETER(TrapFrame
);
754 /* Loop checking for pending interrupts */
757 /* Check for pending software interrupts and compare with current IRQL */
758 PendingIrqlMask
= Pcr
->IRR
& FindHigherIrqlMask
[OldIrql
];
759 if (!PendingIrqlMask
) return NULL
;
761 /* Check for in-service delayed interrupt */
762 if (Pcr
->IrrActive
& 0xFFFFFFF0) return NULL
;
764 /* Check if pending IRQL affects hardware state */
765 BitScanReverse(&PendingIrql
, PendingIrqlMask
);
766 if (PendingIrql
> DISPATCH_LEVEL
)
768 /* Set new PIC mask */
769 Mask
.Both
= Pcr
->IDR
& 0xFFFF;
770 __outbyte(PIC1_DATA_PORT
, Mask
.Master
);
771 __outbyte(PIC2_DATA_PORT
, Mask
.Slave
);
773 /* Set active bit otherwise, and clear it from IRR */
774 PendingIrqMask
= (1 << PendingIrql
);
775 Pcr
->IrrActive
|= PendingIrqMask
;
776 Pcr
->IRR
^= PendingIrqMask
;
778 /* Handle delayed hardware interrupt */
779 SWInterruptHandlerTable
[PendingIrql
]();
781 /* Handling complete */
782 Pcr
->IrrActive
^= PendingIrqMask
;
786 /* No need to loop checking for hardware interrupts */
787 return SWInterruptHandlerTable2
[PendingIrql
];
794 /* EDGE INTERRUPT DISMISSAL FUNCTIONS *****************************************/
798 _HalpDismissIrqGeneric(IN KIRQL Irql
,
805 PKPCR Pcr
= KeGetPcr();
807 /* First save current IRQL and compare it to the requested one */
808 CurrentIrql
= Pcr
->Irql
;
810 /* Check if this interrupt is really allowed to happen */
811 if (Irql
> CurrentIrql
)
813 /* Set the new IRQL and return the current one */
815 *OldIrql
= CurrentIrql
;
817 /* Prepare OCW2 for EOI */
819 Ocw2
.EoiMode
= SpecificEoi
;
821 /* Check which PIC needs the EOI */
824 /* Send the EOI for the IRQ */
825 __outbyte(PIC2_CONTROL_PORT
, Ocw2
.Bits
| ((Irq
- 8) & 0xFF));
827 /* Send the EOI for IRQ2 on the master because this was cascaded */
828 __outbyte(PIC1_CONTROL_PORT
, Ocw2
.Bits
| 2);
832 /* Send the EOI for the IRQ */
833 __outbyte(PIC1_CONTROL_PORT
, Ocw2
.Bits
| (Irq
&0xFF));
836 /* Enable interrupts and return success */
841 /* Update the IRR so that we deliver this interrupt when the IRQL is proper */
842 Pcr
->IRR
|= (1 << (Irq
+ 4));
844 /* Set new PIC mask to real IRQL level, since the optimization is lost now */
845 Mask
.Both
= (KiI8259MaskTable
[CurrentIrql
] | Pcr
->IDR
) & 0xFFFF;
846 __outbyte(PIC1_DATA_PORT
, Mask
.Master
);
847 __outbyte(PIC2_DATA_PORT
, Mask
.Slave
);
849 /* Now lie and say this was spurious */
855 HalpDismissIrqGeneric(IN KIRQL Irql
,
859 /* Run the inline code */
860 return _HalpDismissIrqGeneric(Irql
, Irq
, OldIrql
);
865 HalpDismissIrq15(IN KIRQL Irql
,
873 /* Request the ISR */
875 Ocw3
.Sbo
= 1; /* This encodes an OCW3 vs. an OCW2 */
876 Ocw3
.ReadRequest
= ReadIsr
;
877 __outbyte(PIC2_CONTROL_PORT
, Ocw3
.Bits
);
880 Isr
.Bits
= __inbyte(PIC2_CONTROL_PORT
);
882 /* Is IRQ15 really active (this is IR7) */
883 if (Isr
.Irq7
== FALSE
)
885 /* It isn't, so we have to EOI IRQ2 because this was cascaded */
887 Ocw2
.EoiMode
= SpecificEoi
;
888 __outbyte(PIC1_CONTROL_PORT
, Ocw2
.Bits
| 2);
890 /* And now fail since this was spurious */
894 /* Do normal interrupt dismiss */
895 return _HalpDismissIrqGeneric(Irql
, Irq
, OldIrql
);
901 HalpDismissIrq13(IN KIRQL Irql
,
905 /* Clear the FPU busy latch */
908 /* Do normal interrupt dismiss */
909 return _HalpDismissIrqGeneric(Irql
, Irq
, OldIrql
);
914 HalpDismissIrq07(IN KIRQL Irql
,
921 /* Request the ISR */
924 Ocw3
.ReadRequest
= ReadIsr
;
925 __outbyte(PIC1_CONTROL_PORT
, Ocw3
.Bits
);
928 Isr
.Bits
= __inbyte(PIC1_CONTROL_PORT
);
930 /* Is IRQ 7 really active? If it isn't, this is spurious so fail */
931 if (Isr
.Irq7
== FALSE
) return FALSE
;
933 /* Do normal interrupt dismiss */
934 return _HalpDismissIrqGeneric(Irql
, Irq
, OldIrql
);
937 /* LEVEL INTERRUPT DISMISSAL FUNCTIONS ****************************************/
941 _HalpDismissIrqLevel(IN KIRQL Irql
,
948 PKPCR Pcr
= KeGetPcr();
951 Mask
.Both
= (KiI8259MaskTable
[Irql
] | Pcr
->IDR
) & 0xFFFF;
952 __outbyte(PIC1_DATA_PORT
, Mask
.Master
);
953 __outbyte(PIC2_DATA_PORT
, Mask
.Slave
);
955 /* Update the IRR so that we clear this interrupt when the IRQL is proper */
956 Pcr
->IRR
|= (1 << (Irq
+ 4));
958 /* Save current IRQL */
959 CurrentIrql
= Pcr
->Irql
;
961 /* Prepare OCW2 for EOI */
963 Ocw2
.EoiMode
= SpecificEoi
;
965 /* Check which PIC needs the EOI */
968 /* Send the EOI for the IRQ */
969 __outbyte(PIC2_CONTROL_PORT
, Ocw2
.Bits
| ((Irq
- 8) & 0xFF));
971 /* Send the EOI for IRQ2 on the master because this was cascaded */
972 __outbyte(PIC1_CONTROL_PORT
, Ocw2
.Bits
| 2);
976 /* Send the EOI for the IRQ */
977 __outbyte(PIC1_CONTROL_PORT
, Ocw2
.Bits
| (Irq
& 0xFF));
980 /* Check if this interrupt should be allowed to happen */
981 if (Irql
> CurrentIrql
)
983 /* Set the new IRQL and return the current one */
985 *OldIrql
= CurrentIrql
;
987 /* Enable interrupts and return success */
992 /* Now lie and say this was spurious */
998 HalpDismissIrqLevel(IN KIRQL Irql
,
1002 /* Run the inline code */
1003 return _HalpDismissIrqLevel(Irql
, Irq
, OldIrql
);
1008 HalpDismissIrq15Level(IN KIRQL Irql
,
1016 /* Request the ISR */
1018 Ocw3
.Sbo
= 1; /* This encodes an OCW3 vs. an OCW2 */
1019 Ocw3
.ReadRequest
= ReadIsr
;
1020 __outbyte(PIC2_CONTROL_PORT
, Ocw3
.Bits
);
1023 Isr
.Bits
= __inbyte(PIC2_CONTROL_PORT
);
1025 /* Is IRQ15 really active (this is IR7) */
1026 if (Isr
.Irq7
== FALSE
)
1028 /* It isn't, so we have to EOI IRQ2 because this was cascaded */
1030 Ocw2
.EoiMode
= SpecificEoi
;
1031 __outbyte(PIC1_CONTROL_PORT
, Ocw2
.Bits
| 2);
1033 /* And now fail since this was spurious */
1037 /* Do normal interrupt dismiss */
1038 return _HalpDismissIrqLevel(Irql
, Irq
, OldIrql
);
1043 HalpDismissIrq13Level(IN KIRQL Irql
,
1047 /* Clear the FPU busy latch */
1050 /* Do normal interrupt dismiss */
1051 return _HalpDismissIrqLevel(Irql
, Irq
, OldIrql
);
1056 HalpDismissIrq07Level(IN KIRQL Irql
,
1063 /* Request the ISR */
1066 Ocw3
.ReadRequest
= ReadIsr
;
1067 __outbyte(PIC1_CONTROL_PORT
, Ocw3
.Bits
);
1070 Isr
.Bits
= __inbyte(PIC1_CONTROL_PORT
);
1072 /* Is IRQ 7 really active? If it isn't, this is spurious so fail */
1073 if (Isr
.Irq7
== FALSE
) return FALSE
;
1075 /* Do normal interrupt dismiss */
1076 return _HalpDismissIrqLevel(Irql
, Irq
, OldIrql
);
1081 HalpHardwareInterruptLevel(VOID
)
1083 PKPCR Pcr
= KeGetPcr();
1084 ULONG PendingIrqlMask
, PendingIrql
;
1086 /* Check for pending software interrupts and compare with current IRQL */
1087 PendingIrqlMask
= Pcr
->IRR
& FindHigherIrqlMask
[Pcr
->Irql
];
1088 if (PendingIrqlMask
)
1090 /* Check for in-service delayed interrupt */
1091 if (Pcr
->IrrActive
& 0xFFFFFFF0) return;
1093 /* Check if pending IRQL affects hardware state */
1094 BitScanReverse(&PendingIrql
, PendingIrqlMask
);
1097 Pcr
->IRR
^= (1 << PendingIrql
);
1099 /* Now handle pending interrupt */
1100 SWInterruptHandlerTable
[PendingIrql
]();
1104 /* SYSTEM INTERRUPTS **********************************************************/
1111 HalEnableSystemInterrupt(IN ULONG Vector
,
1113 IN KINTERRUPT_MODE InterruptMode
)
1116 PKPCR Pcr
= KeGetPcr();
1119 /* Validate the IRQ */
1120 Irq
= Vector
- PRIMARY_VECTOR_BASE
;
1121 if (Irq
>= CLOCK2_LEVEL
) return FALSE
;
1123 /* Check for level interrupt */
1124 if (InterruptMode
== LevelSensitive
)
1126 /* Switch handler to level */
1127 SWInterruptHandlerTable
[Irq
+ 4] = HalpHardwareInterruptLevel
;
1129 /* Switch dismiss to level */
1130 HalpSpecialDismissTable
[Irq
] = HalpSpecialDismissLevelTable
[Irq
];
1133 /* Disable interrupts */
1136 /* Update software IDR */
1137 Pcr
->IDR
&= ~(1 << Irq
);
1139 /* Set new PIC mask */
1140 PicMask
.Both
= (KiI8259MaskTable
[Pcr
->Irql
] | Pcr
->IDR
) & 0xFFFF;
1141 __outbyte(PIC1_DATA_PORT
, PicMask
.Master
);
1142 __outbyte(PIC2_DATA_PORT
, PicMask
.Slave
);
1144 /* Enable interrupts and exit */
1154 HalDisableSystemInterrupt(IN ULONG Vector
,
1160 /* Compute new combined IRQ mask */
1161 IrqMask
= 1 << (Vector
- PRIMARY_VECTOR_BASE
);
1163 /* Disable interrupts */
1166 /* Update software IDR */
1167 KeGetPcr()->IDR
|= IrqMask
;
1169 /* Read current interrupt mask */
1170 PicMask
.Master
= __inbyte(PIC1_DATA_PORT
);
1171 PicMask
.Slave
= __inbyte(PIC2_DATA_PORT
);
1173 /* Add the new disabled interrupt */
1174 PicMask
.Both
|= IrqMask
;
1176 /* Write new interrupt mask */
1177 __outbyte(PIC1_DATA_PORT
, PicMask
.Master
);
1178 __outbyte(PIC2_DATA_PORT
, PicMask
.Slave
);
1180 /* Bring interrupts back */
1189 HalBeginSystemInterrupt(IN KIRQL Irql
,
1195 /* Get the IRQ and call the proper routine to handle it */
1196 Irq
= Vector
- PRIMARY_VECTOR_BASE
;
1197 return HalpSpecialDismissTable
[Irq
](Irql
, Irq
, OldIrql
);
1205 HalEndSystemInterrupt(IN KIRQL OldIrql
,
1206 IN PKTRAP_FRAME TrapFrame
)
1208 ULONG PendingIrql
, PendingIrqlMask
, PendingIrqMask
;
1209 PKPCR Pcr
= KeGetPcr();
1213 Pcr
->Irql
= OldIrql
;
1215 /* Check for pending software interrupts and compare with current IRQL */
1216 PendingIrqlMask
= Pcr
->IRR
& FindHigherIrqlMask
[OldIrql
];
1217 if (PendingIrqlMask
)
1219 /* Check for in-service delayed interrupt */
1220 if (Pcr
->IrrActive
& 0xFFFFFFF0) return;
1222 /* Loop checking for pending interrupts */
1225 /* Check if pending IRQL affects hardware state */
1226 BitScanReverse(&PendingIrql
, PendingIrqlMask
);
1227 if (PendingIrql
> DISPATCH_LEVEL
)
1229 /* Set new PIC mask */
1230 Mask
.Both
= Pcr
->IDR
& 0xFFFF;
1231 __outbyte(PIC1_DATA_PORT
, Mask
.Master
);
1232 __outbyte(PIC2_DATA_PORT
, Mask
.Slave
);
1234 /* Now check if this specific interrupt is already in-service */
1235 PendingIrqMask
= (1 << PendingIrql
);
1236 if (Pcr
->IrrActive
& PendingIrqMask
) return;
1238 /* Set active bit otherwise, and clear it from IRR */
1239 Pcr
->IrrActive
|= PendingIrqMask
;
1240 Pcr
->IRR
^= PendingIrqMask
;
1242 /* Handle delayed hardware interrupt */
1243 SWInterruptHandlerTable
[PendingIrql
]();
1245 /* Handling complete */
1246 Pcr
->IrrActive
^= PendingIrqMask
;
1248 /* Check if there's still interrupts pending */
1249 PendingIrqlMask
= Pcr
->IRR
& FindHigherIrqlMask
[Pcr
->Irql
];
1250 if (!PendingIrqlMask
) break;
1254 /* Now handle pending software interrupt */
1255 SWInterruptHandlerTable2
[PendingIrql
](TrapFrame
);
1262 /* SOFTWARE INTERRUPT TRAPS ***************************************************/
1267 _HalpApcInterruptHandler(IN PKTRAP_FRAME TrapFrame
)
1270 PKPCR Pcr
= KeGetPcr();
1272 /* Save the current IRQL and update it */
1273 CurrentIrql
= Pcr
->Irql
;
1274 Pcr
->Irql
= APC_LEVEL
;
1276 /* Remove DPC from IRR */
1277 Pcr
->IRR
&= ~(1 << APC_LEVEL
);
1279 /* Enable interrupts and call the kernel's APC interrupt handler */
1281 KiDeliverApc(((KiUserTrap(TrapFrame
)) || (TrapFrame
->EFlags
& EFLAGS_V86_MASK
)) ?
1282 UserMode
: KernelMode
,
1286 /* Disable interrupts and end the interrupt */
1288 HalpEndSoftwareInterrupt(CurrentIrql
, TrapFrame
);
1290 /* Exit the interrupt */
1291 KiEoiHelper(TrapFrame
);
1297 HalpApcInterrupt2ndEntry(IN PKTRAP_FRAME TrapFrame
)
1300 _HalpApcInterruptHandler(TrapFrame
);
1306 HalpApcInterruptHandler(IN PKTRAP_FRAME TrapFrame
)
1308 /* Set up a fake INT Stack */
1309 TrapFrame
->EFlags
= __readeflags();
1310 TrapFrame
->SegCs
= KGDT_R0_CODE
;
1311 TrapFrame
->Eip
= TrapFrame
->Eax
;
1313 /* Build the trap frame */
1314 KiEnterInterruptTrap(TrapFrame
);
1317 _HalpApcInterruptHandler(TrapFrame
);
1322 _HalpDispatchInterruptHandler(VOID
)
1325 PKPCR Pcr
= KeGetPcr();
1327 /* Save the current IRQL and update it */
1328 CurrentIrql
= Pcr
->Irql
;
1329 Pcr
->Irql
= DISPATCH_LEVEL
;
1331 /* Remove DPC from IRR */
1332 Pcr
->IRR
&= ~(1 << DISPATCH_LEVEL
);
1334 /* Enable interrupts and call the kernel's DPC interrupt handler */
1336 KiDispatchInterrupt();
1346 HalpDispatchInterrupt2ndEntry(IN PKTRAP_FRAME TrapFrame
)
1351 CurrentIrql
= _HalpDispatchInterruptHandler();
1353 /* End the interrupt */
1354 HalpEndSoftwareInterrupt(CurrentIrql
, TrapFrame
);
1356 /* Exit the interrupt */
1357 KiEoiHelper(TrapFrame
);
1362 HalpDispatchInterrupt2(VOID
)
1364 ULONG PendingIrqlMask
, PendingIrql
;
1367 PKPCR Pcr
= KeGetPcr();
1370 OldIrql
= _HalpDispatchInterruptHandler();
1373 Pcr
->Irql
= OldIrql
;
1375 /* Check for pending software interrupts and compare with current IRQL */
1376 PendingIrqlMask
= Pcr
->IRR
& FindHigherIrqlMask
[OldIrql
];
1377 if (PendingIrqlMask
)
1379 /* Check if pending IRQL affects hardware state */
1380 BitScanReverse(&PendingIrql
, PendingIrqlMask
);
1381 if (PendingIrql
> DISPATCH_LEVEL
)
1383 /* Set new PIC mask */
1384 Mask
.Both
= Pcr
->IDR
& 0xFFFF;
1385 __outbyte(PIC1_DATA_PORT
, Mask
.Master
);
1386 __outbyte(PIC2_DATA_PORT
, Mask
.Slave
);
1389 Pcr
->IRR
^= (1 << PendingIrql
);
1392 /* Now handle pending interrupt */
1393 SWInterruptHandlerTable
[PendingIrql
]();
1401 KeGetCurrentIrql(VOID
)
1403 return PASSIVE_LEVEL
;