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 ********************************************************************/
18 * This table basically keeps track of level vs edge triggered interrupts.
19 * Windows has 250+ entries, but it seems stupid to replicate that since the PIC
20 * can't actually have that many.
22 * When a level interrupt is registered, the respective pointer in this table is
23 * modified to point to a dimiss routine for level interrupts instead.
25 * The other thing this table does is special case IRQ7, IRQ13 and IRQ15:
27 * - If an IRQ line is deasserted before it is acknowledged due to a noise spike
28 * generated by an expansion device (since the IRQ line is low during the 1st
29 * acknowledge bus cycle), the i8259 will keep the line low for at least 100ns
30 * When the spike passes, a pull-up resistor will return the IRQ line to high.
31 * Since the PIC requires the input be high until the first acknowledge, the
32 * i8259 knows that this was a spurious interrupt, and on the second interrupt
33 * acknowledge cycle, it reports this to the CPU. Since no valid interrupt has
34 * actually happened Intel hardcoded the chip to report IRQ7 on the master PIC
35 * and IRQ15 on the slave PIC (IR7 either way).
37 * "ISA System Architecture", 3rd Edition, states that these cases should be
38 * handled by reading the respective Interrupt Service Request (ISR) bits from
39 * the affected PIC, and validate whether or not IR7 is set. If it isn't, then
40 * the interrupt is spurious and should be ignored.
42 * Note that for a spurious IRQ15, we DO have to send an EOI to the master for
43 * IRQ2 since the line was asserted by the slave when it received the spurious
46 * - When the 80287/80387 math co-processor generates an FPU/NPX trap, this is
47 * connected to IRQ13, so we have to clear the busy latch on the NPX port.
49 PHAL_DISMISS_INTERRUPT HalpSpecialDismissTable
[16] =
51 HalpDismissIrqGeneric
,
52 HalpDismissIrqGeneric
,
53 HalpDismissIrqGeneric
,
54 HalpDismissIrqGeneric
,
55 HalpDismissIrqGeneric
,
56 HalpDismissIrqGeneric
,
57 HalpDismissIrqGeneric
,
59 HalpDismissIrqGeneric
,
60 HalpDismissIrqGeneric
,
61 HalpDismissIrqGeneric
,
62 HalpDismissIrqGeneric
,
63 HalpDismissIrqGeneric
,
65 HalpDismissIrqGeneric
,
69 /* This table contains the static x86 PIC mapping between IRQLs and IRQs */
70 ULONG KiI8259MaskTable
[32] =
73 #if __GNUC__ * 100 + __GNUC_MINOR__ >= 404
75 * It Device IRQLs only start at 4 or higher, so these are just software
76 * IRQLs that don't really change anything on the hardware
78 0b00000000000000000000000000000000, /* IRQL 0 */
79 0b00000000000000000000000000000000, /* IRQL 1 */
80 0b00000000000000000000000000000000, /* IRQL 2 */
81 0b00000000000000000000000000000000, /* IRQL 3 */
84 * These next IRQLs are actually useless from the PIC perspective, because
85 * with only 2 PICs, the mask you can send them is only 8 bits each, for 16
86 * bits total, so these IRQLs are masking off a phantom PIC.
88 0b11111111100000000000000000000000, /* IRQL 4 */
89 0b11111111110000000000000000000000, /* IRQL 5 */
90 0b11111111111000000000000000000000, /* IRQL 6 */
91 0b11111111111100000000000000000000, /* IRQL 7 */
92 0b11111111111110000000000000000000, /* IRQL 8 */
93 0b11111111111111000000000000000000, /* IRQL 9 */
94 0b11111111111111100000000000000000, /* IRQL 10 */
95 0b11111111111111110000000000000000, /* IRQL 11 */
98 * Okay, now we're finally starting to mask off IRQs on the slave PIC, from
99 * IRQ15 to IRQ8. This means the higher-level IRQs get less priority in the
102 0b11111111111111111000000000000000, /* IRQL 12 */
103 0b11111111111111111100000000000000, /* IRQL 13 */
104 0b11111111111111111110000000000000, /* IRQL 14 */
105 0b11111111111111111111000000000000, /* IRQL 15 */
106 0b11111111111111111111100000000000, /* IRQL 16 */
107 0b11111111111111111111110000000000, /* IRQL 17 */
108 0b11111111111111111111111000000000, /* IRQL 18 */
109 0b11111111111111111111111000000000, /* IRQL 19 */
112 * Now we mask off the IRQs on the master. Notice the 0 "droplet"? You might
113 * have also seen that IRQL 18 and 19 are essentially equal as far as the
114 * PIC is concerned. That bit is actually IRQ8, which happens to be the RTC.
115 * The RTC will keep firing as long as we don't reach PROFILE_LEVEL which
116 * actually kills it. The RTC clock (unlike the system clock) is used by the
117 * profiling APIs in the HAL, so that explains the logic.
119 0b11111111111111111111111010000000, /* IRQL 20 */
120 0b11111111111111111111111011000000, /* IRQL 21 */
121 0b11111111111111111111111011100000, /* IRQL 22 */
122 0b11111111111111111111111011110000, /* IRQL 23 */
123 0b11111111111111111111111011111000, /* IRQL 24 */
124 0b11111111111111111111111011111000, /* IRQL 25 */
125 0b11111111111111111111111011111010, /* IRQL 26 */
126 0b11111111111111111111111111111010, /* IRQL 27 */
129 * IRQL 24 and 25 are actually identical, so IRQL 28 is actually the last
130 * IRQL to modify a bit on the master PIC. It happens to modify the very
131 * last of the IRQs, IRQ0, which corresponds to the system clock interval
132 * timer that keeps track of time (the Windows heartbeat). We only want to
133 * turn this off at a high-enough IRQL, which is why IRQLs 24 and 25 are the
134 * same to give this guy a chance to come up higher. Note that IRQL 28 is
135 * called CLOCK2_LEVEL, which explains the usage we just explained.
137 0b11111111111111111111111111111011, /* IRQL 28 */
140 * We have finished off with the PIC so there's nothing left to mask at the
141 * level of these IRQLs, making them only logical IRQLs on x86 machines.
142 * Note that we have another 0 "droplet" you might've caught since IRQL 26.
143 * In this case, it's the 2nd bit that never gets turned off, which is IRQ2,
144 * the cascade IRQ that we use to bridge the slave PIC with the master PIC.
145 * We never want to turn it off, so no matter the IRQL, it will be set to 0.
147 0b11111111111111111111111111111011, /* IRQL 29 */
148 0b11111111111111111111111111111011, /* IRQL 30 */
149 0b11111111111111111111111111111011 /* IRQL 31 */
155 0xFF800000, /* IRQL 4 */
156 0xFFC00000, /* IRQL 5 */
157 0xFFE00000, /* IRQL 6 */
158 0xFFF00000, /* IRQL 7 */
159 0xFFF80000, /* IRQL 8 */
160 0xFFFC0000, /* IRQL 9 */
161 0xFFFE0000, /* IRQL 10 */
162 0xFFFF0000, /* IRQL 11 */
163 0xFFFF8000, /* IRQL 12 */
164 0xFFFFC000, /* IRQL 13 */
165 0xFFFFE000, /* IRQL 14 */
166 0xFFFFF000, /* IRQL 15 */
167 0xFFFFF800, /* IRQL 16 */
168 0xFFFFFC00, /* IRQL 17 */
169 0xFFFFFE00, /* IRQL 18 */
170 0xFFFFFE00, /* IRQL 19 */
171 0xFFFFFE80, /* IRQL 20 */
172 0xFFFFFEC0, /* IRQL 21 */
173 0xFFFFFEE0, /* IRQL 22 */
174 0xFFFFFEF0, /* IRQL 23 */
175 0xFFFFFEF8, /* IRQL 24 */
176 0xFFFFFEF8, /* IRQL 25 */
177 0xFFFFFEFA, /* IRQL 26 */
178 0xFFFFFFFA, /* IRQL 27 */
179 0xFFFFFFFB, /* IRQL 28 */
180 0xFFFFFFFB, /* IRQL 29 */
181 0xFFFFFFFB, /* IRQL 30 */
182 0xFFFFFFFB /* IRQL 31 */
187 /* Denotes minimum required IRQL before we can process pending SW interrupts */
188 KIRQL SWInterruptLookUpTable
[8] =
190 PASSIVE_LEVEL
, /* IRR 0 */
191 PASSIVE_LEVEL
, /* IRR 1 */
192 APC_LEVEL
, /* IRR 2 */
193 APC_LEVEL
, /* IRR 3 */
194 DISPATCH_LEVEL
, /* IRR 4 */
195 DISPATCH_LEVEL
, /* IRR 5 */
196 DISPATCH_LEVEL
, /* IRR 6 */
197 DISPATCH_LEVEL
/* IRR 7 */
200 /* Handlers for pending software interrupts */
201 PHAL_SW_INTERRUPT_HANDLER SWInterruptHandlerTable
[3] =
203 KiUnexpectedInterrupt
,
205 HalpDispatchInterrupt
208 /* Handlers for pending software interrupts when we already have a trap frame*/
209 PHAL_SW_INTERRUPT_HANDLER_2ND_ENTRY SWInterruptHandlerTable2
[3] =
211 (PHAL_SW_INTERRUPT_HANDLER_2ND_ENTRY
)KiUnexpectedInterrupt
,
212 HalpApcInterrupt2ndEntry
,
213 HalpDispatchInterrupt2ndEntry
219 /* FUNCTIONS ******************************************************************/
223 HalpInitializePICs(IN BOOLEAN EnableInterrupts
)
233 /* Save EFlags and disable interrupts */
234 EFlags
= __readeflags();
237 /* Initialize ICW1 for master, interval 8, edge-triggered mode with ICW4 */
238 Icw1
.NeedIcw4
= TRUE
;
239 Icw1
.InterruptMode
= EdgeTriggered
;
240 Icw1
.OperatingMode
= Cascade
;
241 Icw1
.Interval
= Interval8
;
243 Icw1
.InterruptVectorAddress
= 0; /* This is only used in MCS80/85 mode */
244 __outbyte(PIC1_CONTROL_PORT
, Icw1
.Bits
);
246 /* Set interrupt vector base */
247 Icw2
.Bits
= PRIMARY_VECTOR_BASE
;
248 __outbyte(PIC1_DATA_PORT
, Icw2
.Bits
);
250 /* Connect slave to IRQ 2 */
252 Icw3
.SlaveIrq2
= TRUE
;
253 __outbyte(PIC1_DATA_PORT
, Icw3
.Bits
);
255 /* Enable 8086 mode, non-automatic EOI, non-buffered mode, non special fully nested mode */
257 Icw4
.SystemMode
= New8086Mode
;
258 Icw4
.EoiMode
= NormalEoi
;
259 Icw4
.BufferedMode
= NonBuffered
;
260 Icw4
.SpecialFullyNestedMode
= FALSE
;
261 __outbyte(PIC1_DATA_PORT
, Icw4
.Bits
);
263 /* Mask all interrupts */
264 __outbyte(PIC1_DATA_PORT
, 0xFF);
266 /* Initialize ICW1 for master, interval 8, edge-triggered mode with ICW4 */
267 Icw1
.NeedIcw4
= TRUE
;
268 Icw1
.InterruptMode
= EdgeTriggered
;
269 Icw1
.OperatingMode
= Cascade
;
270 Icw1
.Interval
= Interval8
;
272 Icw1
.InterruptVectorAddress
= 0; /* This is only used in MCS80/85 mode */
273 __outbyte(PIC2_CONTROL_PORT
, Icw1
.Bits
);
275 /* Set interrupt vector base */
276 Icw2
.Bits
= PRIMARY_VECTOR_BASE
+ 8;
277 __outbyte(PIC2_DATA_PORT
, Icw2
.Bits
);
282 __outbyte(PIC2_DATA_PORT
, Icw3
.Bits
);
284 /* Enable 8086 mode, non-automatic EOI, non-buffered mode, non special fully nested mode */
286 Icw4
.SystemMode
= New8086Mode
;
287 Icw4
.EoiMode
= NormalEoi
;
288 Icw4
.BufferedMode
= NonBuffered
;
289 Icw4
.SpecialFullyNestedMode
= FALSE
;
290 __outbyte(PIC2_DATA_PORT
, Icw4
.Bits
);
292 /* Mask all interrupts */
293 __outbyte(PIC2_DATA_PORT
, 0xFF);
295 /* Read EISA Edge/Level Register for master and slave */
296 Elcr
.Bits
= (__inbyte(EISA_ELCR_SLAVE
) << 8) | __inbyte(EISA_ELCR_MASTER
);
298 /* IRQs 0, 1, 2, 8, and 13 are system-reserved and must be edge */
299 if (!(Elcr
.Master
.Irq0Level
) && !(Elcr
.Master
.Irq1Level
) && !(Elcr
.Master
.Irq2Level
) &&
300 !(Elcr
.Slave
.Irq8Level
) && !(Elcr
.Slave
.Irq13Level
))
302 /* ELCR is as it's supposed to be, save it */
303 HalpEisaELCR
= Elcr
.Bits
;
304 DPRINT1("HAL Detected EISA Interrupt Controller (ELCR: %lx)\n", HalpEisaELCR
);
306 /* Scan for level interrupts */
307 for (i
= 1, j
= 0; j
< 16; i
<<= 1, j
++)
309 /* Warn the user ReactOS does not (and has never) supported this */
310 if (HalpEisaELCR
& i
) DPRINT1("WARNING: IRQ %d is SHARED and LEVEL-SENSITIVE. This is unsupported!\n", j
);
314 /* Restore interrupt state */
315 if (EnableInterrupts
) EFlags
|= EFLAGS_INTERRUPT_MASK
;
316 __writeeflags(EFlags
);
319 /* IRQL MANAGEMENT ************************************************************/
326 KeGetCurrentIrql(VOID
)
328 /* Return the IRQL */
329 return KeGetPcr()->Irql
;
337 KeRaiseIrqlToDpcLevel(VOID
)
339 PKPCR Pcr
= KeGetPcr();
342 /* Save and update IRQL */
343 CurrentIrql
= Pcr
->Irql
;
344 Pcr
->Irql
= DISPATCH_LEVEL
;
347 /* Validate correct raise */
348 if (CurrentIrql
> DISPATCH_LEVEL
)
351 KeBugCheckEx(IRQL_NOT_GREATER_OR_EQUAL
,
359 /* Return the previous value */
368 KeRaiseIrqlToSynchLevel(VOID
)
370 PKPCR Pcr
= KeGetPcr();
373 /* Save and update IRQL */
374 CurrentIrql
= Pcr
->Irql
;
375 Pcr
->Irql
= SYNCH_LEVEL
;
378 /* Validate correct raise */
379 if (CurrentIrql
> SYNCH_LEVEL
)
382 KeBugCheckEx(IRQL_NOT_GREATER_OR_EQUAL
,
390 /* Return the previous value */
399 KfRaiseIrql(IN KIRQL NewIrql
)
401 PKPCR Pcr
= KeGetPcr();
406 /* Read current IRQL */
407 CurrentIrql
= Pcr
->Irql
;
410 /* Validate correct raise */
411 if (CurrentIrql
> NewIrql
)
414 Pcr
->Irql
= PASSIVE_LEVEL
;
415 KeBugCheckEx(IRQL_NOT_GREATER_OR_EQUAL
,
423 /* Check if new IRQL affects hardware state */
424 if (NewIrql
> DISPATCH_LEVEL
)
426 /* Save current interrupt state and disable interrupts */
427 EFlags
= __readeflags();
430 /* Update the IRQL */
433 /* Set new PIC mask */
434 Mask
.Both
= KiI8259MaskTable
[NewIrql
] | Pcr
->IDR
;
435 __outbyte(PIC1_DATA_PORT
, Mask
.Master
);
436 __outbyte(PIC2_DATA_PORT
, Mask
.Slave
);
438 /* Restore interrupt state */
439 __writeeflags(EFlags
);
447 /* Return old IRQL */
457 KfLowerIrql(IN KIRQL OldIrql
)
461 PKPCR Pcr
= KeGetPcr();
465 /* Validate correct lower */
466 if (OldIrql
> Pcr
->Irql
)
469 KIRQL CurrentIrql
= Pcr
->Irql
;
470 Pcr
->Irql
= HIGH_LEVEL
;
471 KeBugCheckEx(IRQL_NOT_LESS_OR_EQUAL
,
479 /* Save EFlags and disable interrupts */
480 EFlags
= __readeflags();
483 /* Check if currentl IRQL affects hardware state */
484 if (Pcr
->Irql
> DISPATCH_LEVEL
)
486 /* Set new PIC mask */
487 Mask
.Both
= KiI8259MaskTable
[OldIrql
] | Pcr
->IDR
;
488 __outbyte(PIC1_DATA_PORT
, Mask
.Master
);
489 __outbyte(PIC2_DATA_PORT
, Mask
.Slave
);
495 /* Check for pending software interrupts and compare with current IRQL */
496 PendingIrql
= SWInterruptLookUpTable
[Pcr
->IRR
];
497 if (PendingIrql
> OldIrql
) SWInterruptHandlerTable
[PendingIrql
]();
499 /* Restore interrupt state */
500 __writeeflags(EFlags
);
503 /* SOFTWARE INTERRUPTS ********************************************************/
510 HalRequestSoftwareInterrupt(IN KIRQL Irql
)
513 PKPCR Pcr
= KeGetPcr();
516 /* Save EFlags and disable interrupts */
517 EFlags
= __readeflags();
520 /* Mask out the requested bit */
521 Pcr
->IRR
|= (1 << Irql
);
523 /* Check for pending software interrupts and compare with current IRQL */
524 PendingIrql
= SWInterruptLookUpTable
[Pcr
->IRR
& 3];
525 if (PendingIrql
> Pcr
->Irql
) SWInterruptHandlerTable
[PendingIrql
]();
527 /* Restore interrupt state */
528 __writeeflags(EFlags
);
536 HalClearSoftwareInterrupt(IN KIRQL Irql
)
538 /* Mask out the requested bit */
539 KeGetPcr()->IRR
&= ~(1 << Irql
);
544 HalpEndSoftwareInterrupt(IN KIRQL OldIrql
)
547 PKPCR Pcr
= KeGetPcr();
550 /* Check if currentl IRQL affects hardware state */
551 if (Pcr
->Irql
> DISPATCH_LEVEL
)
553 /* Set new PIC mask */
554 Mask
.Both
= KiI8259MaskTable
[OldIrql
] | Pcr
->IDR
;
555 __outbyte(PIC1_DATA_PORT
, Mask
.Master
);
556 __outbyte(PIC2_DATA_PORT
, Mask
.Slave
);
562 /* Check for pending software interrupts and compare with current IRQL */
563 PendingIrql
= SWInterruptLookUpTable
[Pcr
->IRR
];
564 if (PendingIrql
> OldIrql
) HalpNestedTrap(PendingIrql
);
567 /* INTERRUPT DISMISSAL FUNCTIONS **********************************************/
571 _HalpDismissIrqGeneric(IN KIRQL Irql
,
578 PKPCR Pcr
= KeGetPcr();
580 /* First save current IRQL and compare it to the requested one */
581 CurrentIrql
= Pcr
->Irql
;
583 /* Set the new IRQL and return the current one */
585 *OldIrql
= CurrentIrql
;
587 /* Set new PIC mask */
588 Mask
.Both
= KiI8259MaskTable
[Irql
] | Pcr
->IDR
;
589 __outbyte(PIC1_DATA_PORT
, Mask
.Master
);
590 __outbyte(PIC2_DATA_PORT
, Mask
.Slave
);
592 /* Prepare OCW2 for EOI */
594 Ocw2
.EoiMode
= SpecificEoi
;
596 /* Check which PIC needs the EOI */
599 /* Send the EOI for the IRQ */
600 __outbyte(PIC2_CONTROL_PORT
, Ocw2
.Bits
| (Irq
- 8));
602 /* Send the EOI for IRQ2 on the master because this was cascaded */
603 __outbyte(PIC1_CONTROL_PORT
, Ocw2
.Bits
| 2);
607 /* Send the EOI for the IRQ */
608 __outbyte(PIC1_CONTROL_PORT
, Ocw2
.Bits
| Irq
);
611 /* Enable interrupts and return success */
617 __attribute__((regparm(3)))
618 HalpDismissIrqGeneric(IN KIRQL Irql
,
622 /* Run the inline code */
623 return _HalpDismissIrqGeneric(Irql
, Irq
, OldIrql
);
627 __attribute__((regparm(3)))
628 HalpDismissIrq15(IN KIRQL Irql
,
636 /* Request the ISR */
638 Ocw3
.Sbo
= 1; /* This encodes an OCW3 vs. an OCW2 */
639 Ocw3
.ReadRequest
= ReadIsr
;
640 __outbyte(PIC2_CONTROL_PORT
, Ocw3
.Bits
);
643 Isr
.Bits
= __inbyte(PIC2_CONTROL_PORT
);
645 /* Is IRQ15 really active (this is IR7) */
646 if (Isr
.Irq7
== FALSE
)
648 /* It isn't, so we have to EOI IRQ2 because this was cascaded */
650 Ocw2
.EoiMode
= SpecificEoi
;
651 __outbyte(PIC1_CONTROL_PORT
, Ocw2
.Bits
| 2);
653 /* And now fail since this was spurious */
657 /* Do normal interrupt dismiss */
658 return _HalpDismissIrqGeneric(Irql
, Irq
, OldIrql
);
663 __attribute__((regparm(3)))
664 HalpDismissIrq13(IN KIRQL Irql
,
668 /* Clear the FPU busy latch */
671 /* Do normal interrupt dismiss */
672 return _HalpDismissIrqGeneric(Irql
, Irq
, OldIrql
);
676 __attribute__((regparm(3)))
677 HalpDismissIrq07(IN KIRQL Irql
,
684 /* Request the ISR */
687 Ocw3
.ReadRequest
= ReadIsr
;
688 __outbyte(PIC1_CONTROL_PORT
, Ocw3
.Bits
);
691 Isr
.Bits
= __inbyte(PIC1_CONTROL_PORT
);
693 /* Is IRQ 7 really active? If it isn't, this is spurious so fail */
694 if (Isr
.Irq7
== FALSE
) return FALSE
;
696 /* Do normal interrupt dismiss */
697 return _HalpDismissIrqGeneric(Irql
, Irq
, OldIrql
);
700 /* SYSTEM INTERRUPTS **********************************************************/
707 HalEnableSystemInterrupt(IN UCHAR Vector
,
709 IN KINTERRUPT_MODE InterruptMode
)
712 PKPCR Pcr
= KeGetPcr();
715 /* Validate the IRQ */
716 Irq
= Vector
- PRIMARY_VECTOR_BASE
;
717 if (Irq
>= CLOCK2_LEVEL
) return FALSE
;
720 /* Check if there is a PCI IRQ Routing Miniport Driver */
721 if (HalpIrqMiniportInitialized
)
728 /* Disable interrupts */
731 /* Update software IDR */
732 Pcr
->IDR
&= ~(1 << Irq
);
734 /* Set new PIC mask */
735 PicMask
.Both
= KiI8259MaskTable
[Pcr
->Irql
] | Pcr
->IDR
;
736 __outbyte(PIC1_DATA_PORT
, PicMask
.Master
);
737 __outbyte(PIC2_DATA_PORT
, PicMask
.Slave
);
739 /* Enable interrupts and exit */
749 HalDisableSystemInterrupt(IN UCHAR Vector
,
755 /* Compute new combined IRQ mask */
756 IrqMask
= 1 << (Vector
- PRIMARY_VECTOR_BASE
);
758 /* Disable interrupts */
761 /* Update software IDR */
762 KeGetPcr()->IDR
|= IrqMask
;
764 /* Read current interrupt mask */
765 PicMask
.Master
= __inbyte(PIC1_DATA_PORT
);
766 PicMask
.Slave
= __inbyte(PIC2_DATA_PORT
);
768 /* Add the new disabled interrupt */
769 PicMask
.Both
|= IrqMask
;
771 /* Write new interrupt mask */
772 __outbyte(PIC1_DATA_PORT
, PicMask
.Master
);
773 __outbyte(PIC2_DATA_PORT
, PicMask
.Slave
);
775 /* Bring interrupts back */
784 HalBeginSystemInterrupt(IN KIRQL Irql
,
790 /* Get the IRQ and call the proper routine to handle it */
791 Irq
= Vector
- PRIMARY_VECTOR_BASE
;
792 return HalpSpecialDismissTable
[Irq
](Irql
, Irq
, OldIrql
);
800 HalEndSystemInterrupt(IN KIRQL OldIrql
,
804 PKPCR Pcr
= KeGetPcr();
807 /* Check if currentl IRQL affects hardware state */
808 if (Pcr
->Irql
> DISPATCH_LEVEL
)
810 /* Set new PIC mask */
811 Mask
.Both
= KiI8259MaskTable
[OldIrql
] | Pcr
->IDR
;
812 __outbyte(PIC1_DATA_PORT
, Mask
.Master
);
813 __outbyte(PIC2_DATA_PORT
, Mask
.Slave
);
819 /* Check for pending software interrupts and compare with current IRQL */
820 PendingIrql
= SWInterruptLookUpTable
[Pcr
->IRR
];
821 if (PendingIrql
> OldIrql
) HalpNestedTrap(PendingIrql
);
824 /* SOFTWARE INTERRUPT TRAPS ***************************************************/
829 _HalpApcInterruptHandler(IN PKTRAP_FRAME TrapFrame
)
832 PKPCR Pcr
= KeGetPcr();
834 /* Save the current IRQL and update it */
835 CurrentIrql
= Pcr
->Irql
;
836 Pcr
->Irql
= APC_LEVEL
;
838 /* Remove DPC from IRR */
839 Pcr
->IRR
&= ~(1 << APC_LEVEL
);
841 /* Enable interrupts and call the kernel's APC interrupt handler */
843 KiDeliverApc(((KiUserTrap(TrapFrame
)) || (TrapFrame
->EFlags
& EFLAGS_V86_MASK
)) ?
844 UserMode
: KernelMode
,
848 /* Disable interrupts and end the interrupt */
850 Pcr
->VdmAlert
= (ULONG_PTR
)TrapFrame
;
851 HalpEndSoftwareInterrupt(CurrentIrql
);
853 /* Exit the interrupt */
854 KiEoiHelper(TrapFrame
);
860 HalpApcInterrupt2ndEntry(IN PKTRAP_FRAME TrapFrame
)
863 _HalpApcInterruptHandler(TrapFrame
);
869 HalpApcInterruptHandler(IN PKTRAP_FRAME TrapFrame
)
871 /* Set up a fake INT Stack */
872 TrapFrame
->EFlags
= __readeflags();
873 TrapFrame
->SegCs
= KGDT_R0_CODE
;
874 TrapFrame
->Eip
= TrapFrame
->Eax
;
876 /* Build the trap frame */
877 KiEnterInterruptTrap(TrapFrame
);
880 _HalpApcInterruptHandler(TrapFrame
);
886 _HalpDispatchInterruptHandler(IN PKTRAP_FRAME TrapFrame
)
889 PKPCR Pcr
= KeGetPcr();
891 /* Save the current IRQL and update it */
892 CurrentIrql
= Pcr
->Irql
;
893 Pcr
->Irql
= DISPATCH_LEVEL
;
895 /* Remove DPC from IRR */
896 Pcr
->IRR
&= ~(1 << DISPATCH_LEVEL
);
898 /* Enable interrupts and call the kernel's DPC interrupt handler */
900 KiDispatchInterrupt();
902 /* Disable interrupts and end the interrupt */
904 Pcr
->VdmAlert
= (ULONG_PTR
)TrapFrame
;
905 HalpEndSoftwareInterrupt(CurrentIrql
);
907 /* Exit the interrupt */
908 KiEoiHelper(TrapFrame
);
914 HalpDispatchInterrupt2ndEntry(IN PKTRAP_FRAME TrapFrame
)
917 _HalpDispatchInterruptHandler(TrapFrame
);
923 HalpDispatchInterruptHandler(IN PKTRAP_FRAME TrapFrame
)
925 /* Set up a fake INT Stack */
926 TrapFrame
->EFlags
= __readeflags();
927 TrapFrame
->SegCs
= KGDT_R0_CODE
;
928 TrapFrame
->Eip
= TrapFrame
->Eax
;
930 /* Build the trap frame */
931 KiEnterInterruptTrap(TrapFrame
);
934 _HalpDispatchInterruptHandler(TrapFrame
);
937 KiTrap(HalpApcInterrupt
, KI_SOFTWARE_TRAP
);
938 KiTrap(HalpDispatchInterrupt
, KI_SOFTWARE_TRAP
);