[HALX86] Fix a Clang-Cl warning about KiUnexpectedInterrupt
[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 HalpDispatchInterrupt,
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)(PVOID)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 PHAL_SW_INTERRUPT_HANDLER
1019 __cdecl
1020 HalpHardwareInterruptLevel2(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 NULL;
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 return SWInterruptHandlerTable[PendingIrql];
1040 }
1041
1042 return NULL;
1043 }
1044
1045 /* SYSTEM INTERRUPTS **********************************************************/
1046
1047 /*
1048 * @implemented
1049 */
1050 BOOLEAN
1051 NTAPI
1052 HalEnableSystemInterrupt(IN ULONG Vector,
1053 IN KIRQL Irql,
1054 IN KINTERRUPT_MODE InterruptMode)
1055 {
1056 ULONG Irq;
1057 PKPCR Pcr = KeGetPcr();
1058 PIC_MASK PicMask;
1059
1060 /* Validate the IRQ */
1061 Irq = Vector - PRIMARY_VECTOR_BASE;
1062 if (Irq >= CLOCK2_LEVEL) return FALSE;
1063
1064 /* Check for level interrupt */
1065 if (InterruptMode == LevelSensitive)
1066 {
1067 /* Switch handler to level */
1068 SWInterruptHandlerTable[Irq + 4] = HalpHardwareInterruptLevel;
1069
1070 /* Switch dismiss to level */
1071 HalpSpecialDismissTable[Irq] = HalpSpecialDismissLevelTable[Irq];
1072 }
1073
1074 /* Disable interrupts */
1075 _disable();
1076
1077 /* Update software IDR */
1078 Pcr->IDR &= ~(1 << Irq);
1079
1080 /* Set new PIC mask */
1081 PicMask.Both = (KiI8259MaskTable[Pcr->Irql] | Pcr->IDR) & 0xFFFF;
1082 __outbyte(PIC1_DATA_PORT, PicMask.Master);
1083 __outbyte(PIC2_DATA_PORT, PicMask.Slave);
1084
1085 /* Enable interrupts and exit */
1086 _enable();
1087 return TRUE;
1088 }
1089
1090 /*
1091 * @implemented
1092 */
1093 VOID
1094 NTAPI
1095 HalDisableSystemInterrupt(IN ULONG Vector,
1096 IN KIRQL Irql)
1097 {
1098 ULONG IrqMask;
1099 PIC_MASK PicMask;
1100
1101 /* Compute new combined IRQ mask */
1102 IrqMask = 1 << (Vector - PRIMARY_VECTOR_BASE);
1103
1104 /* Disable interrupts */
1105 _disable();
1106
1107 /* Update software IDR */
1108 KeGetPcr()->IDR |= IrqMask;
1109
1110 /* Read current interrupt mask */
1111 PicMask.Master = __inbyte(PIC1_DATA_PORT);
1112 PicMask.Slave = __inbyte(PIC2_DATA_PORT);
1113
1114 /* Add the new disabled interrupt */
1115 PicMask.Both |= IrqMask;
1116
1117 /* Write new interrupt mask */
1118 __outbyte(PIC1_DATA_PORT, PicMask.Master);
1119 __outbyte(PIC2_DATA_PORT, PicMask.Slave);
1120
1121 /* Bring interrupts back */
1122 _enable();
1123 }
1124
1125 /*
1126 * @implemented
1127 */
1128 BOOLEAN
1129 NTAPI
1130 HalBeginSystemInterrupt(IN KIRQL Irql,
1131 IN ULONG Vector,
1132 OUT PKIRQL OldIrql)
1133 {
1134 ULONG Irq;
1135
1136 /* Get the IRQ and call the proper routine to handle it */
1137 Irq = Vector - PRIMARY_VECTOR_BASE;
1138 return HalpSpecialDismissTable[Irq](Irql, Irq, OldIrql);
1139 }
1140
1141 /*
1142 * @implemented
1143 */
1144 PHAL_SW_INTERRUPT_HANDLER_2ND_ENTRY
1145 FASTCALL
1146 HalEndSystemInterrupt2(IN KIRQL OldIrql,
1147 IN PKTRAP_FRAME TrapFrame)
1148 {
1149 ULONG PendingIrql, PendingIrqlMask, PendingIrqMask;
1150 PKPCR Pcr = KeGetPcr();
1151 PIC_MASK Mask;
1152
1153 /* Set old IRQL */
1154 Pcr->Irql = OldIrql;
1155
1156 /* Check for pending software interrupts and compare with current IRQL */
1157 PendingIrqlMask = Pcr->IRR & FindHigherIrqlMask[OldIrql];
1158 if (PendingIrqlMask)
1159 {
1160 /* Check for in-service delayed interrupt */
1161 if (Pcr->IrrActive & 0xFFFFFFF0) return NULL;
1162
1163 /* Loop checking for pending interrupts */
1164 while (TRUE)
1165 {
1166 /* Check if pending IRQL affects hardware state */
1167 BitScanReverse(&PendingIrql, PendingIrqlMask);
1168 if (PendingIrql > DISPATCH_LEVEL)
1169 {
1170 /* Set new PIC mask */
1171 Mask.Both = Pcr->IDR & 0xFFFF;
1172 __outbyte(PIC1_DATA_PORT, Mask.Master);
1173 __outbyte(PIC2_DATA_PORT, Mask.Slave);
1174
1175 /* Now check if this specific interrupt is already in-service */
1176 PendingIrqMask = (1 << PendingIrql);
1177 if (Pcr->IrrActive & PendingIrqMask) return NULL;
1178
1179 /* Set active bit otherwise, and clear it from IRR */
1180 Pcr->IrrActive |= PendingIrqMask;
1181 Pcr->IRR ^= PendingIrqMask;
1182
1183 /* Handle delayed hardware interrupt */
1184 SWInterruptHandlerTable[PendingIrql]();
1185
1186 /* Handling complete */
1187 Pcr->IrrActive ^= PendingIrqMask;
1188
1189 /* Check if there's still interrupts pending */
1190 PendingIrqlMask = Pcr->IRR & FindHigherIrqlMask[Pcr->Irql];
1191 if (!PendingIrqlMask) break;
1192 }
1193 else
1194 {
1195 /* Now handle pending software interrupt */
1196 return SWInterruptHandlerTable2[PendingIrql];
1197 }
1198 }
1199 }
1200
1201 return NULL;
1202 }
1203
1204 /* SOFTWARE INTERRUPT TRAPS ***************************************************/
1205
1206 FORCEINLINE
1207 DECLSPEC_NORETURN
1208 VOID
1209 _HalpApcInterruptHandler(IN PKTRAP_FRAME TrapFrame)
1210 {
1211 KIRQL CurrentIrql;
1212 PKPCR Pcr = KeGetPcr();
1213
1214 /* Save the current IRQL and update it */
1215 CurrentIrql = Pcr->Irql;
1216 Pcr->Irql = APC_LEVEL;
1217
1218 /* Remove DPC from IRR */
1219 Pcr->IRR &= ~(1 << APC_LEVEL);
1220
1221 /* Enable interrupts and call the kernel's APC interrupt handler */
1222 _enable();
1223 KiDeliverApc(((KiUserTrap(TrapFrame)) || (TrapFrame->EFlags & EFLAGS_V86_MASK)) ?
1224 UserMode : KernelMode,
1225 NULL,
1226 TrapFrame);
1227
1228 /* Disable interrupts and end the interrupt */
1229 _disable();
1230 HalpEndSoftwareInterrupt(CurrentIrql, TrapFrame);
1231
1232 /* Exit the interrupt */
1233 KiEoiHelper(TrapFrame);
1234 }
1235
1236 DECLSPEC_NORETURN
1237 VOID
1238 FASTCALL
1239 HalpApcInterrupt2ndEntry(IN PKTRAP_FRAME TrapFrame)
1240 {
1241 /* Do the work */
1242 _HalpApcInterruptHandler(TrapFrame);
1243 }
1244
1245 DECLSPEC_NORETURN
1246 VOID
1247 FASTCALL
1248 HalpApcInterruptHandler(IN PKTRAP_FRAME TrapFrame)
1249 {
1250 /* Set up a fake INT Stack */
1251 TrapFrame->EFlags = __readeflags();
1252 TrapFrame->SegCs = KGDT_R0_CODE;
1253 TrapFrame->Eip = TrapFrame->Eax;
1254
1255 /* Build the trap frame */
1256 KiEnterInterruptTrap(TrapFrame);
1257
1258 /* Do the work */
1259 _HalpApcInterruptHandler(TrapFrame);
1260 }
1261
1262 FORCEINLINE
1263 KIRQL
1264 _HalpDispatchInterruptHandler(VOID)
1265 {
1266 KIRQL CurrentIrql;
1267 PKPCR Pcr = KeGetPcr();
1268
1269 /* Save the current IRQL and update it */
1270 CurrentIrql = Pcr->Irql;
1271 Pcr->Irql = DISPATCH_LEVEL;
1272
1273 /* Remove DPC from IRR */
1274 Pcr->IRR &= ~(1 << DISPATCH_LEVEL);
1275
1276 /* Enable interrupts and call the kernel's DPC interrupt handler */
1277 _enable();
1278 KiDispatchInterrupt();
1279 _disable();
1280
1281 /* Return IRQL */
1282 return CurrentIrql;
1283 }
1284
1285 DECLSPEC_NORETURN
1286 VOID
1287 FASTCALL
1288 HalpDispatchInterrupt2ndEntry(IN PKTRAP_FRAME TrapFrame)
1289 {
1290 KIRQL CurrentIrql;
1291
1292 /* Do the work */
1293 CurrentIrql = _HalpDispatchInterruptHandler();
1294
1295 /* End the interrupt */
1296 HalpEndSoftwareInterrupt(CurrentIrql, TrapFrame);
1297
1298 /* Exit the interrupt */
1299 KiEoiHelper(TrapFrame);
1300 }
1301
1302 PHAL_SW_INTERRUPT_HANDLER
1303 __cdecl
1304 HalpDispatchInterrupt2(VOID)
1305 {
1306 ULONG PendingIrqlMask, PendingIrql;
1307 KIRQL OldIrql;
1308 PIC_MASK Mask;
1309 PKPCR Pcr = KeGetPcr();
1310
1311 /* Do the work */
1312 OldIrql = _HalpDispatchInterruptHandler();
1313
1314 /* Restore IRQL */
1315 Pcr->Irql = OldIrql;
1316
1317 /* Check for pending software interrupts and compare with current IRQL */
1318 PendingIrqlMask = Pcr->IRR & FindHigherIrqlMask[OldIrql];
1319 if (PendingIrqlMask)
1320 {
1321 /* Check if pending IRQL affects hardware state */
1322 BitScanReverse(&PendingIrql, PendingIrqlMask);
1323 if (PendingIrql > DISPATCH_LEVEL)
1324 {
1325 /* Set new PIC mask */
1326 Mask.Both = Pcr->IDR & 0xFFFF;
1327 __outbyte(PIC1_DATA_PORT, Mask.Master);
1328 __outbyte(PIC2_DATA_PORT, Mask.Slave);
1329
1330 /* Clear IRR bit */
1331 Pcr->IRR ^= (1 << PendingIrql);
1332 }
1333
1334 /* Now handle pending interrupt */
1335 return SWInterruptHandlerTable[PendingIrql];
1336 }
1337
1338 return NULL;
1339 }
1340
1341 #else
1342
1343 KIRQL
1344 NTAPI
1345 KeGetCurrentIrql(VOID)
1346 {
1347 return PASSIVE_LEVEL;
1348 }
1349
1350 VOID
1351 FASTCALL
1352 KfLowerIrql(
1353 IN KIRQL OldIrql)
1354 {
1355 }
1356
1357 KIRQL
1358 FASTCALL
1359 KfRaiseIrql(
1360 IN KIRQL NewIrql)
1361 {
1362 return NewIrql;
1363 }
1364
1365 #endif