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
210 /* FUNCTIONS ******************************************************************/
214 HalpInitializePICs(IN BOOLEAN EnableInterrupts
)
224 /* Save EFlags and disable interrupts */
225 EFlags
= __readeflags();
228 /* Initialize ICW1 for master, interval 8, edge-triggered mode with ICW4 */
229 Icw1
.NeedIcw4
= TRUE
;
230 Icw1
.InterruptMode
= EdgeTriggered
;
231 Icw1
.OperatingMode
= Cascade
;
232 Icw1
.Interval
= Interval8
;
234 Icw1
.InterruptVectorAddress
= 0; /* This is only used in MCS80/85 mode */
235 __outbyte(PIC1_CONTROL_PORT
, Icw1
.Bits
);
237 /* Set interrupt vector base */
238 Icw2
.Bits
= PRIMARY_VECTOR_BASE
;
239 __outbyte(PIC1_DATA_PORT
, Icw2
.Bits
);
241 /* Connect slave to IRQ 2 */
243 Icw3
.SlaveIrq2
= TRUE
;
244 __outbyte(PIC1_DATA_PORT
, Icw3
.Bits
);
246 /* Enable 8086 mode, non-automatic EOI, non-buffered mode, non special fully nested mode */
248 Icw4
.SystemMode
= New8086Mode
;
249 Icw4
.EoiMode
= NormalEoi
;
250 Icw4
.BufferedMode
= NonBuffered
;
251 Icw4
.SpecialFullyNestedMode
= FALSE
;
252 __outbyte(PIC1_DATA_PORT
, Icw4
.Bits
);
254 /* Mask all interrupts */
255 __outbyte(PIC1_DATA_PORT
, 0xFF);
257 /* Initialize ICW1 for master, interval 8, edge-triggered mode with ICW4 */
258 Icw1
.NeedIcw4
= TRUE
;
259 Icw1
.InterruptMode
= EdgeTriggered
;
260 Icw1
.OperatingMode
= Cascade
;
261 Icw1
.Interval
= Interval8
;
263 Icw1
.InterruptVectorAddress
= 0; /* This is only used in MCS80/85 mode */
264 __outbyte(PIC2_CONTROL_PORT
, Icw1
.Bits
);
266 /* Set interrupt vector base */
267 Icw2
.Bits
= PRIMARY_VECTOR_BASE
+ 8;
268 __outbyte(PIC2_DATA_PORT
, Icw2
.Bits
);
273 __outbyte(PIC2_DATA_PORT
, Icw3
.Bits
);
275 /* Enable 8086 mode, non-automatic EOI, non-buffered mode, non special fully nested mode */
277 Icw4
.SystemMode
= New8086Mode
;
278 Icw4
.EoiMode
= NormalEoi
;
279 Icw4
.BufferedMode
= NonBuffered
;
280 Icw4
.SpecialFullyNestedMode
= FALSE
;
281 __outbyte(PIC2_DATA_PORT
, Icw4
.Bits
);
283 /* Mask all interrupts */
284 __outbyte(PIC2_DATA_PORT
, 0xFF);
286 /* Read EISA Edge/Level Register for master and slave */
287 Elcr
.Bits
= (__inbyte(EISA_ELCR_SLAVE
) << 8) | __inbyte(EISA_ELCR_MASTER
);
289 /* IRQs 0, 1, 2, 8, and 13 are system-reserved and must be edge */
290 if (!(Elcr
.Master
.Irq0Level
) && !(Elcr
.Master
.Irq1Level
) && !(Elcr
.Master
.Irq2Level
) &&
291 !(Elcr
.Slave
.Irq8Level
) && !(Elcr
.Slave
.Irq13Level
))
293 /* ELCR is as it's supposed to be, save it */
294 HalpEisaELCR
= Elcr
.Bits
;
295 DPRINT1("HAL Detected EISA Interrupt Controller (ELCR: %lx)\n", HalpEisaELCR
);
297 /* Scan for level interrupts */
298 for (i
= 1, j
= 0; j
< 16; i
<<= 1, j
++)
300 /* Warn the user ReactOS does not (and has never) supported this */
301 if (HalpEisaELCR
& i
) DPRINT1("WARNING: IRQ %d is SHARED and LEVEL-SENSITIVE. This is unsupported!\n", j
);
305 /* Restore interrupt state */
306 if (EnableInterrupts
) EFlags
|= EFLAGS_INTERRUPT_MASK
;
307 __writeeflags(EFlags
);
310 /* IRQL MANAGEMENT ************************************************************/
317 KeGetCurrentIrql(VOID
)
319 /* Return the IRQL */
320 return KeGetPcr()->Irql
;
328 KeRaiseIrqlToDpcLevel(VOID
)
330 PKPCR Pcr
= KeGetPcr();
333 /* Save and update IRQL */
334 CurrentIrql
= Pcr
->Irql
;
335 Pcr
->Irql
= DISPATCH_LEVEL
;
338 /* Validate correct raise */
339 if (CurrentIrql
> DISPATCH_LEVEL
)
342 KeBugCheckEx(IRQL_NOT_GREATER_OR_EQUAL
,
350 /* Return the previous value */
359 KeRaiseIrqlToSynchLevel(VOID
)
361 PKPCR Pcr
= KeGetPcr();
364 /* Save and update IRQL */
365 CurrentIrql
= Pcr
->Irql
;
366 Pcr
->Irql
= SYNCH_LEVEL
;
369 /* Validate correct raise */
370 if (CurrentIrql
> SYNCH_LEVEL
)
373 KeBugCheckEx(IRQL_NOT_GREATER_OR_EQUAL
,
381 /* Return the previous value */
390 KfRaiseIrql(IN KIRQL NewIrql
)
392 PKPCR Pcr
= KeGetPcr();
397 /* Read current IRQL */
398 CurrentIrql
= Pcr
->Irql
;
401 /* Validate correct raise */
402 if (CurrentIrql
> NewIrql
)
405 Pcr
->Irql
= PASSIVE_LEVEL
;
406 KeBugCheckEx(IRQL_NOT_GREATER_OR_EQUAL
,
414 /* Check if new IRQL affects hardware state */
415 if (NewIrql
> DISPATCH_LEVEL
)
417 /* Save current interrupt state and disable interrupts */
418 EFlags
= __readeflags();
421 /* Update the IRQL */
424 /* Set new PIC mask */
425 Mask
.Both
= KiI8259MaskTable
[NewIrql
] | Pcr
->IDR
;
426 __outbyte(PIC1_DATA_PORT
, Mask
.Master
);
427 __outbyte(PIC2_DATA_PORT
, Mask
.Slave
);
429 /* Restore interrupt state */
430 __writeeflags(EFlags
);
438 /* Return old IRQL */
448 KfLowerIrql(IN KIRQL OldIrql
)
452 PKPCR Pcr
= KeGetPcr();
456 /* Validate correct lower */
457 if (OldIrql
> Pcr
->Irql
)
460 KIRQL CurrentIrql
= Pcr
->Irql
;
461 Pcr
->Irql
= HIGH_LEVEL
;
462 KeBugCheckEx(IRQL_NOT_LESS_OR_EQUAL
,
470 /* Save EFlags and disable interrupts */
471 EFlags
= __readeflags();
474 /* Check if currentl IRQL affects hardware state */
475 if (Pcr
->Irql
> DISPATCH_LEVEL
)
477 /* Set new PIC mask */
478 Mask
.Both
= KiI8259MaskTable
[OldIrql
] | Pcr
->IDR
;
479 __outbyte(PIC1_DATA_PORT
, Mask
.Master
);
480 __outbyte(PIC2_DATA_PORT
, Mask
.Slave
);
486 /* Check for pending software interrupts and compare with current IRQL */
487 PendingIrql
= SWInterruptLookUpTable
[Pcr
->IRR
];
488 if (PendingIrql
> OldIrql
) SWInterruptHandlerTable
[PendingIrql
]();
490 /* Restore interrupt state */
491 __writeeflags(EFlags
);
494 /* SOFTWARE INTERRUPTS ********************************************************/
501 HalRequestSoftwareInterrupt(IN KIRQL Irql
)
504 PKPCR Pcr
= KeGetPcr();
507 /* Save EFlags and disable interrupts */
508 EFlags
= __readeflags();
511 /* Mask out the requested bit */
512 Pcr
->IRR
|= (1 << Irql
);
514 /* Check for pending software interrupts and compare with current IRQL */
515 PendingIrql
= SWInterruptLookUpTable
[Pcr
->IRR
& 3];
516 if (PendingIrql
> Pcr
->Irql
) SWInterruptHandlerTable
[PendingIrql
]();
518 /* Restore interrupt state */
519 __writeeflags(EFlags
);
527 HalClearSoftwareInterrupt(IN KIRQL Irql
)
529 /* Mask out the requested bit */
530 KeGetPcr()->IRR
&= ~(1 << Irql
);
535 HalpEndSoftwareInterrupt(IN KIRQL OldIrql
)
538 PKPCR Pcr
= KeGetPcr();
541 /* Check if currentl IRQL affects hardware state */
542 if (Pcr
->Irql
> DISPATCH_LEVEL
)
544 /* Set new PIC mask */
545 Mask
.Both
= KiI8259MaskTable
[OldIrql
] | Pcr
->IDR
;
546 __outbyte(PIC1_DATA_PORT
, Mask
.Master
);
547 __outbyte(PIC2_DATA_PORT
, Mask
.Slave
);
553 /* Check for pending software interrupts and compare with current IRQL */
554 PendingIrql
= SWInterruptLookUpTable
[Pcr
->IRR
];
556 /* NOTE: We can do better! We need to support "jumping" a frame for nested cases! */
557 if (PendingIrql
> OldIrql
) SWInterruptHandlerTable
[PendingIrql
]();
560 /* INTERRUPT DISMISSAL FUNCTIONS **********************************************/
564 _HalpDismissIrqGeneric(IN KIRQL Irql
,
571 PKPCR Pcr
= KeGetPcr();
573 /* First save current IRQL and compare it to the requested one */
574 CurrentIrql
= Pcr
->Irql
;
576 /* Set the new IRQL and return the current one */
578 *OldIrql
= CurrentIrql
;
580 /* Set new PIC mask */
581 Mask
.Both
= KiI8259MaskTable
[Irql
] | Pcr
->IDR
;
582 __outbyte(PIC1_DATA_PORT
, Mask
.Master
);
583 __outbyte(PIC2_DATA_PORT
, Mask
.Slave
);
585 /* Prepare OCW2 for EOI */
587 Ocw2
.EoiMode
= SpecificEoi
;
589 /* Check which PIC needs the EOI */
592 /* Send the EOI for the IRQ */
593 __outbyte(PIC2_CONTROL_PORT
, Ocw2
.Bits
| (Irq
- 8));
595 /* Send the EOI for IRQ2 on the master because this was cascaded */
596 __outbyte(PIC1_CONTROL_PORT
, Ocw2
.Bits
| 2);
600 /* Send the EOI for the IRQ */
601 __outbyte(PIC1_CONTROL_PORT
, Ocw2
.Bits
| Irq
);
604 /* Enable interrupts and return success */
610 __attribute__((regparm(3)))
611 HalpDismissIrqGeneric(IN KIRQL Irql
,
615 /* Run the inline code */
616 return _HalpDismissIrqGeneric(Irql
, Irq
, OldIrql
);
620 __attribute__((regparm(3)))
621 HalpDismissIrq15(IN KIRQL Irql
,
629 /* Request the ISR */
631 Ocw3
.Sbo
= 1; /* This encodes an OCW3 vs. an OCW2 */
632 Ocw3
.ReadRequest
= ReadIsr
;
633 __outbyte(PIC2_CONTROL_PORT
, Ocw3
.Bits
);
636 Isr
.Bits
= __inbyte(PIC2_CONTROL_PORT
);
638 /* Is IRQ15 really active (this is IR7) */
639 if (Isr
.Irq7
== FALSE
)
641 /* It isn't, so we have to EOI IRQ2 because this was cascaded */
643 Ocw2
.EoiMode
= SpecificEoi
;
644 __outbyte(PIC1_CONTROL_PORT
, Ocw2
.Bits
| 2);
646 /* And now fail since this was spurious */
650 /* Do normal interrupt dismiss */
651 return _HalpDismissIrqGeneric(Irql
, Irq
, OldIrql
);
656 __attribute__((regparm(3)))
657 HalpDismissIrq13(IN KIRQL Irql
,
661 /* Clear the FPU busy latch */
664 /* Do normal interrupt dismiss */
665 return _HalpDismissIrqGeneric(Irql
, Irq
, OldIrql
);
669 __attribute__((regparm(3)))
670 HalpDismissIrq07(IN KIRQL Irql
,
677 /* Request the ISR */
680 Ocw3
.ReadRequest
= ReadIsr
;
681 __outbyte(PIC1_CONTROL_PORT
, Ocw3
.Bits
);
684 Isr
.Bits
= __inbyte(PIC1_CONTROL_PORT
);
686 /* Is IRQ 7 really active? If it isn't, this is spurious so fail */
687 if (Isr
.Irq7
== FALSE
) return FALSE
;
689 /* Do normal interrupt dismiss */
690 return _HalpDismissIrqGeneric(Irql
, Irq
, OldIrql
);
693 /* SYSTEM INTERRUPTS **********************************************************/
700 HalEnableSystemInterrupt(IN UCHAR Vector
,
702 IN KINTERRUPT_MODE InterruptMode
)
705 PKPCR Pcr
= KeGetPcr();
708 /* Validate the IRQ */
709 Irq
= Vector
- PRIMARY_VECTOR_BASE
;
710 if (Irq
>= CLOCK2_LEVEL
) return FALSE
;
713 /* Check if there is a PCI IRQ Routing Miniport Driver */
714 if (HalpIrqMiniportInitialized
)
721 /* Disable interrupts */
724 /* Update software IDR */
725 Pcr
->IDR
&= ~(1 << Irq
);
727 /* Set new PIC mask */
728 PicMask
.Both
= KiI8259MaskTable
[Pcr
->Irql
] | Pcr
->IDR
;
729 __outbyte(PIC1_DATA_PORT
, PicMask
.Master
);
730 __outbyte(PIC2_DATA_PORT
, PicMask
.Slave
);
732 /* Enable interrupts and exit */
742 HalDisableSystemInterrupt(IN UCHAR Vector
,
748 /* Compute new combined IRQ mask */
749 IrqMask
= 1 << (Vector
- PRIMARY_VECTOR_BASE
);
751 /* Disable interrupts */
754 /* Update software IDR */
755 KeGetPcr()->IDR
|= IrqMask
;
757 /* Read current interrupt mask */
758 PicMask
.Master
= __inbyte(PIC1_DATA_PORT
);
759 PicMask
.Slave
= __inbyte(PIC2_DATA_PORT
);
761 /* Add the new disabled interrupt */
762 PicMask
.Both
|= IrqMask
;
764 /* Write new interrupt mask */
765 __outbyte(PIC1_DATA_PORT
, PicMask
.Master
);
766 __outbyte(PIC2_DATA_PORT
, PicMask
.Slave
);
768 /* Bring interrupts back */
777 HalBeginSystemInterrupt(IN KIRQL Irql
,
783 /* Get the IRQ and call the proper routine to handle it */
784 Irq
= Vector
- PRIMARY_VECTOR_BASE
;
785 return HalpSpecialDismissTable
[Irq
](Irql
, Irq
, OldIrql
);
793 HalEndSystemInterrupt(IN KIRQL OldIrql
,
797 PKPCR Pcr
= KeGetPcr();
800 /* Check if currentl IRQL affects hardware state */
801 if (Pcr
->Irql
> DISPATCH_LEVEL
)
803 /* Set new PIC mask */
804 Mask
.Both
= KiI8259MaskTable
[OldIrql
] | Pcr
->IDR
;
805 __outbyte(PIC1_DATA_PORT
, Mask
.Master
);
806 __outbyte(PIC2_DATA_PORT
, Mask
.Slave
);
812 /* Check for pending software interrupts and compare with current IRQL */
813 PendingIrql
= SWInterruptLookUpTable
[Pcr
->IRR
];
814 if (PendingIrql
> OldIrql
) SWInterruptHandlerTable
[PendingIrql
]();
817 /* SOFTWARE INTERRUPT TRAPS ***************************************************/
821 HalpApcInterruptHandler(IN PKTRAP_FRAME TrapFrame
)
824 PKPCR Pcr
= KeGetPcr();
826 /* Set up a fake INT Stack */
827 TrapFrame
->EFlags
= __readeflags();
828 TrapFrame
->SegCs
= KGDT_R0_CODE
;
829 TrapFrame
->Eip
= TrapFrame
->Eax
;
831 /* Build the trap frame */
832 KiEnterInterruptTrap(TrapFrame
);
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 HalpEndSoftwareInterrupt(CurrentIrql
);
852 /* Exit the interrupt */
853 KiEoiHelper(TrapFrame
);
858 HalpDispatchInterruptHandler(IN PKTRAP_FRAME TrapFrame
)
861 PKPCR Pcr
= KeGetPcr();
863 /* Set up a fake INT Stack */
864 TrapFrame
->EFlags
= __readeflags();
865 TrapFrame
->SegCs
= KGDT_R0_CODE
;
866 TrapFrame
->Eip
= TrapFrame
->Eax
;
868 /* Build the trap frame */
869 KiEnterInterruptTrap(TrapFrame
);
871 /* Save the current IRQL and update it */
872 CurrentIrql
= Pcr
->Irql
;
873 Pcr
->Irql
= DISPATCH_LEVEL
;
875 /* Remove DPC from IRR */
876 Pcr
->IRR
&= ~(1 << DISPATCH_LEVEL
);
878 /* Enable interrupts and call the kernel's DPC interrupt handler */
880 KiDispatchInterrupt();
882 /* Disable interrupts and end the interrupt */
884 HalpEndSoftwareInterrupt(CurrentIrql
);
886 /* Exit the interrupt */
887 KiEoiHelper(TrapFrame
);
890 KiTrap(HalpApcInterrupt
, KI_SOFTWARE_TRAP
);
891 KiTrap(HalpDispatchInterrupt
, KI_SOFTWARE_TRAP
);