3e1419ed401c8adc5878cc92a1a9bbafc866481a
[reactos.git] / reactos / hal / halx86 / generic / pic.c
1 /*
2 * PROJECT: ReactOS HAL
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
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include <hal.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 /* GLOBALS ********************************************************************/
16
17 /*
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.
21 *
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.
24 *
25 * The other thing this table does is special case IRQ7, IRQ13 and IRQ15:
26 *
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).
36 *
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.
41 *
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
44 * IRQ15!
45 *
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.
48 */
49 PHAL_DISMISS_INTERRUPT HalpSpecialDismissTable[16] =
50 {
51 HalpDismissIrqGeneric,
52 HalpDismissIrqGeneric,
53 HalpDismissIrqGeneric,
54 HalpDismissIrqGeneric,
55 HalpDismissIrqGeneric,
56 HalpDismissIrqGeneric,
57 HalpDismissIrqGeneric,
58 HalpDismissIrq07,
59 HalpDismissIrqGeneric,
60 HalpDismissIrqGeneric,
61 HalpDismissIrqGeneric,
62 HalpDismissIrqGeneric,
63 HalpDismissIrqGeneric,
64 HalpDismissIrq13,
65 HalpDismissIrqGeneric,
66 HalpDismissIrq15
67 };
68
69 /* This table contains the static x86 PIC mapping between IRQLs and IRQs */
70 ULONG KiI8259MaskTable[32] =
71 {
72 #ifdef __GNUC__
73 #if __GNUC__ * 100 + __GNUC_MINOR__ >= 404
74 /*
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
77 */
78 0b00000000000000000000000000000000, /* IRQL 0 */
79 0b00000000000000000000000000000000, /* IRQL 1 */
80 0b00000000000000000000000000000000, /* IRQL 2 */
81 0b00000000000000000000000000000000, /* IRQL 3 */
82
83 /*
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.
87 */
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 */
96
97 /*
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
100 * IRQL sense.
101 */
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 */
110
111 /*
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.
118 */
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 */
127
128 /*
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.
136 */
137 0b11111111111111111111111111111011, /* IRQL 28 */
138
139 /*
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.
146 */
147 0b11111111111111111111111111111011, /* IRQL 29 */
148 0b11111111111111111111111111111011, /* IRQL 30 */
149 0b11111111111111111111111111111011 /* IRQL 31 */
150 #else
151 0, /* IRQL 0 */
152 0, /* IRQL 1 */
153 0, /* IRQL 2 */
154 0, /* IRQL 3 */
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 */
183 #endif
184 #endif
185 };
186
187 /* Denotes minimum required IRQL before we can process pending SW interrupts */
188 KIRQL SWInterruptLookUpTable[8] =
189 {
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 */
198 };
199
200 /* Handlers for pending software interrupts */
201 PHAL_SW_INTERRUPT_HANDLER SWInterruptHandlerTable[3] =
202 {
203 KiUnexpectedInterrupt,
204 HalpApcInterrupt,
205 HalpDispatchInterrupt
206 };
207
208 USHORT HalpEisaELCR;
209
210 /* FUNCTIONS ******************************************************************/
211
212 VOID
213 NTAPI
214 HalpInitializePICs(IN BOOLEAN EnableInterrupts)
215 {
216 ULONG EFlags;
217 I8259_ICW1 Icw1;
218 I8259_ICW2 Icw2;
219 I8259_ICW3 Icw3;
220 I8259_ICW4 Icw4;
221 EISA_ELCR Elcr;
222 ULONG i, j;
223
224 /* Save EFlags and disable interrupts */
225 EFlags = __readeflags();
226 _disable();
227
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;
233 Icw1.Init = TRUE;
234 Icw1.InterruptVectorAddress = 0; /* This is only used in MCS80/85 mode */
235 __outbyte(PIC1_CONTROL_PORT, Icw1.Bits);
236
237 /* Set interrupt vector base */
238 Icw2.Bits = PRIMARY_VECTOR_BASE;
239 __outbyte(PIC1_DATA_PORT, Icw2.Bits);
240
241 /* Connect slave to IRQ 2 */
242 Icw3.Bits = 0;
243 Icw3.SlaveIrq2 = TRUE;
244 __outbyte(PIC1_DATA_PORT, Icw3.Bits);
245
246 /* Enable 8086 mode, non-automatic EOI, non-buffered mode, non special fully nested mode */
247 Icw4.Reserved = 0;
248 Icw4.SystemMode = New8086Mode;
249 Icw4.EoiMode = NormalEoi;
250 Icw4.BufferedMode = NonBuffered;
251 Icw4.SpecialFullyNestedMode = FALSE;
252 __outbyte(PIC1_DATA_PORT, Icw4.Bits);
253
254 /* Mask all interrupts */
255 __outbyte(PIC1_DATA_PORT, 0xFF);
256
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;
262 Icw1.Init = TRUE;
263 Icw1.InterruptVectorAddress = 0; /* This is only used in MCS80/85 mode */
264 __outbyte(PIC2_CONTROL_PORT, Icw1.Bits);
265
266 /* Set interrupt vector base */
267 Icw2.Bits = PRIMARY_VECTOR_BASE + 8;
268 __outbyte(PIC2_DATA_PORT, Icw2.Bits);
269
270 /* Slave ID */
271 Icw3.Bits = 0;
272 Icw3.SlaveId = 2;
273 __outbyte(PIC2_DATA_PORT, Icw3.Bits);
274
275 /* Enable 8086 mode, non-automatic EOI, non-buffered mode, non special fully nested mode */
276 Icw4.Reserved = 0;
277 Icw4.SystemMode = New8086Mode;
278 Icw4.EoiMode = NormalEoi;
279 Icw4.BufferedMode = NonBuffered;
280 Icw4.SpecialFullyNestedMode = FALSE;
281 __outbyte(PIC2_DATA_PORT, Icw4.Bits);
282
283 /* Mask all interrupts */
284 __outbyte(PIC2_DATA_PORT, 0xFF);
285
286 /* Read EISA Edge/Level Register for master and slave */
287 Elcr.Bits = (__inbyte(EISA_ELCR_SLAVE) << 8) | __inbyte(EISA_ELCR_MASTER);
288
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))
292 {
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);
296
297 /* Scan for level interrupts */
298 for (i = 1, j = 0; j < 16; i <<= 1, j++)
299 {
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);
302 }
303 }
304
305 /* Restore interrupt state */
306 if (EnableInterrupts) EFlags |= EFLAGS_INTERRUPT_MASK;
307 __writeeflags(EFlags);
308 }
309
310 /* IRQL MANAGEMENT ************************************************************/
311
312 /*
313 * @implemented
314 */
315 KIRQL
316 NTAPI
317 KeGetCurrentIrql(VOID)
318 {
319 /* Return the IRQL */
320 return KeGetPcr()->Irql;
321 }
322
323 /*
324 * @implemented
325 */
326 KIRQL
327 NTAPI
328 KeRaiseIrqlToDpcLevel(VOID)
329 {
330 PKPCR Pcr = KeGetPcr();
331 KIRQL CurrentIrql;
332
333 /* Save and update IRQL */
334 CurrentIrql = Pcr->Irql;
335 Pcr->Irql = DISPATCH_LEVEL;
336
337 #ifdef IRQL_DEBUG
338 /* Validate correct raise */
339 if (CurrentIrql > DISPATCH_LEVEL)
340 {
341 /* Crash system */
342 KeBugCheckEx(IRQL_NOT_GREATER_OR_EQUAL,
343 CurrentIrql,
344 DISPATCH_LEVEL,
345 0,
346 1);
347 }
348 #endif
349
350 /* Return the previous value */
351 return CurrentIrql;
352 }
353
354 /*
355 * @implemented
356 */
357 KIRQL
358 NTAPI
359 KeRaiseIrqlToSynchLevel(VOID)
360 {
361 PKPCR Pcr = KeGetPcr();
362 KIRQL CurrentIrql;
363
364 /* Save and update IRQL */
365 CurrentIrql = Pcr->Irql;
366 Pcr->Irql = SYNCH_LEVEL;
367
368 #ifdef IRQL_DEBUG
369 /* Validate correct raise */
370 if (CurrentIrql > SYNCH_LEVEL)
371 {
372 /* Crash system */
373 KeBugCheckEx(IRQL_NOT_GREATER_OR_EQUAL,
374 CurrentIrql,
375 SYNCH_LEVEL,
376 0,
377 1);
378 }
379 #endif
380
381 /* Return the previous value */
382 return CurrentIrql;
383 }
384
385 /*
386 * @implemented
387 */
388 KIRQL
389 FASTCALL
390 KfRaiseIrql(IN KIRQL NewIrql)
391 {
392 PKPCR Pcr = KeGetPcr();
393 ULONG EFlags;
394 KIRQL CurrentIrql;
395 PIC_MASK Mask;
396
397 /* Read current IRQL */
398 CurrentIrql = Pcr->Irql;
399
400 #ifdef IRQL_DEBUG
401 /* Validate correct raise */
402 if (CurrentIrql > NewIrql)
403 {
404 /* Crash system */
405 Pcr->Irql = PASSIVE_LEVEL;
406 KeBugCheckEx(IRQL_NOT_GREATER_OR_EQUAL,
407 CurrentIrql,
408 NewIrql,
409 0,
410 9);
411 }
412 #endif
413
414 /* Check if new IRQL affects hardware state */
415 if (NewIrql > DISPATCH_LEVEL)
416 {
417 /* Save current interrupt state and disable interrupts */
418 EFlags = __readeflags();
419 _disable();
420
421 /* Update the IRQL */
422 Pcr->Irql = NewIrql;
423
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);
428
429 /* Restore interrupt state */
430 __writeeflags(EFlags);
431 }
432 else
433 {
434 /* Set new IRQL */
435 Pcr->Irql = NewIrql;
436 }
437
438 /* Return old IRQL */
439 return CurrentIrql;
440 }
441
442
443 /*
444 * @implemented
445 */
446 VOID
447 FASTCALL
448 KfLowerIrql(IN KIRQL OldIrql)
449 {
450 ULONG EFlags;
451 KIRQL PendingIrql;
452 PKPCR Pcr = KeGetPcr();
453 PIC_MASK Mask;
454
455 #ifdef IRQL_DEBUG
456 /* Validate correct lower */
457 if (OldIrql > Pcr->Irql)
458 {
459 /* Crash system */
460 KIRQL CurrentIrql = Pcr->Irql;
461 Pcr->Irql = HIGH_LEVEL;
462 KeBugCheckEx(IRQL_NOT_LESS_OR_EQUAL,
463 CurrentIrql,
464 OldIrql,
465 0,
466 3);
467 }
468 #endif
469
470 /* Save EFlags and disable interrupts */
471 EFlags = __readeflags();
472 _disable();
473
474 /* Check if currentl IRQL affects hardware state */
475 if (Pcr->Irql > DISPATCH_LEVEL)
476 {
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);
481 }
482
483 /* Set old IRQL */
484 Pcr->Irql = OldIrql;
485
486 /* Check for pending software interrupts and compare with current IRQL */
487 PendingIrql = SWInterruptLookUpTable[Pcr->IRR];
488 if (PendingIrql > OldIrql) SWInterruptHandlerTable[PendingIrql]();
489
490 /* Restore interrupt state */
491 __writeeflags(EFlags);
492 }
493
494 /* SOFTWARE INTERRUPTS ********************************************************/
495
496 /*
497 * @implemented
498 */
499 VOID
500 FASTCALL
501 HalRequestSoftwareInterrupt(IN KIRQL Irql)
502 {
503 ULONG EFlags;
504 PKPCR Pcr = KeGetPcr();
505 KIRQL PendingIrql;
506
507 /* Save EFlags and disable interrupts */
508 EFlags = __readeflags();
509 _disable();
510
511 /* Mask out the requested bit */
512 Pcr->IRR |= (1 << Irql);
513
514 /* Check for pending software interrupts and compare with current IRQL */
515 PendingIrql = SWInterruptLookUpTable[Pcr->IRR & 3];
516 if (PendingIrql > Pcr->Irql) SWInterruptHandlerTable[PendingIrql]();
517
518 /* Restore interrupt state */
519 __writeeflags(EFlags);
520 }
521
522 /*
523 * @implemented
524 */
525 VOID
526 FASTCALL
527 HalClearSoftwareInterrupt(IN KIRQL Irql)
528 {
529 /* Mask out the requested bit */
530 KeGetPcr()->IRR &= ~(1 << Irql);
531 }
532
533 VOID
534 NTAPI
535 HalpEndSoftwareInterrupt(IN KIRQL OldIrql)
536 {
537 KIRQL PendingIrql;
538 PKPCR Pcr = KeGetPcr();
539 PIC_MASK Mask;
540
541 /* Check if currentl IRQL affects hardware state */
542 if (Pcr->Irql > DISPATCH_LEVEL)
543 {
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);
548 }
549
550 /* Set old IRQL */
551 Pcr->Irql = OldIrql;
552
553 /* Check for pending software interrupts and compare with current IRQL */
554 PendingIrql = SWInterruptLookUpTable[Pcr->IRR];
555
556 /* NOTE: We can do better! We need to support "jumping" a frame for nested cases! */
557 if (PendingIrql > OldIrql) SWInterruptHandlerTable[PendingIrql]();
558 }
559
560 /* INTERRUPT DISMISSAL FUNCTIONS **********************************************/
561
562 BOOLEAN
563 FORCEINLINE
564 _HalpDismissIrqGeneric(IN KIRQL Irql,
565 IN ULONG Irq,
566 OUT PKIRQL OldIrql)
567 {
568 PIC_MASK Mask;
569 KIRQL CurrentIrql;
570 I8259_OCW2 Ocw2;
571 PKPCR Pcr = KeGetPcr();
572
573 /* First save current IRQL and compare it to the requested one */
574 CurrentIrql = Pcr->Irql;
575
576 /* Set the new IRQL and return the current one */
577 Pcr->Irql = Irql;
578 *OldIrql = CurrentIrql;
579
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);
584
585 /* Prepare OCW2 for EOI */
586 Ocw2.Bits = 0;
587 Ocw2.EoiMode = SpecificEoi;
588
589 /* Check which PIC needs the EOI */
590 if (Irq > 8)
591 {
592 /* Send the EOI for the IRQ */
593 __outbyte(PIC2_CONTROL_PORT, Ocw2.Bits | (Irq - 8));
594
595 /* Send the EOI for IRQ2 on the master because this was cascaded */
596 __outbyte(PIC1_CONTROL_PORT, Ocw2.Bits | 2);
597 }
598 else
599 {
600 /* Send the EOI for the IRQ */
601 __outbyte(PIC1_CONTROL_PORT, Ocw2.Bits | Irq);
602 }
603
604 /* Enable interrupts and return success */
605 _enable();
606 return TRUE;
607 }
608
609 BOOLEAN
610 __attribute__((regparm(3)))
611 HalpDismissIrqGeneric(IN KIRQL Irql,
612 IN ULONG Irq,
613 OUT PKIRQL OldIrql)
614 {
615 /* Run the inline code */
616 return _HalpDismissIrqGeneric(Irql, Irq, OldIrql);
617 }
618
619 BOOLEAN
620 __attribute__((regparm(3)))
621 HalpDismissIrq15(IN KIRQL Irql,
622 IN ULONG Irq,
623 OUT PKIRQL OldIrql)
624 {
625 I8259_OCW3 Ocw3;
626 I8259_OCW2 Ocw2;
627 I8259_ISR Isr;
628
629 /* Request the ISR */
630 Ocw3.Bits = 0;
631 Ocw3.Sbo = 1; /* This encodes an OCW3 vs. an OCW2 */
632 Ocw3.ReadRequest = ReadIsr;
633 __outbyte(PIC2_CONTROL_PORT, Ocw3.Bits);
634
635 /* Read the ISR */
636 Isr.Bits = __inbyte(PIC2_CONTROL_PORT);
637
638 /* Is IRQ15 really active (this is IR7) */
639 if (Isr.Irq7 == FALSE)
640 {
641 /* It isn't, so we have to EOI IRQ2 because this was cascaded */
642 Ocw2.Bits = 0;
643 Ocw2.EoiMode = SpecificEoi;
644 __outbyte(PIC1_CONTROL_PORT, Ocw2.Bits | 2);
645
646 /* And now fail since this was spurious */
647 return FALSE;
648 }
649
650 /* Do normal interrupt dismiss */
651 return _HalpDismissIrqGeneric(Irql, Irq, OldIrql);
652 }
653
654
655 BOOLEAN
656 __attribute__((regparm(3)))
657 HalpDismissIrq13(IN KIRQL Irql,
658 IN ULONG Irq,
659 OUT PKIRQL OldIrql)
660 {
661 /* Clear the FPU busy latch */
662 __outbyte(0xF0, 0);
663
664 /* Do normal interrupt dismiss */
665 return _HalpDismissIrqGeneric(Irql, Irq, OldIrql);
666 }
667
668 BOOLEAN
669 __attribute__((regparm(3)))
670 HalpDismissIrq07(IN KIRQL Irql,
671 IN ULONG Irq,
672 OUT PKIRQL OldIrql)
673 {
674 I8259_OCW3 Ocw3;
675 I8259_ISR Isr;
676
677 /* Request the ISR */
678 Ocw3.Bits = 0;
679 Ocw3.Sbo = 1;
680 Ocw3.ReadRequest = ReadIsr;
681 __outbyte(PIC1_CONTROL_PORT, Ocw3.Bits);
682
683 /* Read the ISR */
684 Isr.Bits = __inbyte(PIC1_CONTROL_PORT);
685
686 /* Is IRQ 7 really active? If it isn't, this is spurious so fail */
687 if (Isr.Irq7 == FALSE) return FALSE;
688
689 /* Do normal interrupt dismiss */
690 return _HalpDismissIrqGeneric(Irql, Irq, OldIrql);
691 }
692
693 /* SYSTEM INTERRUPTS **********************************************************/
694
695 /*
696 * @implemented
697 */
698 BOOLEAN
699 NTAPI
700 HalEnableSystemInterrupt(IN UCHAR Vector,
701 IN KIRQL Irql,
702 IN KINTERRUPT_MODE InterruptMode)
703 {
704 ULONG Irq;
705 PKPCR Pcr = KeGetPcr();
706 PIC_MASK PicMask;
707
708 /* Validate the IRQ */
709 Irq = Vector - PRIMARY_VECTOR_BASE;
710 if (Irq >= CLOCK2_LEVEL) return FALSE;
711
712 #ifdef PCI_IRQ_MP
713 /* Check if there is a PCI IRQ Routing Miniport Driver */
714 if (HalpIrqMiniportInitialized)
715 {
716 UNIMPLEMENTED;
717 while (TRUE);
718 }
719 #endif
720
721 /* Disable interrupts */
722 _disable();
723
724 /* Update software IDR */
725 Pcr->IDR &= ~(1 << Irq);
726
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);
731
732 /* Enable interrupts and exit */
733 _enable();
734 return TRUE;
735 }
736
737 /*
738 * @implemented
739 */
740 VOID
741 NTAPI
742 HalDisableSystemInterrupt(IN UCHAR Vector,
743 IN KIRQL Irql)
744 {
745 ULONG IrqMask;
746 PIC_MASK PicMask;
747
748 /* Compute new combined IRQ mask */
749 IrqMask = 1 << (Vector - PRIMARY_VECTOR_BASE);
750
751 /* Disable interrupts */
752 _disable();
753
754 /* Update software IDR */
755 KeGetPcr()->IDR |= IrqMask;
756
757 /* Read current interrupt mask */
758 PicMask.Master = __inbyte(PIC1_DATA_PORT);
759 PicMask.Slave = __inbyte(PIC2_DATA_PORT);
760
761 /* Add the new disabled interrupt */
762 PicMask.Both |= IrqMask;
763
764 /* Write new interrupt mask */
765 __outbyte(PIC1_DATA_PORT, PicMask.Master);
766 __outbyte(PIC2_DATA_PORT, PicMask.Slave);
767
768 /* Bring interrupts back */
769 _enable();
770 }
771
772 /*
773 * @implemented
774 */
775 BOOLEAN
776 NTAPI
777 HalBeginSystemInterrupt(IN KIRQL Irql,
778 IN UCHAR Vector,
779 OUT PKIRQL OldIrql)
780 {
781 ULONG Irq;
782
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);
786 }
787
788 /*
789 * @implemented
790 */
791 VOID
792 NTAPI
793 HalEndSystemInterrupt(IN KIRQL OldIrql,
794 IN UCHAR Vector)
795 {
796 KIRQL PendingIrql;
797 PKPCR Pcr = KeGetPcr();
798 PIC_MASK Mask;
799
800 /* Check if currentl IRQL affects hardware state */
801 if (Pcr->Irql > DISPATCH_LEVEL)
802 {
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);
807 }
808
809 /* Set old IRQL */
810 Pcr->Irql = OldIrql;
811
812 /* Check for pending software interrupts and compare with current IRQL */
813 PendingIrql = SWInterruptLookUpTable[Pcr->IRR];
814 if (PendingIrql > OldIrql) SWInterruptHandlerTable[PendingIrql]();
815 }
816
817 /* SOFTWARE INTERRUPT TRAPS ***************************************************/
818
819 VOID
820 FASTCALL
821 HalpApcInterruptHandler(IN PKTRAP_FRAME TrapFrame)
822 {
823 KIRQL CurrentIrql;
824 PKPCR Pcr = KeGetPcr();
825
826 /* Set up a fake INT Stack */
827 TrapFrame->EFlags = __readeflags();
828 TrapFrame->SegCs = KGDT_R0_CODE;
829 TrapFrame->Eip = TrapFrame->Eax;
830
831 /* Build the trap frame */
832 KiEnterInterruptTrap(TrapFrame);
833
834 /* Save the current IRQL and update it */
835 CurrentIrql = Pcr->Irql;
836 Pcr->Irql = APC_LEVEL;
837
838 /* Remove DPC from IRR */
839 Pcr->IRR &= ~(1 << APC_LEVEL);
840
841 /* Enable interrupts and call the kernel's APC interrupt handler */
842 _enable();
843 KiDeliverApc(((KiUserTrap(TrapFrame)) || (TrapFrame->EFlags & EFLAGS_V86_MASK)) ?
844 UserMode : KernelMode,
845 NULL,
846 TrapFrame);
847
848 /* Disable interrupts and end the interrupt */
849 _disable();
850 HalpEndSoftwareInterrupt(CurrentIrql);
851
852 /* Exit the interrupt */
853 KiEoiHelper(TrapFrame);
854 }
855
856 VOID
857 FASTCALL
858 HalpDispatchInterruptHandler(IN PKTRAP_FRAME TrapFrame)
859 {
860 KIRQL CurrentIrql;
861 PKPCR Pcr = KeGetPcr();
862
863 /* Set up a fake INT Stack */
864 TrapFrame->EFlags = __readeflags();
865 TrapFrame->SegCs = KGDT_R0_CODE;
866 TrapFrame->Eip = TrapFrame->Eax;
867
868 /* Build the trap frame */
869 KiEnterInterruptTrap(TrapFrame);
870
871 /* Save the current IRQL and update it */
872 CurrentIrql = Pcr->Irql;
873 Pcr->Irql = DISPATCH_LEVEL;
874
875 /* Remove DPC from IRR */
876 Pcr->IRR &= ~(1 << DISPATCH_LEVEL);
877
878 /* Enable interrupts and call the kernel's DPC interrupt handler */
879 _enable();
880 KiDispatchInterrupt();
881
882 /* Disable interrupts and end the interrupt */
883 _disable();
884 HalpEndSoftwareInterrupt(CurrentIrql);
885
886 /* Exit the interrupt */
887 KiEoiHelper(TrapFrame);
888 }
889
890 KiTrap(HalpApcInterrupt, KI_SOFTWARE_TRAP);
891 KiTrap(HalpDispatchInterrupt, KI_SOFTWARE_TRAP);