1 /*
2 * PROJECT: ReactOS HAL
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * PURPOSE: HAL PIC Management and Control Code
5 * PROGRAMMERS: ReactOS Portable Systems Group
6 */
7
8 /* INCLUDES *******************************************************************/
9
10 #include <hal.h>
11
12 #define NDEBUG
13 #include <debug.h>
14
15 VOID
16 NTAPI
17 HalpEndSoftwareInterrupt(IN KIRQL OldIrql,
18 IN PKTRAP_FRAME TrapFrame);
19
20 /* GLOBALS ********************************************************************/
21
22 #ifndef _MINIHAL_
23 /*
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.
27 *
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.
30 *
31 * The other thing this table does is special case IRQ7, IRQ13 and IRQ15:
32 *
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).
42 *
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.
47 *
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
50 * IRQ15!
51 *
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.
54 */
55 PHAL_DISMISS_INTERRUPT HalpSpecialDismissTable[16] =
56 {
57 HalpDismissIrqGeneric,
58 HalpDismissIrqGeneric,
59 HalpDismissIrqGeneric,
60 HalpDismissIrqGeneric,
61 HalpDismissIrqGeneric,
62 HalpDismissIrqGeneric,
63 HalpDismissIrqGeneric,
64 HalpDismissIrq07,
65 #if defined(SARCH_PC98)
66 HalpDismissIrq08,
67 #else
68 HalpDismissIrqGeneric,
69 #endif
70 HalpDismissIrqGeneric,
71 HalpDismissIrqGeneric,
72 HalpDismissIrqGeneric,
73 HalpDismissIrqGeneric,
74 #if defined(SARCH_PC98)
75 HalpDismissIrqGeneric,
76 #else
77 HalpDismissIrq13,
78 #endif
79 HalpDismissIrqGeneric,
80 HalpDismissIrq15
81 };
82
83 /*
84 * These are the level IRQ dismissal functions that get copied in the table
85 * above if the given IRQ is actually level triggered.
86 */
87 PHAL_DISMISS_INTERRUPT HalpSpecialDismissLevelTable[16] =
88 {
89 HalpDismissIrqLevel,
90 HalpDismissIrqLevel,
91 HalpDismissIrqLevel,
92 HalpDismissIrqLevel,
93 HalpDismissIrqLevel,
94 HalpDismissIrqLevel,
95 HalpDismissIrqLevel,
96 HalpDismissIrq07Level,
97 #if defined(SARCH_PC98)
98 HalpDismissIrq08Level,
99 #else
100 HalpDismissIrqLevel,
101 #endif
102 HalpDismissIrqLevel,
103 HalpDismissIrqLevel,
104 HalpDismissIrqLevel,
105 HalpDismissIrqLevel,
106 #if defined(SARCH_PC98)
107 HalpDismissIrqLevel,
108 #else
109 HalpDismissIrq13Level,
110 #endif
111 HalpDismissIrqLevel,
112 HalpDismissIrq15Level
113 };
114
115 /* This table contains the static x86 PIC mapping between IRQLs and IRQs */
116 extern ULONG KiI8259MaskTable[32];
117
118 /* This table indicates which IRQs, if pending, can preempt a given IRQL level */
119 extern ULONG FindHigherIrqlMask[32];
120
121 /* Denotes minimum required IRQL before we can process pending SW interrupts */
122 KIRQL SWInterruptLookUpTable[8] =
123 {
124 PASSIVE_LEVEL, /* IRR 0 */
125 PASSIVE_LEVEL, /* IRR 1 */
126 APC_LEVEL, /* IRR 2 */
127 APC_LEVEL, /* IRR 3 */
128 DISPATCH_LEVEL, /* IRR 4 */
129 DISPATCH_LEVEL, /* IRR 5 */
130 DISPATCH_LEVEL, /* IRR 6 */
131 DISPATCH_LEVEL /* IRR 7 */
132 };
133
134 #if defined(__GNUC__)
135
136 #define HalpDelayedHardwareInterrupt(x) \
137 VOID __cdecl HalpHardwareInterrupt##x(VOID); \
138 VOID \
139 __cdecl \
140 HalpHardwareInterrupt##x(VOID) \
141 { \
142 asm volatile ("int $%c0\n"::"i"(PRIMARY_VECTOR_BASE + x)); \
143 }
144
145 #elif defined(_MSC_VER)
146
147 #define HalpDelayedHardwareInterrupt(x) \
148 VOID __cdecl HalpHardwareInterrupt##x(VOID); \
149 VOID \
150 __cdecl \
151 HalpHardwareInterrupt##x(VOID) \
152 { \
153 __asm \
154 { \
155 int PRIMARY_VECTOR_BASE + x \
156 } \
157 }
158
159 #else
160 #error Unsupported compiler
161 #endif
162
163 /* Pending/delayed hardware interrupt handlers */
164 HalpDelayedHardwareInterrupt(0);
165 HalpDelayedHardwareInterrupt(1);
166 HalpDelayedHardwareInterrupt(2);
167 HalpDelayedHardwareInterrupt(3);
168 HalpDelayedHardwareInterrupt(4);
169 HalpDelayedHardwareInterrupt(5);
170 HalpDelayedHardwareInterrupt(6);
171 HalpDelayedHardwareInterrupt(7);
172 HalpDelayedHardwareInterrupt(8);
173 HalpDelayedHardwareInterrupt(9);
174 HalpDelayedHardwareInterrupt(10);
175 HalpDelayedHardwareInterrupt(11);
176 HalpDelayedHardwareInterrupt(12);
177 HalpDelayedHardwareInterrupt(13);
178 HalpDelayedHardwareInterrupt(14);
179 HalpDelayedHardwareInterrupt(15);
180
181 /* Handlers for pending interrupts */
182 PHAL_SW_INTERRUPT_HANDLER SWInterruptHandlerTable[20] =
183 {
184 (PHAL_SW_INTERRUPT_HANDLER)KiUnexpectedInterrupt,
185 HalpApcInterrupt,
186 HalpDispatchInterrupt,
187 (PHAL_SW_INTERRUPT_HANDLER)KiUnexpectedInterrupt,
188 HalpHardwareInterrupt0,
189 HalpHardwareInterrupt1,
190 HalpHardwareInterrupt2,
191 HalpHardwareInterrupt3,
192 HalpHardwareInterrupt4,
193 HalpHardwareInterrupt5,
194 HalpHardwareInterrupt6,
195 HalpHardwareInterrupt7,
196 HalpHardwareInterrupt8,
197 HalpHardwareInterrupt9,
198 HalpHardwareInterrupt10,
199 HalpHardwareInterrupt11,
200 HalpHardwareInterrupt12,
201 HalpHardwareInterrupt13,
202 HalpHardwareInterrupt14,
203 HalpHardwareInterrupt15
204 };
205
206 /* Handlers for pending software interrupts when we already have a trap frame*/
207 PHAL_SW_INTERRUPT_HANDLER_2ND_ENTRY SWInterruptHandlerTable2[3] =
208 {
209 (PHAL_SW_INTERRUPT_HANDLER_2ND_ENTRY)(PVOID)KiUnexpectedInterrupt,
210 HalpApcInterrupt2ndEntry,
211 HalpDispatchInterrupt2ndEntry
212 };
213
214 LONG HalpEisaELCR;
215
216 /* FUNCTIONS ******************************************************************/
217
218 VOID
219 NTAPI
HalpInitializePICs(IN BOOLEAN EnableInterrupts)220 HalpInitializePICs(IN BOOLEAN EnableInterrupts)
221 {
222 ULONG EFlags;
223 EISA_ELCR Elcr;
224 ULONG i, j;
225 BOOLEAN ElcrFound;
226
227 /* Save EFlags and disable interrupts */
228 EFlags = __readeflags();
229 _disable();
230
231 /* Initialize and mask the PIC */
232 HalpInitializeLegacyPICs();
233
234 /* Read EISA Edge/Level Register for master and slave */
235 Elcr.Bits = (__inbyte(EISA_ELCR_SLAVE) << 8) | __inbyte(EISA_ELCR_MASTER);
236
237 #if defined(SARCH_PC98)
238 /* Force defaults when ELCR is not supported */
239 if (Elcr.Bits == 0xFFFF)
240 {
241 Elcr.Master.Irq0Level = 0;
242 Elcr.Master.Irq1Level = 0;
243 Elcr.Master.Irq7Level = 0;
244 Elcr.Slave.Irq8Level = 0;
245 }
246 ElcrFound = TRUE;
247 #else
248 /* IRQs 0, 1, 2, 8, and 13 are system-reserved and must be edge */
249 ElcrFound = (!(Elcr.Master.Irq0Level) && !(Elcr.Master.Irq1Level) && !(Elcr.Master.Irq2Level) &&
250 !(Elcr.Slave.Irq8Level) && !(Elcr.Slave.Irq13Level));
251 #endif
252
253 if (ElcrFound)
254 {
255 /* ELCR is as it's supposed to be, save it */
256 HalpEisaELCR = Elcr.Bits;
257
258 /* Scan for level interrupts */
259 for (i = 1, j = 0; j < 16; i <<= 1, j++)
260 {
261 if (HalpEisaELCR & i)
262 {
263 /* Switch handler to level */
264 SWInterruptHandlerTable[j + 4] = HalpHardwareInterruptLevel;
265
266 /* Switch dismiss to level */
267 HalpSpecialDismissTable[j] = HalpSpecialDismissLevelTable[j];
268 }
269 }
270 }
271
272 /* Report cascade IRQ usage */
273 HalpRegisterVector(IDT_INTERNAL,
274 PRIMARY_VECTOR_BASE + PIC_CASCADE_IRQ,
275 PRIMARY_VECTOR_BASE + PIC_CASCADE_IRQ,
276 HIGH_LEVEL);
277
278 /* Restore interrupt state */
279 if (EnableInterrupts) EFlags |= EFLAGS_INTERRUPT_MASK;
280 __writeeflags(EFlags);
281 }
282
283 UCHAR
284 FASTCALL
HalpIrqToVector(UCHAR Irq)285 HalpIrqToVector(UCHAR Irq)
286 {
287 return (PRIMARY_VECTOR_BASE + Irq);
288 }
289
290 UCHAR
291 FASTCALL
HalpVectorToIrq(UCHAR Vector)292 HalpVectorToIrq(UCHAR Vector)
293 {
294 return (Vector - PRIMARY_VECTOR_BASE);
295 }
296
297 KIRQL
298 FASTCALL
HalpVectorToIrql(UCHAR Vector)299 HalpVectorToIrql(UCHAR Vector)
300 {
301 return (PROFILE_LEVEL - (Vector - PRIMARY_VECTOR_BASE));
302 }
303
304 /* IRQL MANAGEMENT ************************************************************/
305
306 /*
307 * @implemented
308 */
309 KIRQL
310 NTAPI
KeGetCurrentIrql(VOID)311 KeGetCurrentIrql(VOID)
312 {
313 /* Return the IRQL */
314 return KeGetPcr()->Irql;
315 }
316
317 /*
318 * @implemented
319 */
320 KIRQL
321 NTAPI
KeRaiseIrqlToDpcLevel(VOID)322 KeRaiseIrqlToDpcLevel(VOID)
323 {
324 PKPCR Pcr = KeGetPcr();
325 KIRQL CurrentIrql;
326
327 /* Save and update IRQL */
328 CurrentIrql = Pcr->Irql;
329 Pcr->Irql = DISPATCH_LEVEL;
330
331 #if DBG
332 /* Validate correct raise */
333 if (CurrentIrql > DISPATCH_LEVEL) KeBugCheck(IRQL_NOT_GREATER_OR_EQUAL);
334 #endif
335
336 /* Return the previous value */
337 return CurrentIrql;
338 }
339
340 /*
341 * @implemented
342 */
343 KIRQL
344 NTAPI
KeRaiseIrqlToSynchLevel(VOID)345 KeRaiseIrqlToSynchLevel(VOID)
346 {
347 PKPCR Pcr = KeGetPcr();
348 KIRQL CurrentIrql;
349
350 /* Save and update IRQL */
351 CurrentIrql = Pcr->Irql;
352 Pcr->Irql = SYNCH_LEVEL;
353
354 #if DBG
355 /* Validate correct raise */
356 if (CurrentIrql > SYNCH_LEVEL)
357 {
358 /* Crash system */
359 KeBugCheckEx(IRQL_NOT_GREATER_OR_EQUAL,
360 CurrentIrql,
361 SYNCH_LEVEL,
362 0,
363 1);
364 }
365 #endif
366
367 /* Return the previous value */
368 return CurrentIrql;
369 }
370
371 /*
372 * @implemented
373 */
374 KIRQL
375 FASTCALL
KfRaiseIrql(IN KIRQL NewIrql)376 KfRaiseIrql(IN KIRQL NewIrql)
377 {
378 PKPCR Pcr = KeGetPcr();
379 KIRQL CurrentIrql;
380
381 /* Read current IRQL */
382 CurrentIrql = Pcr->Irql;
383
384 #if DBG
385 /* Validate correct raise */
386 if (CurrentIrql > NewIrql)
387 {
388 /* Crash system */
389 Pcr->Irql = PASSIVE_LEVEL;
390 KeBugCheck(IRQL_NOT_GREATER_OR_EQUAL);
391 }
392 #endif
393
394 /* Set new IRQL */
395 Pcr->Irql = NewIrql;
396
397 /* Return old IRQL */
398 return CurrentIrql;
399 }
400
401
402 /*
403 * @implemented
404 */
405 VOID
406 FASTCALL
KfLowerIrql(IN KIRQL OldIrql)407 KfLowerIrql(IN KIRQL OldIrql)
408 {
409 ULONG EFlags;
410 ULONG PendingIrql, PendingIrqlMask;
411 PKPCR Pcr = KeGetPcr();
412 PIC_MASK Mask;
413
414 #if DBG
415 /* Validate correct lower */
416 if (OldIrql > Pcr->Irql)
417 {
418 /* Crash system */
419 Pcr->Irql = HIGH_LEVEL;
420 KeBugCheck(IRQL_NOT_LESS_OR_EQUAL);
421 }
422 #endif
423
424 /* Save EFlags and disable interrupts */
425 EFlags = __readeflags();
426 _disable();
427
428 /* Set old IRQL */
429 Pcr->Irql = OldIrql;
430
431 /* Check for pending software interrupts and compare with current IRQL */
432 PendingIrqlMask = Pcr->IRR & FindHigherIrqlMask[OldIrql];
433 if (PendingIrqlMask)
434 {
435 /* Check if pending IRQL affects hardware state */
436 BitScanReverse(&PendingIrql, PendingIrqlMask);
437 if (PendingIrql > DISPATCH_LEVEL)
438 {
439 /* Set new PIC mask */
440 Mask.Both = Pcr->IDR & 0xFFFF;
441 __outbyte(PIC1_DATA_PORT, Mask.Master);
442 __outbyte(PIC2_DATA_PORT, Mask.Slave);
443
444 /* Clear IRR bit */
445 Pcr->IRR ^= (1 << PendingIrql);
446 }
447
448 /* Now handle pending interrupt */
449 SWInterruptHandlerTable[PendingIrql]();
450 }
451
452 /* Restore interrupt state */
453 __writeeflags(EFlags);
454 }
455
456 /* SOFTWARE INTERRUPTS ********************************************************/
457
458 /*
459 * @implemented
460 */
461 VOID
462 FASTCALL
HalRequestSoftwareInterrupt(IN KIRQL Irql)463 HalRequestSoftwareInterrupt(IN KIRQL Irql)
464 {
465 ULONG EFlags;
466 PKPCR Pcr = KeGetPcr();
467 KIRQL PendingIrql;
468
469 /* Save EFlags and disable interrupts */
470 EFlags = __readeflags();
471 _disable();
472
473 /* Mask out the requested bit */
474 Pcr->IRR |= (1 << Irql);
475
476 /* Check for pending software interrupts and compare with current IRQL */
477 PendingIrql = SWInterruptLookUpTable[Pcr->IRR & 3];
478 if (PendingIrql > Pcr->Irql) SWInterruptHandlerTable[PendingIrql]();
479
480 /* Restore interrupt state */
481 __writeeflags(EFlags);
482 }
483
484 /*
485 * @implemented
486 */
487 VOID
488 FASTCALL
HalClearSoftwareInterrupt(IN KIRQL Irql)489 HalClearSoftwareInterrupt(IN KIRQL Irql)
490 {
491 /* Mask out the requested bit */
492 KeGetPcr()->IRR &= ~(1 << Irql);
493 }
494
495 PHAL_SW_INTERRUPT_HANDLER_2ND_ENTRY
496 FASTCALL
HalpEndSoftwareInterrupt2(IN KIRQL OldIrql,IN PKTRAP_FRAME TrapFrame)497 HalpEndSoftwareInterrupt2(IN KIRQL OldIrql,
498 IN PKTRAP_FRAME TrapFrame)
499 {
500 ULONG PendingIrql, PendingIrqlMask, PendingIrqMask;
501 PKPCR Pcr = KeGetPcr();
502 PIC_MASK Mask;
503
504 UNREFERENCED_PARAMETER(TrapFrame);
505
506 /* Set old IRQL */
507 Pcr->Irql = OldIrql;
508
509 /* Loop checking for pending interrupts */
510 while (TRUE)
511 {
512 /* Check for pending software interrupts and compare with current IRQL */
513 PendingIrqlMask = Pcr->IRR & FindHigherIrqlMask[OldIrql];
514 if (!PendingIrqlMask) return NULL;
515
516 /* Check for in-service delayed interrupt */
517 if (Pcr->IrrActive & 0xFFFFFFF0) return NULL;
518
519 /* Check if pending IRQL affects hardware state */
520 BitScanReverse(&PendingIrql, PendingIrqlMask);
521 if (PendingIrql > DISPATCH_LEVEL)
522 {
523 /* Set new PIC mask */
524 Mask.Both = Pcr->IDR & 0xFFFF;
525 __outbyte(PIC1_DATA_PORT, Mask.Master);
526 __outbyte(PIC2_DATA_PORT, Mask.Slave);
527
528 /* Set active bit otherwise, and clear it from IRR */
529 PendingIrqMask = (1 << PendingIrql);
530 Pcr->IrrActive |= PendingIrqMask;
531 Pcr->IRR ^= PendingIrqMask;
532
533 /* Handle delayed hardware interrupt */
534 SWInterruptHandlerTable[PendingIrql]();
535
536 /* Handling complete */
537 Pcr->IrrActive ^= PendingIrqMask;
538 }
539 else
540 {
541 /* No need to loop checking for hardware interrupts */
542 return SWInterruptHandlerTable2[PendingIrql];
543 }
544 }
545
546 return NULL;
547 }
548
549 /* EDGE INTERRUPT DISMISSAL FUNCTIONS *****************************************/
550
551 FORCEINLINE
552 BOOLEAN
_HalpDismissIrqGeneric(IN KIRQL Irql,IN ULONG Irq,OUT PKIRQL OldIrql)553 _HalpDismissIrqGeneric(IN KIRQL Irql,
554 IN ULONG Irq,
555 OUT PKIRQL OldIrql)
556 {
557 PIC_MASK Mask;
558 KIRQL CurrentIrql;
559 I8259_OCW2 Ocw2;
560 PKPCR Pcr = KeGetPcr();
561
562 /* First save current IRQL and compare it to the requested one */
563 CurrentIrql = Pcr->Irql;
564
565 /* Check if this interrupt is really allowed to happen */
566 if (Irql > CurrentIrql)
567 {
568 /* Set the new IRQL and return the current one */
569 Pcr->Irql = Irql;
570 *OldIrql = CurrentIrql;
571
572 /* Prepare OCW2 for EOI */
573 Ocw2.Bits = 0;
574 Ocw2.EoiMode = SpecificEoi;
575
576 /* Check which PIC needs the EOI */
577 if (Irq >= 8)
578 {
579 #if defined(SARCH_PC98)
580 I8259_OCW3 Ocw3;
581 I8259_ISR Isr;
582
583 /* Send the EOI for the IRQ */
584 __outbyte(PIC2_CONTROL_PORT, Ocw2.Bits | ((Irq - 8) & 0xFF));
585
586 /* Request the ISR */
587 Ocw3.Bits = 0;
588 Ocw3.Sbo = 1;
589 Ocw3.ReadRequest = ReadIsr;
590 __outbyte(PIC2_CONTROL_PORT, Ocw3.Bits);
591
592 /* Read the ISR */
593 Isr.Bits = __inbyte(PIC2_CONTROL_PORT);
594
595 /* Check if the interrupt serviced was the only one from the slave PIC */
596 if (Isr.Bits == 0)
597 {
598 /* If ISR is empty, send the EOI for cascade IRQ on the master PIC */
599 __outbyte(PIC1_CONTROL_PORT, Ocw2.Bits | PIC_CASCADE_IRQ);
600 }
601 #else
602 /* Send the EOI for the IRQ */
603 __outbyte(PIC2_CONTROL_PORT, Ocw2.Bits | ((Irq - 8) & 0xFF));
604
605 /* Send the EOI for cascade IRQ on the master PIC */
606 __outbyte(PIC1_CONTROL_PORT, Ocw2.Bits | PIC_CASCADE_IRQ);
607 #endif
608 }
609 else
610 {
611 /* Send the EOI for the IRQ */
612 __outbyte(PIC1_CONTROL_PORT, Ocw2.Bits | (Irq & 0xFF));
613 }
614
615 /* Enable interrupts and return success */
616 _enable();
617 return TRUE;
618 }
619
620 /* Update the IRR so that we deliver this interrupt when the IRQL is proper */
621 Pcr->IRR |= (1 << (Irq + 4));
622
623 /* Set new PIC mask to real IRQL level, since the optimization is lost now */
624 Mask.Both = (KiI8259MaskTable[CurrentIrql] | Pcr->IDR) & 0xFFFF;
625 __outbyte(PIC1_DATA_PORT, Mask.Master);
626 __outbyte(PIC2_DATA_PORT, Mask.Slave);
627
628 /* Now lie and say this was spurious */
629 return FALSE;
630 }
631
632 BOOLEAN
633 NTAPI
HalpDismissIrqGeneric(IN KIRQL Irql,IN ULONG Irq,OUT PKIRQL OldIrql)634 HalpDismissIrqGeneric(IN KIRQL Irql,
635 IN ULONG Irq,
636 OUT PKIRQL OldIrql)
637 {
638 /* Run the inline code */
639 return _HalpDismissIrqGeneric(Irql, Irq, OldIrql);
640 }
641
642 BOOLEAN
643 NTAPI
HalpDismissIrq15(IN KIRQL Irql,IN ULONG Irq,OUT PKIRQL OldIrql)644 HalpDismissIrq15(IN KIRQL Irql,
645 IN ULONG Irq,
646 OUT PKIRQL OldIrql)
647 {
648 I8259_OCW3 Ocw3;
649 I8259_OCW2 Ocw2;
650 I8259_ISR Isr;
651
652 /* Request the ISR */
653 Ocw3.Bits = 0;
654 Ocw3.Sbo = 1; /* This encodes an OCW3 vs. an OCW2 */
655 Ocw3.ReadRequest = ReadIsr;
656 __outbyte(PIC2_CONTROL_PORT, Ocw3.Bits);
657
658 /* Read the ISR */
659 Isr.Bits = __inbyte(PIC2_CONTROL_PORT);
660
661 /* Is IRQ15 really active (this is IR7) */
662 if (Isr.Irq7 == FALSE)
663 {
664 /* It isn't, so we have to EOI cascade IRQ */
665 Ocw2.Bits = 0;
666 Ocw2.EoiMode = SpecificEoi;
667 __outbyte(PIC1_CONTROL_PORT, Ocw2.Bits | PIC_CASCADE_IRQ);
668
669 /* And now fail since this was spurious */
670 return FALSE;
671 }
672
673 /* Do normal interrupt dismiss */
674 return _HalpDismissIrqGeneric(Irql, Irq, OldIrql);
675 }
676
677 BOOLEAN
678 NTAPI
HalpDismissIrq13(IN KIRQL Irql,IN ULONG Irq,OUT PKIRQL OldIrql)679 HalpDismissIrq13(IN KIRQL Irql,
680 IN ULONG Irq,
681 OUT PKIRQL OldIrql)
682 {
683 /* Clear the FPU busy latch */
684 __outbyte(0xF0, 0);
685
686 /* Do normal interrupt dismiss */
687 return _HalpDismissIrqGeneric(Irql, Irq, OldIrql);
688 }
689
690 #if defined(SARCH_PC98)
691 BOOLEAN
692 NTAPI
HalpDismissIrq08(_In_ KIRQL Irql,_In_ ULONG Irq,_Out_ PKIRQL OldIrql)693 HalpDismissIrq08(
694 _In_ KIRQL Irql,
695 _In_ ULONG Irq,
696 _Out_ PKIRQL OldIrql)
697 {
698 /* Clear the FPU busy latch */
699 __outbyte(CPU_IO_o_FPU_BUSY_LATCH, 0);
700
701 /* Do normal interrupt dismiss */
702 return _HalpDismissIrqGeneric(Irql, Irq, OldIrql);
703 }
704 #endif
705
706 BOOLEAN
707 NTAPI
HalpDismissIrq07(IN KIRQL Irql,IN ULONG Irq,OUT PKIRQL OldIrql)708 HalpDismissIrq07(IN KIRQL Irql,
709 IN ULONG Irq,
710 OUT PKIRQL OldIrql)
711 {
712 I8259_OCW3 Ocw3;
713 I8259_ISR Isr;
714
715 /* Request the ISR */
716 Ocw3.Bits = 0;
717 Ocw3.Sbo = 1;
718 Ocw3.ReadRequest = ReadIsr;
719 __outbyte(PIC1_CONTROL_PORT, Ocw3.Bits);
720
721 /* Read the ISR */
722 Isr.Bits = __inbyte(PIC1_CONTROL_PORT);
723
724 /* Is IRQ 7 really active? If it isn't, this is spurious so fail */
725 if (Isr.Irq7 == FALSE) return FALSE;
726
727 /* Do normal interrupt dismiss */
728 return _HalpDismissIrqGeneric(Irql, Irq, OldIrql);
729 }
730
731 /* LEVEL INTERRUPT DISMISSAL FUNCTIONS ****************************************/
732
733 FORCEINLINE
734 BOOLEAN
_HalpDismissIrqLevel(IN KIRQL Irql,IN ULONG Irq,OUT PKIRQL OldIrql)735 _HalpDismissIrqLevel(IN KIRQL Irql,
736 IN ULONG Irq,
737 OUT PKIRQL OldIrql)
738 {
739 PIC_MASK Mask;
740 KIRQL CurrentIrql;
741 I8259_OCW2 Ocw2;
742 PKPCR Pcr = KeGetPcr();
743
744 /* Update the PIC */
745 Mask.Both = (KiI8259MaskTable[Irql] | Pcr->IDR) & 0xFFFF;
746 __outbyte(PIC1_DATA_PORT, Mask.Master);
747 __outbyte(PIC2_DATA_PORT, Mask.Slave);
748
749 /* Update the IRR so that we clear this interrupt when the IRQL is proper */
750 Pcr->IRR |= (1 << (Irq + 4));
751
752 /* Save current IRQL */
753 CurrentIrql = Pcr->Irql;
754
755 /* Prepare OCW2 for EOI */
756 Ocw2.Bits = 0;
757 Ocw2.EoiMode = SpecificEoi;
758
759 /* Check which PIC needs the EOI */
760 if (Irq >= 8)
761 {
762 #if defined(SARCH_PC98)
763 I8259_OCW3 Ocw3;
764 I8259_ISR Isr;
765
766 /* Send the EOI for the IRQ */
767 __outbyte(PIC2_CONTROL_PORT, Ocw2.Bits | ((Irq - 8) & 0xFF));
768
769 /* Request the ISR */
770 Ocw3.Bits = 0;
771 Ocw3.Sbo = 1;
772 Ocw3.ReadRequest = ReadIsr;
773 __outbyte(PIC2_CONTROL_PORT, Ocw3.Bits);
774
775 /* Read the ISR */
776 Isr.Bits = __inbyte(PIC2_CONTROL_PORT);
777
778 /* Check if the interrupt serviced was the only one from the slave PIC */
779 if (Isr.Bits == 0)
780 {
781 /* If ISR is empty, send the EOI for cascade IRQ on the master PIC */
782 __outbyte(PIC1_CONTROL_PORT, Ocw2.Bits | PIC_CASCADE_IRQ);
783 }
784 #else
785 /* Send the EOI for the IRQ */
786 __outbyte(PIC2_CONTROL_PORT, Ocw2.Bits | ((Irq - 8) & 0xFF));
787
788 /* Send the EOI for cascade IRQ on the master PIC */
789 __outbyte(PIC1_CONTROL_PORT, Ocw2.Bits | PIC_CASCADE_IRQ);
790 #endif
791 }
792 else
793 {
794 /* Send the EOI for the IRQ */
795 __outbyte(PIC1_CONTROL_PORT, Ocw2.Bits | (Irq & 0xFF));
796 }
797
798 /* Check if this interrupt should be allowed to happen */
799 if (Irql > CurrentIrql)
800 {
801 /* Set the new IRQL and return the current one */
802 Pcr->Irql = Irql;
803 *OldIrql = CurrentIrql;
804
805 /* Enable interrupts and return success */
806 _enable();
807 return TRUE;
808 }
809
810 /* Now lie and say this was spurious */
811 return FALSE;
812 }
813
814 BOOLEAN
815 NTAPI
HalpDismissIrqLevel(IN KIRQL Irql,IN ULONG Irq,OUT PKIRQL OldIrql)816 HalpDismissIrqLevel(IN KIRQL Irql,
817 IN ULONG Irq,
818 OUT PKIRQL OldIrql)
819 {
820 /* Run the inline code */
821 return _HalpDismissIrqLevel(Irql, Irq, OldIrql);
822 }
823
824 BOOLEAN
825 NTAPI
HalpDismissIrq15Level(IN KIRQL Irql,IN ULONG Irq,OUT PKIRQL OldIrql)826 HalpDismissIrq15Level(IN KIRQL Irql,
827 IN ULONG Irq,
828 OUT PKIRQL OldIrql)
829 {
830 I8259_OCW3 Ocw3;
831 I8259_OCW2 Ocw2;
832 I8259_ISR Isr;
833
834 /* Request the ISR */
835 Ocw3.Bits = 0;
836 Ocw3.Sbo = 1; /* This encodes an OCW3 vs. an OCW2 */
837 Ocw3.ReadRequest = ReadIsr;
838 __outbyte(PIC2_CONTROL_PORT, Ocw3.Bits);
839
840 /* Read the ISR */
841 Isr.Bits = __inbyte(PIC2_CONTROL_PORT);
842
843 /* Is IRQ15 really active (this is IR7) */
844 if (Isr.Irq7 == FALSE)
845 {
846 /* It isn't, so we have to EOI cascade IRQ */
847 Ocw2.Bits = 0;
848 Ocw2.EoiMode = SpecificEoi;
849 __outbyte(PIC1_CONTROL_PORT, Ocw2.Bits | PIC_CASCADE_IRQ);
850
851 /* And now fail since this was spurious */
852 return FALSE;
853 }
854
855 /* Do normal interrupt dismiss */
856 return _HalpDismissIrqLevel(Irql, Irq, OldIrql);
857 }
858
859 BOOLEAN
860 NTAPI
HalpDismissIrq13Level(IN KIRQL Irql,IN ULONG Irq,OUT PKIRQL OldIrql)861 HalpDismissIrq13Level(IN KIRQL Irql,
862 IN ULONG Irq,
863 OUT PKIRQL OldIrql)
864 {
865 /* Clear the FPU busy latch */
866 __outbyte(0xF0, 0);
867
868 /* Do normal interrupt dismiss */
869 return _HalpDismissIrqLevel(Irql, Irq, OldIrql);
870 }
871
872 #if defined(SARCH_PC98)
873 BOOLEAN
874 NTAPI
HalpDismissIrq08Level(_In_ KIRQL Irql,_In_ ULONG Irq,_Out_ PKIRQL OldIrql)875 HalpDismissIrq08Level(
876 _In_ KIRQL Irql,
877 _In_ ULONG Irq,
878 _Out_ PKIRQL OldIrql)
879 {
880 /* Clear the FPU busy latch */
881 __outbyte(CPU_IO_o_FPU_BUSY_LATCH, 0);
882
883 /* Do normal interrupt dismiss */
884 return _HalpDismissIrqLevel(Irql, Irq, OldIrql);
885 }
886 #endif
887
888 BOOLEAN
889 NTAPI
HalpDismissIrq07Level(IN KIRQL Irql,IN ULONG Irq,OUT PKIRQL OldIrql)890 HalpDismissIrq07Level(IN KIRQL Irql,
891 IN ULONG Irq,
892 OUT PKIRQL OldIrql)
893 {
894 I8259_OCW3 Ocw3;
895 I8259_ISR Isr;
896
897 /* Request the ISR */
898 Ocw3.Bits = 0;
899 Ocw3.Sbo = 1;
900 Ocw3.ReadRequest = ReadIsr;
901 __outbyte(PIC1_CONTROL_PORT, Ocw3.Bits);
902
903 /* Read the ISR */
904 Isr.Bits = __inbyte(PIC1_CONTROL_PORT);
905
906 /* Is IRQ 7 really active? If it isn't, this is spurious so fail */
907 if (Isr.Irq7 == FALSE) return FALSE;
908
909 /* Do normal interrupt dismiss */
910 return _HalpDismissIrqLevel(Irql, Irq, OldIrql);
911 }
912
913 PHAL_SW_INTERRUPT_HANDLER
914 __cdecl
HalpHardwareInterruptLevel2(VOID)915 HalpHardwareInterruptLevel2(VOID)
916 {
917 PKPCR Pcr = KeGetPcr();
918 ULONG PendingIrqlMask, PendingIrql;
919
920 /* Check for pending software interrupts and compare with current IRQL */
921 PendingIrqlMask = Pcr->IRR & FindHigherIrqlMask[Pcr->Irql];
922 if (PendingIrqlMask)
923 {
924 /* Check for in-service delayed interrupt */
925 if (Pcr->IrrActive & 0xFFFFFFF0) return NULL;
926
927 /* Check if pending IRQL affects hardware state */
928 BitScanReverse(&PendingIrql, PendingIrqlMask);
929
930 /* Clear IRR bit */
931 Pcr->IRR ^= (1 << PendingIrql);
932
933 /* Now handle pending interrupt */
934 return SWInterruptHandlerTable[PendingIrql];
935 }
936
937 return NULL;
938 }
939
940 /* SYSTEM INTERRUPTS **********************************************************/
941
942 /*
943 * @implemented
944 */
945 BOOLEAN
946 NTAPI
HalEnableSystemInterrupt(IN ULONG Vector,IN KIRQL Irql,IN KINTERRUPT_MODE InterruptMode)947 HalEnableSystemInterrupt(IN ULONG Vector,
948 IN KIRQL Irql,
949 IN KINTERRUPT_MODE InterruptMode)
950 {
951 ULONG Irq;
952 PKPCR Pcr = KeGetPcr();
953 PIC_MASK PicMask;
954
955 /* Validate the IRQ */
956 Irq = Vector - PRIMARY_VECTOR_BASE;
957 if (Irq >= CLOCK2_LEVEL) return FALSE;
958
959 /* Check for level interrupt */
960 if (InterruptMode == LevelSensitive)
961 {
962 /* Switch handler to level */
963 SWInterruptHandlerTable[Irq + 4] = HalpHardwareInterruptLevel;
964
965 /* Switch dismiss to level */
966 HalpSpecialDismissTable[Irq] = HalpSpecialDismissLevelTable[Irq];
967 }
968
969 /* Disable interrupts */
970 _disable();
971
972 /* Update software IDR */
973 Pcr->IDR &= ~(1 << Irq);
974
975 /* Set new PIC mask */
976 PicMask.Both = (KiI8259MaskTable[Pcr->Irql] | Pcr->IDR) & 0xFFFF;
977 __outbyte(PIC1_DATA_PORT, PicMask.Master);
978 __outbyte(PIC2_DATA_PORT, PicMask.Slave);
979
980 /* Enable interrupts and exit */
981 _enable();
982 return TRUE;
983 }
984
985 /*
986 * @implemented
987 */
988 VOID
989 NTAPI
HalDisableSystemInterrupt(IN ULONG Vector,IN KIRQL Irql)990 HalDisableSystemInterrupt(IN ULONG Vector,
991 IN KIRQL Irql)
992 {
993 ULONG IrqMask;
994 PIC_MASK PicMask;
995
996 /* Compute new combined IRQ mask */
997 IrqMask = 1 << (Vector - PRIMARY_VECTOR_BASE);
998
999 /* Disable interrupts */
1000 _disable();
1001
1002 /* Update software IDR */
1003 KeGetPcr()->IDR |= IrqMask;
1004
1005 /* Read current interrupt mask */
1006 PicMask.Master = __inbyte(PIC1_DATA_PORT);
1007 PicMask.Slave = __inbyte(PIC2_DATA_PORT);
1008
1009 /* Add the new disabled interrupt */
1010 PicMask.Both |= IrqMask;
1011
1012 /* Write new interrupt mask */
1013 __outbyte(PIC1_DATA_PORT, PicMask.Master);
1014 __outbyte(PIC2_DATA_PORT, PicMask.Slave);
1015
1016 /* Bring interrupts back */
1017 _enable();
1018 }
1019
1020 /*
1021 * @implemented
1022 */
1023 BOOLEAN
1024 NTAPI
HalBeginSystemInterrupt(IN KIRQL Irql,IN ULONG Vector,OUT PKIRQL OldIrql)1025 HalBeginSystemInterrupt(IN KIRQL Irql,
1026 IN ULONG Vector,
1027 OUT PKIRQL OldIrql)
1028 {
1029 ULONG Irq;
1030
1031 /* Get the IRQ and call the proper routine to handle it */
1032 Irq = Vector - PRIMARY_VECTOR_BASE;
1033 return HalpSpecialDismissTable[Irq](Irql, Irq, OldIrql);
1034 }
1035
1036 /*
1037 * @implemented
1038 */
1039 PHAL_SW_INTERRUPT_HANDLER_2ND_ENTRY
1040 FASTCALL
HalEndSystemInterrupt2(IN KIRQL OldIrql,IN PKTRAP_FRAME TrapFrame)1041 HalEndSystemInterrupt2(IN KIRQL OldIrql,
1042 IN PKTRAP_FRAME TrapFrame)
1043 {
1044 ULONG PendingIrql, PendingIrqlMask, PendingIrqMask;
1045 PKPCR Pcr = KeGetPcr();
1046 PIC_MASK Mask;
1047
1048 /* Set old IRQL */
1049 Pcr->Irql = OldIrql;
1050
1051 /* Check for pending software interrupts and compare with current IRQL */
1052 PendingIrqlMask = Pcr->IRR & FindHigherIrqlMask[OldIrql];
1053 if (PendingIrqlMask)
1054 {
1055 /* Check for in-service delayed interrupt */
1056 if (Pcr->IrrActive & 0xFFFFFFF0) return NULL;
1057
1058 /* Loop checking for pending interrupts */
1059 while (TRUE)
1060 {
1061 /* Check if pending IRQL affects hardware state */
1062 BitScanReverse(&PendingIrql, PendingIrqlMask);
1063 if (PendingIrql > DISPATCH_LEVEL)
1064 {
1065 /* Set new PIC mask */
1066 Mask.Both = Pcr->IDR & 0xFFFF;
1067 __outbyte(PIC1_DATA_PORT, Mask.Master);
1068 __outbyte(PIC2_DATA_PORT, Mask.Slave);
1069
1070 /* Now check if this specific interrupt is already in-service */
1071 PendingIrqMask = (1 << PendingIrql);
1072 if (Pcr->IrrActive & PendingIrqMask) return NULL;
1073
1074 /* Set active bit otherwise, and clear it from IRR */
1075 Pcr->IrrActive |= PendingIrqMask;
1076 Pcr->IRR ^= PendingIrqMask;
1077
1078 /* Handle delayed hardware interrupt */
1079 SWInterruptHandlerTable[PendingIrql]();
1080
1081 /* Handling complete */
1082 Pcr->IrrActive ^= PendingIrqMask;
1083
1084 /* Check if there's still interrupts pending */
1085 PendingIrqlMask = Pcr->IRR & FindHigherIrqlMask[Pcr->Irql];
1086 if (!PendingIrqlMask) break;
1087 }
1088 else
1089 {
1090 /* Now handle pending software interrupt */
1091 return SWInterruptHandlerTable2[PendingIrql];
1092 }
1093 }
1094 }
1095
1096 return NULL;
1097 }
1098
1099 /* SOFTWARE INTERRUPT TRAPS ***************************************************/
1100
1101 FORCEINLINE
1102 DECLSPEC_NORETURN
1103 VOID
_HalpApcInterruptHandler(IN PKTRAP_FRAME TrapFrame)1104 _HalpApcInterruptHandler(IN PKTRAP_FRAME TrapFrame)
1105 {
1106 KIRQL CurrentIrql;
1107 PKPCR Pcr = KeGetPcr();
1108
1109 /* Save the current IRQL and update it */
1110 CurrentIrql = Pcr->Irql;
1111 Pcr->Irql = APC_LEVEL;
1112
1113 /* Remove DPC from IRR */
1114 Pcr->IRR &= ~(1 << APC_LEVEL);
1115
1116 /* Enable interrupts and call the kernel's APC interrupt handler */
1117 _enable();
1118 KiDeliverApc(((KiUserTrap(TrapFrame)) || (TrapFrame->EFlags & EFLAGS_V86_MASK)) ?
1119 UserMode : KernelMode,
1120 NULL,
1121 TrapFrame);
1122
1123 /* Disable interrupts and end the interrupt */
1124 _disable();
1125 HalpEndSoftwareInterrupt(CurrentIrql, TrapFrame);
1126
1127 /* Exit the interrupt */
1128 KiEoiHelper(TrapFrame);
1129 }
1130
1131 DECLSPEC_NORETURN
1132 VOID
1133 FASTCALL
HalpApcInterrupt2ndEntry(IN PKTRAP_FRAME TrapFrame)1134 HalpApcInterrupt2ndEntry(IN PKTRAP_FRAME TrapFrame)
1135 {
1136 /* Do the work */
1137 _HalpApcInterruptHandler(TrapFrame);
1138 }
1139
1140 DECLSPEC_NORETURN
1141 VOID
1142 FASTCALL
HalpApcInterruptHandler(IN PKTRAP_FRAME TrapFrame)1143 HalpApcInterruptHandler(IN PKTRAP_FRAME TrapFrame)
1144 {
1145 /* Set up a fake INT Stack */
1146 TrapFrame->EFlags = __readeflags();
1147 TrapFrame->SegCs = KGDT_R0_CODE;
1148 TrapFrame->Eip = TrapFrame->Eax;
1149
1150 /* Build the trap frame */
1151 KiEnterInterruptTrap(TrapFrame);
1152
1153 /* Do the work */
1154 _HalpApcInterruptHandler(TrapFrame);
1155 }
1156
1157 FORCEINLINE
1158 KIRQL
_HalpDispatchInterruptHandler(VOID)1159 _HalpDispatchInterruptHandler(VOID)
1160 {
1161 KIRQL CurrentIrql;
1162 PKPCR Pcr = KeGetPcr();
1163
1164 /* Save the current IRQL and update it */
1165 CurrentIrql = Pcr->Irql;
1166 Pcr->Irql = DISPATCH_LEVEL;
1167
1168 /* Remove DPC from IRR */
1169 Pcr->IRR &= ~(1 << DISPATCH_LEVEL);
1170
1171 /* Enable interrupts and call the kernel's DPC interrupt handler */
1172 _enable();
1173 KiDispatchInterrupt();
1174 _disable();
1175
1176 /* Return IRQL */
1177 return CurrentIrql;
1178 }
1179
1180 DECLSPEC_NORETURN
1181 VOID
1182 FASTCALL
HalpDispatchInterrupt2ndEntry(IN PKTRAP_FRAME TrapFrame)1183 HalpDispatchInterrupt2ndEntry(IN PKTRAP_FRAME TrapFrame)
1184 {
1185 KIRQL CurrentIrql;
1186
1187 /* Do the work */
1188 CurrentIrql = _HalpDispatchInterruptHandler();
1189
1190 /* End the interrupt */
1191 HalpEndSoftwareInterrupt(CurrentIrql, TrapFrame);
1192
1193 /* Exit the interrupt */
1194 KiEoiHelper(TrapFrame);
1195 }
1196
1197 PHAL_SW_INTERRUPT_HANDLER
1198 __cdecl
HalpDispatchInterrupt2(VOID)1199 HalpDispatchInterrupt2(VOID)
1200 {
1201 ULONG PendingIrqlMask, PendingIrql;
1202 KIRQL OldIrql;
1203 PIC_MASK Mask;
1204 PKPCR Pcr = KeGetPcr();
1205
1206 /* Do the work */
1207 OldIrql = _HalpDispatchInterruptHandler();
1208
1209 /* Restore IRQL */
1210 Pcr->Irql = OldIrql;
1211
1212 /* Check for pending software interrupts and compare with current IRQL */
1213 PendingIrqlMask = Pcr->IRR & FindHigherIrqlMask[OldIrql];
1214 if (PendingIrqlMask)
1215 {
1216 /* Check if pending IRQL affects hardware state */
1217 BitScanReverse(&PendingIrql, PendingIrqlMask);
1218 if (PendingIrql > DISPATCH_LEVEL)
1219 {
1220 /* Set new PIC mask */
1221 Mask.Both = Pcr->IDR & 0xFFFF;
1222 __outbyte(PIC1_DATA_PORT, Mask.Master);
1223 __outbyte(PIC2_DATA_PORT, Mask.Slave);
1224
1225 /* Clear IRR bit */
1226 Pcr->IRR ^= (1 << PendingIrql);
1227 }
1228
1229 /* Now handle pending interrupt */
1230 return SWInterruptHandlerTable[PendingIrql];
1231 }
1232
1233 return NULL;
1234 }
1235
1236 ULONG
1237 NTAPI
HalpGetRootInterruptVector(IN ULONG BusInterruptLevel,IN ULONG BusInterruptVector,OUT PKIRQL Irql,OUT PKAFFINITY Affinity)1238 HalpGetRootInterruptVector(IN ULONG BusInterruptLevel,
1239 IN ULONG BusInterruptVector,
1240 OUT PKIRQL Irql,
1241 OUT PKAFFINITY Affinity)
1242 {
1243 UCHAR SystemVector;
1244
1245 /* Validate the IRQ */
1246 if (BusInterruptLevel > 23)
1247 {
1248 /* Invalid vector */
1249 DPRINT1("IRQ %lx is too high!\n", BusInterruptLevel);
1250 return 0;
1251 }
1252
1253 /* Get the system vector */
1254 SystemVector = HalpIrqToVector((UCHAR)BusInterruptLevel);
1255
1256 /* Return the IRQL and affinity */
1257 *Irql = HalpVectorToIrql(SystemVector);
1258 *Affinity = HalpDefaultInterruptAffinity;
1259 ASSERT(HalpDefaultInterruptAffinity);
1260
1261 /* Return the vector */
1262 return SystemVector;
1263 }
1264
1265 #else /* _MINIHAL_ */
1266
1267 KIRQL
1268 NTAPI
KeGetCurrentIrql(VOID)1269 KeGetCurrentIrql(VOID)
1270 {
1271 return PASSIVE_LEVEL;
1272 }
1273
1274 VOID
1275 FASTCALL
KfLowerIrql(IN KIRQL OldIrql)1276 KfLowerIrql(
1277 IN KIRQL OldIrql)
1278 {
1279 }
1280
1281 KIRQL
1282 FASTCALL
KfRaiseIrql(IN KIRQL NewIrql)1283 KfRaiseIrql(
1284 IN KIRQL NewIrql)
1285 {
1286 return NewIrql;
1287 }
1288
1289 #endif /* !_MINIHAL_ */
1290