Sync to trunk revision 63922.
[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/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 #if defined(__GNUC__) && \
98 (__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 };
210
211 /* This table indicates which IRQs, if pending, can preempt a given IRQL level */
212 ULONG FindHigherIrqlMask[32] =
213 {
214 #if defined(__GNUC__) && \
215 (__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 };
316
317 /* Denotes minimum required IRQL before we can process pending SW interrupts */
318 KIRQL SWInterruptLookUpTable[8] =
319 {
320 PASSIVE_LEVEL, /* IRR 0 */
321 PASSIVE_LEVEL, /* IRR 1 */
322 APC_LEVEL, /* IRR 2 */
323 APC_LEVEL, /* IRR 3 */
324 DISPATCH_LEVEL, /* IRR 4 */
325 DISPATCH_LEVEL, /* IRR 5 */
326 DISPATCH_LEVEL, /* IRR 6 */
327 DISPATCH_LEVEL /* IRR 7 */
328 };
329
330 #if defined(__GNUC__)
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 #elif defined(_MSC_VER)
341
342 #define HalpDelayedHardwareInterrupt(x) \
343 VOID HalpHardwareInterrupt##x(VOID); \
344 VOID \
345 HalpHardwareInterrupt##x(VOID) \
346 { \
347 __asm \
348 { \
349 int PRIMARY_VECTOR_BASE + x \
350 } \
351 }
352
353 #else
354 #error Unsupported compiler
355 #endif
356
357 /* Pending/delayed hardware interrupt handlers */
358 HalpDelayedHardwareInterrupt(0);
359 HalpDelayedHardwareInterrupt(1);
360 HalpDelayedHardwareInterrupt(2);
361 HalpDelayedHardwareInterrupt(3);
362 HalpDelayedHardwareInterrupt(4);
363 HalpDelayedHardwareInterrupt(5);
364 HalpDelayedHardwareInterrupt(6);
365 HalpDelayedHardwareInterrupt(7);
366 HalpDelayedHardwareInterrupt(8);
367 HalpDelayedHardwareInterrupt(9);
368 HalpDelayedHardwareInterrupt(10);
369 HalpDelayedHardwareInterrupt(11);
370 HalpDelayedHardwareInterrupt(12);
371 HalpDelayedHardwareInterrupt(13);
372 HalpDelayedHardwareInterrupt(14);
373 HalpDelayedHardwareInterrupt(15);
374
375 /* Handlers for pending interrupts */
376 PHAL_SW_INTERRUPT_HANDLER SWInterruptHandlerTable[20] =
377 {
378 KiUnexpectedInterrupt,
379 HalpApcInterrupt,
380 HalpDispatchInterrupt2,
381 KiUnexpectedInterrupt,
382 HalpHardwareInterrupt0,
383 HalpHardwareInterrupt1,
384 HalpHardwareInterrupt2,
385 HalpHardwareInterrupt3,
386 HalpHardwareInterrupt4,
387 HalpHardwareInterrupt5,
388 HalpHardwareInterrupt6,
389 HalpHardwareInterrupt7,
390 HalpHardwareInterrupt8,
391 HalpHardwareInterrupt9,
392 HalpHardwareInterrupt10,
393 HalpHardwareInterrupt11,
394 HalpHardwareInterrupt12,
395 HalpHardwareInterrupt13,
396 HalpHardwareInterrupt14,
397 HalpHardwareInterrupt15
398 };
399
400 /* Handlers for pending software interrupts when we already have a trap frame*/
401 PHAL_SW_INTERRUPT_HANDLER_2ND_ENTRY SWInterruptHandlerTable2[3] =
402 {
403 (PHAL_SW_INTERRUPT_HANDLER_2ND_ENTRY)KiUnexpectedInterrupt,
404 HalpApcInterrupt2ndEntry,
405 HalpDispatchInterrupt2ndEntry
406 };
407
408 LONG HalpEisaELCR;
409
410 /* FUNCTIONS ******************************************************************/
411
412 VOID
413 NTAPI
414 HalpInitializePICs(IN BOOLEAN EnableInterrupts)
415 {
416 ULONG EFlags;
417 I8259_ICW1 Icw1;
418 I8259_ICW2 Icw2;
419 I8259_ICW3 Icw3;
420 I8259_ICW4 Icw4;
421 EISA_ELCR Elcr;
422 ULONG i, j;
423
424 /* Save EFlags and disable interrupts */
425 EFlags = __readeflags();
426 _disable();
427
428 /* Initialize ICW1 for master, interval 8, edge-triggered mode with ICW4 */
429 Icw1.NeedIcw4 = TRUE;
430 Icw1.InterruptMode = EdgeTriggered;
431 Icw1.OperatingMode = Cascade;
432 Icw1.Interval = Interval8;
433 Icw1.Init = TRUE;
434 Icw1.InterruptVectorAddress = 0; /* This is only used in MCS80/85 mode */
435 __outbyte(PIC1_CONTROL_PORT, Icw1.Bits);
436
437 /* Set interrupt vector base */
438 Icw2.Bits = PRIMARY_VECTOR_BASE;
439 __outbyte(PIC1_DATA_PORT, Icw2.Bits);
440
441 /* Connect slave to IRQ 2 */
442 Icw3.Bits = 0;
443 Icw3.SlaveIrq2 = TRUE;
444 __outbyte(PIC1_DATA_PORT, Icw3.Bits);
445
446 /* Enable 8086 mode, non-automatic EOI, non-buffered mode, non special fully nested mode */
447 Icw4.Reserved = 0;
448 Icw4.SystemMode = New8086Mode;
449 Icw4.EoiMode = NormalEoi;
450 Icw4.BufferedMode = NonBuffered;
451 Icw4.SpecialFullyNestedMode = FALSE;
452 __outbyte(PIC1_DATA_PORT, Icw4.Bits);
453
454 /* Mask all interrupts */
455 __outbyte(PIC1_DATA_PORT, 0xFF);
456
457 /* Initialize ICW1 for master, interval 8, edge-triggered mode with ICW4 */
458 Icw1.NeedIcw4 = TRUE;
459 Icw1.InterruptMode = EdgeTriggered;
460 Icw1.OperatingMode = Cascade;
461 Icw1.Interval = Interval8;
462 Icw1.Init = TRUE;
463 Icw1.InterruptVectorAddress = 0; /* This is only used in MCS80/85 mode */
464 __outbyte(PIC2_CONTROL_PORT, Icw1.Bits);
465
466 /* Set interrupt vector base */
467 Icw2.Bits = PRIMARY_VECTOR_BASE + 8;
468 __outbyte(PIC2_DATA_PORT, Icw2.Bits);
469
470 /* Slave ID */
471 Icw3.Bits = 0;
472 Icw3.SlaveId = 2;
473 __outbyte(PIC2_DATA_PORT, Icw3.Bits);
474
475 /* Enable 8086 mode, non-automatic EOI, non-buffered mode, non special fully nested mode */
476 Icw4.Reserved = 0;
477 Icw4.SystemMode = New8086Mode;
478 Icw4.EoiMode = NormalEoi;
479 Icw4.BufferedMode = NonBuffered;
480 Icw4.SpecialFullyNestedMode = FALSE;
481 __outbyte(PIC2_DATA_PORT, Icw4.Bits);
482
483 /* Mask all interrupts */
484 __outbyte(PIC2_DATA_PORT, 0xFF);
485
486 /* Read EISA Edge/Level Register for master and slave */
487 Elcr.Bits = (__inbyte(EISA_ELCR_SLAVE) << 8) | __inbyte(EISA_ELCR_MASTER);
488
489 /* IRQs 0, 1, 2, 8, and 13 are system-reserved and must be edge */
490 if (!(Elcr.Master.Irq0Level) && !(Elcr.Master.Irq1Level) && !(Elcr.Master.Irq2Level) &&
491 !(Elcr.Slave.Irq8Level) && !(Elcr.Slave.Irq13Level))
492 {
493 /* ELCR is as it's supposed to be, save it */
494 HalpEisaELCR = Elcr.Bits;
495
496 /* Scan for level interrupts */
497 for (i = 1, j = 0; j < 16; i <<= 1, j++)
498 {
499 if (HalpEisaELCR & i)
500 {
501 /* Switch handler to level */
502 SWInterruptHandlerTable[j + 4] = HalpHardwareInterruptLevel;
503
504 /* Switch dismiss to level */
505 HalpSpecialDismissTable[j] = HalpSpecialDismissLevelTable[j];
506 }
507 }
508 }
509
510 /* Register IRQ 2 */
511 HalpRegisterVector(IDT_INTERNAL,
512 PRIMARY_VECTOR_BASE + 2,
513 PRIMARY_VECTOR_BASE + 2,
514 HIGH_LEVEL);
515
516 /* Restore interrupt state */
517 if (EnableInterrupts) EFlags |= EFLAGS_INTERRUPT_MASK;
518 __writeeflags(EFlags);
519 }
520
521 UCHAR
522 FASTCALL
523 HalpIrqToVector(UCHAR Irq)
524 {
525 return (PRIMARY_VECTOR_BASE + Irq);
526 }
527
528 UCHAR
529 FASTCALL
530 HalpVectorToIrq(UCHAR Vector)
531 {
532 return (Vector - PRIMARY_VECTOR_BASE);
533 }
534
535 KIRQL
536 FASTCALL
537 HalpVectorToIrql(UCHAR Vector)
538 {
539 return (PROFILE_LEVEL - (Vector - PRIMARY_VECTOR_BASE));
540 }
541
542 /* IRQL MANAGEMENT ************************************************************/
543
544 /*
545 * @implemented
546 */
547 KIRQL
548 NTAPI
549 KeGetCurrentIrql(VOID)
550 {
551 /* Return the IRQL */
552 return KeGetPcr()->Irql;
553 }
554
555 /*
556 * @implemented
557 */
558 KIRQL
559 NTAPI
560 KeRaiseIrqlToDpcLevel(VOID)
561 {
562 PKPCR Pcr = KeGetPcr();
563 KIRQL CurrentIrql;
564
565 /* Save and update IRQL */
566 CurrentIrql = Pcr->Irql;
567 Pcr->Irql = DISPATCH_LEVEL;
568
569 #if DBG
570 /* Validate correct raise */
571 if (CurrentIrql > DISPATCH_LEVEL) KeBugCheck(IRQL_NOT_GREATER_OR_EQUAL);
572 #endif
573
574 /* Return the previous value */
575 return CurrentIrql;
576 }
577
578 /*
579 * @implemented
580 */
581 KIRQL
582 NTAPI
583 KeRaiseIrqlToSynchLevel(VOID)
584 {
585 PKPCR Pcr = KeGetPcr();
586 KIRQL CurrentIrql;
587
588 /* Save and update IRQL */
589 CurrentIrql = Pcr->Irql;
590 Pcr->Irql = SYNCH_LEVEL;
591
592 #if DBG
593 /* Validate correct raise */
594 if (CurrentIrql > SYNCH_LEVEL)
595 {
596 /* Crash system */
597 KeBugCheckEx(IRQL_NOT_GREATER_OR_EQUAL,
598 CurrentIrql,
599 SYNCH_LEVEL,
600 0,
601 1);
602 }
603 #endif
604
605 /* Return the previous value */
606 return CurrentIrql;
607 }
608
609 /*
610 * @implemented
611 */
612 KIRQL
613 FASTCALL
614 KfRaiseIrql(IN KIRQL NewIrql)
615 {
616 PKPCR Pcr = KeGetPcr();
617 KIRQL CurrentIrql;
618
619 /* Read current IRQL */
620 CurrentIrql = Pcr->Irql;
621
622 #if DBG
623 /* Validate correct raise */
624 if (CurrentIrql > NewIrql)
625 {
626 /* Crash system */
627 Pcr->Irql = PASSIVE_LEVEL;
628 KeBugCheck(IRQL_NOT_GREATER_OR_EQUAL);
629 }
630 #endif
631
632 /* Set new IRQL */
633 Pcr->Irql = NewIrql;
634
635 /* Return old IRQL */
636 return CurrentIrql;
637 }
638
639
640 /*
641 * @implemented
642 */
643 VOID
644 FASTCALL
645 KfLowerIrql(IN KIRQL OldIrql)
646 {
647 ULONG EFlags;
648 ULONG PendingIrql, PendingIrqlMask;
649 PKPCR Pcr = KeGetPcr();
650 PIC_MASK Mask;
651
652 #if DBG
653 /* Validate correct lower */
654 if (OldIrql > Pcr->Irql)
655 {
656 /* Crash system */
657 Pcr->Irql = HIGH_LEVEL;
658 KeBugCheck(IRQL_NOT_LESS_OR_EQUAL);
659 }
660 #endif
661
662 /* Save EFlags and disable interrupts */
663 EFlags = __readeflags();
664 _disable();
665
666 /* Set old IRQL */
667 Pcr->Irql = OldIrql;
668
669 /* Check for pending software interrupts and compare with current IRQL */
670 PendingIrqlMask = Pcr->IRR & FindHigherIrqlMask[OldIrql];
671 if (PendingIrqlMask)
672 {
673 /* Check if pending IRQL affects hardware state */
674 BitScanReverse(&PendingIrql, PendingIrqlMask);
675 if (PendingIrql > DISPATCH_LEVEL)
676 {
677 /* Set new PIC mask */
678 Mask.Both = Pcr->IDR & 0xFFFF;
679 __outbyte(PIC1_DATA_PORT, Mask.Master);
680 __outbyte(PIC2_DATA_PORT, Mask.Slave);
681
682 /* Clear IRR bit */
683 Pcr->IRR ^= (1 << PendingIrql);
684 }
685
686 /* Now handle pending interrupt */
687 SWInterruptHandlerTable[PendingIrql]();
688 }
689
690 /* Restore interrupt state */
691 __writeeflags(EFlags);
692 }
693
694 /* SOFTWARE INTERRUPTS ********************************************************/
695
696 /*
697 * @implemented
698 */
699 VOID
700 FASTCALL
701 HalRequestSoftwareInterrupt(IN KIRQL Irql)
702 {
703 ULONG EFlags;
704 PKPCR Pcr = KeGetPcr();
705 KIRQL PendingIrql;
706
707 /* Save EFlags and disable interrupts */
708 EFlags = __readeflags();
709 _disable();
710
711 /* Mask out the requested bit */
712 Pcr->IRR |= (1 << Irql);
713
714 /* Check for pending software interrupts and compare with current IRQL */
715 PendingIrql = SWInterruptLookUpTable[Pcr->IRR & 3];
716 if (PendingIrql > Pcr->Irql) SWInterruptHandlerTable[PendingIrql]();
717
718 /* Restore interrupt state */
719 __writeeflags(EFlags);
720 }
721
722 /*
723 * @implemented
724 */
725 VOID
726 FASTCALL
727 HalClearSoftwareInterrupt(IN KIRQL Irql)
728 {
729 /* Mask out the requested bit */
730 KeGetPcr()->IRR &= ~(1 << Irql);
731 }
732
733 VOID
734 NTAPI
735 HalpEndSoftwareInterrupt(IN KIRQL OldIrql,
736 IN PKTRAP_FRAME TrapFrame)
737 {
738 ULONG PendingIrql, PendingIrqlMask, PendingIrqMask;
739 PKPCR Pcr = KeGetPcr();
740 PIC_MASK Mask;
741
742 /* Set old IRQL */
743 Pcr->Irql = OldIrql;
744
745 /* Loop checking for pending interrupts */
746 while (TRUE)
747 {
748 /* Check for pending software interrupts and compare with current IRQL */
749 PendingIrqlMask = Pcr->IRR & FindHigherIrqlMask[OldIrql];
750 if (!PendingIrqlMask) return;
751
752 /* Check for in-service delayed interrupt */
753 if (Pcr->IrrActive & 0xFFFFFFF0) return;
754
755 /* Check if pending IRQL affects hardware state */
756 BitScanReverse(&PendingIrql, PendingIrqlMask);
757 if (PendingIrql > DISPATCH_LEVEL)
758 {
759 /* Set new PIC mask */
760 Mask.Both = Pcr->IDR & 0xFFFF;
761 __outbyte(PIC1_DATA_PORT, Mask.Master);
762 __outbyte(PIC2_DATA_PORT, Mask.Slave);
763
764 /* Set active bit otherwise, and clear it from IRR */
765 PendingIrqMask = (1 << PendingIrql);
766 Pcr->IrrActive |= PendingIrqMask;
767 Pcr->IRR ^= PendingIrqMask;
768
769 /* Handle delayed hardware interrupt */
770 SWInterruptHandlerTable[PendingIrql]();
771
772 /* Handling complete */
773 Pcr->IrrActive ^= PendingIrqMask;
774 }
775 else
776 {
777 /* No need to loop checking for hardware interrupts */
778 SWInterruptHandlerTable2[PendingIrql](TrapFrame);
779 }
780 }
781 }
782
783 /* EDGE INTERRUPT DISMISSAL FUNCTIONS *****************************************/
784
785 FORCEINLINE
786 BOOLEAN
787 _HalpDismissIrqGeneric(IN KIRQL Irql,
788 IN ULONG Irq,
789 OUT PKIRQL OldIrql)
790 {
791 PIC_MASK Mask;
792 KIRQL CurrentIrql;
793 I8259_OCW2 Ocw2;
794 PKPCR Pcr = KeGetPcr();
795
796 /* First save current IRQL and compare it to the requested one */
797 CurrentIrql = Pcr->Irql;
798
799 /* Check if this interrupt is really allowed to happen */
800 if (Irql > CurrentIrql)
801 {
802 /* Set the new IRQL and return the current one */
803 Pcr->Irql = Irql;
804 *OldIrql = CurrentIrql;
805
806 /* Prepare OCW2 for EOI */
807 Ocw2.Bits = 0;
808 Ocw2.EoiMode = SpecificEoi;
809
810 /* Check which PIC needs the EOI */
811 if (Irq > 8)
812 {
813 /* Send the EOI for the IRQ */
814 __outbyte(PIC2_CONTROL_PORT, Ocw2.Bits | ((Irq - 8) & 0xFF));
815
816 /* Send the EOI for IRQ2 on the master because this was cascaded */
817 __outbyte(PIC1_CONTROL_PORT, Ocw2.Bits | 2);
818 }
819 else
820 {
821 /* Send the EOI for the IRQ */
822 __outbyte(PIC1_CONTROL_PORT, Ocw2.Bits | (Irq &0xFF));
823 }
824
825 /* Enable interrupts and return success */
826 _enable();
827 return TRUE;
828 }
829
830 /* Update the IRR so that we deliver this interrupt when the IRQL is proper */
831 Pcr->IRR |= (1 << (Irq + 4));
832
833 /* Set new PIC mask to real IRQL level, since the optimization is lost now */
834 Mask.Both = (KiI8259MaskTable[CurrentIrql] | Pcr->IDR) & 0xFFFF;
835 __outbyte(PIC1_DATA_PORT, Mask.Master);
836 __outbyte(PIC2_DATA_PORT, Mask.Slave);
837
838 /* Now lie and say this was spurious */
839 return FALSE;
840 }
841
842 BOOLEAN
843 REGISTERCALL
844 HalpDismissIrqGeneric(IN KIRQL Irql,
845 IN ULONG Irq,
846 OUT PKIRQL OldIrql)
847 {
848 /* Run the inline code */
849 return _HalpDismissIrqGeneric(Irql, Irq, OldIrql);
850 }
851
852 BOOLEAN
853 REGISTERCALL
854 HalpDismissIrq15(IN KIRQL Irql,
855 IN ULONG Irq,
856 OUT PKIRQL OldIrql)
857 {
858 I8259_OCW3 Ocw3;
859 I8259_OCW2 Ocw2;
860 I8259_ISR Isr;
861
862 /* Request the ISR */
863 Ocw3.Bits = 0;
864 Ocw3.Sbo = 1; /* This encodes an OCW3 vs. an OCW2 */
865 Ocw3.ReadRequest = ReadIsr;
866 __outbyte(PIC2_CONTROL_PORT, Ocw3.Bits);
867
868 /* Read the ISR */
869 Isr.Bits = __inbyte(PIC2_CONTROL_PORT);
870
871 /* Is IRQ15 really active (this is IR7) */
872 if (Isr.Irq7 == FALSE)
873 {
874 /* It isn't, so we have to EOI IRQ2 because this was cascaded */
875 Ocw2.Bits = 0;
876 Ocw2.EoiMode = SpecificEoi;
877 __outbyte(PIC1_CONTROL_PORT, Ocw2.Bits | 2);
878
879 /* And now fail since this was spurious */
880 return FALSE;
881 }
882
883 /* Do normal interrupt dismiss */
884 return _HalpDismissIrqGeneric(Irql, Irq, OldIrql);
885 }
886
887
888 BOOLEAN
889 REGISTERCALL
890 HalpDismissIrq13(IN KIRQL Irql,
891 IN ULONG Irq,
892 OUT PKIRQL OldIrql)
893 {
894 /* Clear the FPU busy latch */
895 __outbyte(0xF0, 0);
896
897 /* Do normal interrupt dismiss */
898 return _HalpDismissIrqGeneric(Irql, Irq, OldIrql);
899 }
900
901 BOOLEAN
902 REGISTERCALL
903 HalpDismissIrq07(IN KIRQL Irql,
904 IN ULONG Irq,
905 OUT PKIRQL OldIrql)
906 {
907 I8259_OCW3 Ocw3;
908 I8259_ISR Isr;
909
910 /* Request the ISR */
911 Ocw3.Bits = 0;
912 Ocw3.Sbo = 1;
913 Ocw3.ReadRequest = ReadIsr;
914 __outbyte(PIC1_CONTROL_PORT, Ocw3.Bits);
915
916 /* Read the ISR */
917 Isr.Bits = __inbyte(PIC1_CONTROL_PORT);
918
919 /* Is IRQ 7 really active? If it isn't, this is spurious so fail */
920 if (Isr.Irq7 == FALSE) return FALSE;
921
922 /* Do normal interrupt dismiss */
923 return _HalpDismissIrqGeneric(Irql, Irq, OldIrql);
924 }
925
926 /* LEVEL INTERRUPT DISMISSAL FUNCTIONS ****************************************/
927
928 FORCEINLINE
929 BOOLEAN
930 _HalpDismissIrqLevel(IN KIRQL Irql,
931 IN ULONG Irq,
932 OUT PKIRQL OldIrql)
933 {
934 PIC_MASK Mask;
935 KIRQL CurrentIrql;
936 I8259_OCW2 Ocw2;
937 PKPCR Pcr = KeGetPcr();
938
939 /* Update the PIC */
940 Mask.Both = (KiI8259MaskTable[Irql] | Pcr->IDR) & 0xFFFF;
941 __outbyte(PIC1_DATA_PORT, Mask.Master);
942 __outbyte(PIC2_DATA_PORT, Mask.Slave);
943
944 /* Update the IRR so that we clear this interrupt when the IRQL is proper */
945 Pcr->IRR |= (1 << (Irq + 4));
946
947 /* Save current IRQL */
948 CurrentIrql = Pcr->Irql;
949
950 /* Prepare OCW2 for EOI */
951 Ocw2.Bits = 0;
952 Ocw2.EoiMode = SpecificEoi;
953
954 /* Check which PIC needs the EOI */
955 if (Irq > 8)
956 {
957 /* Send the EOI for the IRQ */
958 __outbyte(PIC2_CONTROL_PORT, Ocw2.Bits | ((Irq - 8) & 0xFF));
959
960 /* Send the EOI for IRQ2 on the master because this was cascaded */
961 __outbyte(PIC1_CONTROL_PORT, Ocw2.Bits | 2);
962 }
963 else
964 {
965 /* Send the EOI for the IRQ */
966 __outbyte(PIC1_CONTROL_PORT, Ocw2.Bits | (Irq & 0xFF));
967 }
968
969 /* Check if this interrupt should be allowed to happen */
970 if (Irql > CurrentIrql)
971 {
972 /* Set the new IRQL and return the current one */
973 Pcr->Irql = Irql;
974 *OldIrql = CurrentIrql;
975
976 /* Enable interrupts and return success */
977 _enable();
978 return TRUE;
979 }
980
981 /* Now lie and say this was spurious */
982 return FALSE;
983 }
984
985 BOOLEAN
986 REGISTERCALL
987 HalpDismissIrqLevel(IN KIRQL Irql,
988 IN ULONG Irq,
989 OUT PKIRQL OldIrql)
990 {
991 /* Run the inline code */
992 return _HalpDismissIrqLevel(Irql, Irq, OldIrql);
993 }
994
995 BOOLEAN
996 REGISTERCALL
997 HalpDismissIrq15Level(IN KIRQL Irql,
998 IN ULONG Irq,
999 OUT PKIRQL OldIrql)
1000 {
1001 I8259_OCW3 Ocw3;
1002 I8259_OCW2 Ocw2;
1003 I8259_ISR Isr;
1004
1005 /* Request the ISR */
1006 Ocw3.Bits = 0;
1007 Ocw3.Sbo = 1; /* This encodes an OCW3 vs. an OCW2 */
1008 Ocw3.ReadRequest = ReadIsr;
1009 __outbyte(PIC2_CONTROL_PORT, Ocw3.Bits);
1010
1011 /* Read the ISR */
1012 Isr.Bits = __inbyte(PIC2_CONTROL_PORT);
1013
1014 /* Is IRQ15 really active (this is IR7) */
1015 if (Isr.Irq7 == FALSE)
1016 {
1017 /* It isn't, so we have to EOI IRQ2 because this was cascaded */
1018 Ocw2.Bits = 0;
1019 Ocw2.EoiMode = SpecificEoi;
1020 __outbyte(PIC1_CONTROL_PORT, Ocw2.Bits | 2);
1021
1022 /* And now fail since this was spurious */
1023 return FALSE;
1024 }
1025
1026 /* Do normal interrupt dismiss */
1027 return _HalpDismissIrqLevel(Irql, Irq, OldIrql);
1028 }
1029
1030 BOOLEAN
1031 REGISTERCALL
1032 HalpDismissIrq13Level(IN KIRQL Irql,
1033 IN ULONG Irq,
1034 OUT PKIRQL OldIrql)
1035 {
1036 /* Clear the FPU busy latch */
1037 __outbyte(0xF0, 0);
1038
1039 /* Do normal interrupt dismiss */
1040 return _HalpDismissIrqLevel(Irql, Irq, OldIrql);
1041 }
1042
1043 BOOLEAN
1044 REGISTERCALL
1045 HalpDismissIrq07Level(IN KIRQL Irql,
1046 IN ULONG Irq,
1047 OUT PKIRQL OldIrql)
1048 {
1049 I8259_OCW3 Ocw3;
1050 I8259_ISR Isr;
1051
1052 /* Request the ISR */
1053 Ocw3.Bits = 0;
1054 Ocw3.Sbo = 1;
1055 Ocw3.ReadRequest = ReadIsr;
1056 __outbyte(PIC1_CONTROL_PORT, Ocw3.Bits);
1057
1058 /* Read the ISR */
1059 Isr.Bits = __inbyte(PIC1_CONTROL_PORT);
1060
1061 /* Is IRQ 7 really active? If it isn't, this is spurious so fail */
1062 if (Isr.Irq7 == FALSE) return FALSE;
1063
1064 /* Do normal interrupt dismiss */
1065 return _HalpDismissIrqLevel(Irql, Irq, OldIrql);
1066 }
1067
1068 VOID
1069 HalpHardwareInterruptLevel(VOID)
1070 {
1071 PKPCR Pcr = KeGetPcr();
1072 ULONG PendingIrqlMask, PendingIrql;
1073
1074 /* Check for pending software interrupts and compare with current IRQL */
1075 PendingIrqlMask = Pcr->IRR & FindHigherIrqlMask[Pcr->Irql];
1076 if (PendingIrqlMask)
1077 {
1078 /* Check for in-service delayed interrupt */
1079 if (Pcr->IrrActive & 0xFFFFFFF0) return;
1080
1081 /* Check if pending IRQL affects hardware state */
1082 BitScanReverse(&PendingIrql, PendingIrqlMask);
1083
1084 /* Clear IRR bit */
1085 Pcr->IRR ^= (1 << PendingIrql);
1086
1087 /* Now handle pending interrupt */
1088 SWInterruptHandlerTable[PendingIrql]();
1089 }
1090 }
1091
1092 /* SYSTEM INTERRUPTS **********************************************************/
1093
1094 /*
1095 * @implemented
1096 */
1097 BOOLEAN
1098 NTAPI
1099 HalEnableSystemInterrupt(IN ULONG Vector,
1100 IN KIRQL Irql,
1101 IN KINTERRUPT_MODE InterruptMode)
1102 {
1103 ULONG Irq;
1104 PKPCR Pcr = KeGetPcr();
1105 PIC_MASK PicMask;
1106
1107 /* Validate the IRQ */
1108 Irq = Vector - PRIMARY_VECTOR_BASE;
1109 if (Irq >= CLOCK2_LEVEL) return FALSE;
1110
1111 /* Check for level interrupt */
1112 if (InterruptMode == LevelSensitive)
1113 {
1114 /* Switch handler to level */
1115 SWInterruptHandlerTable[Irq + 4] = HalpHardwareInterruptLevel;
1116
1117 /* Switch dismiss to level */
1118 HalpSpecialDismissTable[Irq] = HalpSpecialDismissLevelTable[Irq];
1119 }
1120
1121 /* Disable interrupts */
1122 _disable();
1123
1124 /* Update software IDR */
1125 Pcr->IDR &= ~(1 << Irq);
1126
1127 /* Set new PIC mask */
1128 PicMask.Both = (KiI8259MaskTable[Pcr->Irql] | Pcr->IDR) & 0xFFFF;
1129 __outbyte(PIC1_DATA_PORT, PicMask.Master);
1130 __outbyte(PIC2_DATA_PORT, PicMask.Slave);
1131
1132 /* Enable interrupts and exit */
1133 _enable();
1134 return TRUE;
1135 }
1136
1137 /*
1138 * @implemented
1139 */
1140 VOID
1141 NTAPI
1142 HalDisableSystemInterrupt(IN ULONG Vector,
1143 IN KIRQL Irql)
1144 {
1145 ULONG IrqMask;
1146 PIC_MASK PicMask;
1147
1148 /* Compute new combined IRQ mask */
1149 IrqMask = 1 << (Vector - PRIMARY_VECTOR_BASE);
1150
1151 /* Disable interrupts */
1152 _disable();
1153
1154 /* Update software IDR */
1155 KeGetPcr()->IDR |= IrqMask;
1156
1157 /* Read current interrupt mask */
1158 PicMask.Master = __inbyte(PIC1_DATA_PORT);
1159 PicMask.Slave = __inbyte(PIC2_DATA_PORT);
1160
1161 /* Add the new disabled interrupt */
1162 PicMask.Both |= IrqMask;
1163
1164 /* Write new interrupt mask */
1165 __outbyte(PIC1_DATA_PORT, PicMask.Master);
1166 __outbyte(PIC2_DATA_PORT, PicMask.Slave);
1167
1168 /* Bring interrupts back */
1169 _enable();
1170 }
1171
1172 /*
1173 * @implemented
1174 */
1175 BOOLEAN
1176 NTAPI
1177 HalBeginSystemInterrupt(IN KIRQL Irql,
1178 IN ULONG Vector,
1179 OUT PKIRQL OldIrql)
1180 {
1181 ULONG Irq;
1182
1183 /* Get the IRQ and call the proper routine to handle it */
1184 Irq = Vector - PRIMARY_VECTOR_BASE;
1185 return HalpSpecialDismissTable[Irq](Irql, Irq, OldIrql);
1186 }
1187
1188 /*
1189 * @implemented
1190 */
1191 VOID
1192 NTAPI
1193 HalEndSystemInterrupt(IN KIRQL OldIrql,
1194 IN PKTRAP_FRAME TrapFrame)
1195 {
1196 ULONG PendingIrql, PendingIrqlMask, PendingIrqMask;
1197 PKPCR Pcr = KeGetPcr();
1198 PIC_MASK Mask;
1199
1200 /* Set old IRQL */
1201 Pcr->Irql = OldIrql;
1202
1203 /* Check for pending software interrupts and compare with current IRQL */
1204 PendingIrqlMask = Pcr->IRR & FindHigherIrqlMask[OldIrql];
1205 if (PendingIrqlMask)
1206 {
1207 /* Check for in-service delayed interrupt */
1208 if (Pcr->IrrActive & 0xFFFFFFF0) return;
1209
1210 /* Loop checking for pending interrupts */
1211 while (TRUE)
1212 {
1213 /* Check if pending IRQL affects hardware state */
1214 BitScanReverse(&PendingIrql, PendingIrqlMask);
1215 if (PendingIrql > DISPATCH_LEVEL)
1216 {
1217 /* Set new PIC mask */
1218 Mask.Both = Pcr->IDR & 0xFFFF;
1219 __outbyte(PIC1_DATA_PORT, Mask.Master);
1220 __outbyte(PIC2_DATA_PORT, Mask.Slave);
1221
1222 /* Now check if this specific interrupt is already in-service */
1223 PendingIrqMask = (1 << PendingIrql);
1224 if (Pcr->IrrActive & PendingIrqMask) return;
1225
1226 /* Set active bit otherwise, and clear it from IRR */
1227 Pcr->IrrActive |= PendingIrqMask;
1228 Pcr->IRR ^= PendingIrqMask;
1229
1230 /* Handle delayed hardware interrupt */
1231 SWInterruptHandlerTable[PendingIrql]();
1232
1233 /* Handling complete */
1234 Pcr->IrrActive ^= PendingIrqMask;
1235
1236 /* Check if there's still interrupts pending */
1237 PendingIrqlMask = Pcr->IRR & FindHigherIrqlMask[Pcr->Irql];
1238 if (!PendingIrqlMask) break;
1239 }
1240 else
1241 {
1242 /* Now handle pending software interrupt */
1243 SWInterruptHandlerTable2[PendingIrql](TrapFrame);
1244 }
1245 }
1246 }
1247 }
1248
1249 /* SOFTWARE INTERRUPT TRAPS ***************************************************/
1250
1251 FORCEINLINE
1252 VOID
1253 DECLSPEC_NORETURN
1254 _HalpApcInterruptHandler(IN PKTRAP_FRAME TrapFrame)
1255 {
1256 KIRQL CurrentIrql;
1257 PKPCR Pcr = KeGetPcr();
1258
1259 /* Save the current IRQL and update it */
1260 CurrentIrql = Pcr->Irql;
1261 Pcr->Irql = APC_LEVEL;
1262
1263 /* Remove DPC from IRR */
1264 Pcr->IRR &= ~(1 << APC_LEVEL);
1265
1266 /* Enable interrupts and call the kernel's APC interrupt handler */
1267 _enable();
1268 KiDeliverApc(((KiUserTrap(TrapFrame)) || (TrapFrame->EFlags & EFLAGS_V86_MASK)) ?
1269 UserMode : KernelMode,
1270 NULL,
1271 TrapFrame);
1272
1273 /* Disable interrupts and end the interrupt */
1274 _disable();
1275 HalpEndSoftwareInterrupt(CurrentIrql, TrapFrame);
1276
1277 /* Exit the interrupt */
1278 KiEoiHelper(TrapFrame);
1279 }
1280
1281 VOID
1282 DECLSPEC_NORETURN
1283 FASTCALL
1284 HalpApcInterrupt2ndEntry(IN PKTRAP_FRAME TrapFrame)
1285 {
1286 /* Do the work */
1287 _HalpApcInterruptHandler(TrapFrame);
1288 }
1289
1290 VOID
1291 DECLSPEC_NORETURN
1292 FASTCALL
1293 HalpApcInterruptHandler(IN PKTRAP_FRAME TrapFrame)
1294 {
1295 /* Set up a fake INT Stack */
1296 TrapFrame->EFlags = __readeflags();
1297 TrapFrame->SegCs = KGDT_R0_CODE;
1298 TrapFrame->Eip = TrapFrame->Eax;
1299
1300 /* Build the trap frame */
1301 KiEnterInterruptTrap(TrapFrame);
1302
1303 /* Do the work */
1304 _HalpApcInterruptHandler(TrapFrame);
1305 }
1306
1307 FORCEINLINE
1308 KIRQL
1309 _HalpDispatchInterruptHandler(VOID)
1310 {
1311 KIRQL CurrentIrql;
1312 PKPCR Pcr = KeGetPcr();
1313
1314 /* Save the current IRQL and update it */
1315 CurrentIrql = Pcr->Irql;
1316 Pcr->Irql = DISPATCH_LEVEL;
1317
1318 /* Remove DPC from IRR */
1319 Pcr->IRR &= ~(1 << DISPATCH_LEVEL);
1320
1321 /* Enable interrupts and call the kernel's DPC interrupt handler */
1322 _enable();
1323 KiDispatchInterrupt();
1324 _disable();
1325
1326 /* Return IRQL */
1327 return CurrentIrql;
1328 }
1329
1330 VOID
1331 DECLSPEC_NORETURN
1332 FASTCALL
1333 HalpDispatchInterrupt2ndEntry(IN PKTRAP_FRAME TrapFrame)
1334 {
1335 KIRQL CurrentIrql;
1336
1337 /* Do the work */
1338 CurrentIrql = _HalpDispatchInterruptHandler();
1339
1340 /* End the interrupt */
1341 HalpEndSoftwareInterrupt(CurrentIrql, TrapFrame);
1342
1343 /* Exit the interrupt */
1344 KiEoiHelper(TrapFrame);
1345 }
1346
1347 VOID
1348 HalpDispatchInterrupt2(VOID)
1349 {
1350 ULONG PendingIrqlMask, PendingIrql;
1351 KIRQL OldIrql;
1352 PIC_MASK Mask;
1353 PKPCR Pcr = KeGetPcr();
1354
1355 /* Do the work */
1356 OldIrql = _HalpDispatchInterruptHandler();
1357
1358 /* Restore IRQL */
1359 Pcr->Irql = OldIrql;
1360
1361 /* Check for pending software interrupts and compare with current IRQL */
1362 PendingIrqlMask = Pcr->IRR & FindHigherIrqlMask[OldIrql];
1363 if (PendingIrqlMask)
1364 {
1365 /* Check if pending IRQL affects hardware state */
1366 BitScanReverse(&PendingIrql, PendingIrqlMask);
1367 if (PendingIrql > DISPATCH_LEVEL)
1368 {
1369 /* Set new PIC mask */
1370 Mask.Both = Pcr->IDR & 0xFFFF;
1371 __outbyte(PIC1_DATA_PORT, Mask.Master);
1372 __outbyte(PIC2_DATA_PORT, Mask.Slave);
1373
1374 /* Clear IRR bit */
1375 Pcr->IRR ^= (1 << PendingIrql);
1376 }
1377
1378 /* Now handle pending interrupt */
1379 SWInterruptHandlerTable[PendingIrql]();
1380 }
1381 }
1382
1383 #else
1384
1385 KIRQL
1386 NTAPI
1387 KeGetCurrentIrql(VOID)
1388 {
1389 return PASSIVE_LEVEL;
1390 }
1391
1392 VOID
1393 FASTCALL
1394 KfLowerIrql(
1395 IN KIRQL OldIrql)
1396 {
1397 }
1398
1399 KIRQL
1400 FASTCALL
1401 KfRaiseIrql(
1402 IN KIRQL NewIrql)
1403 {
1404 return NewIrql;
1405 }
1406
1407 #endif