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