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