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