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