[USB-BRINGUP-TRUNK]
[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 /* Make sure interrupts were enabled */
670 if (EFlags & EFLAGS_INTERRUPT_MASK)
671 {
672 /* Check for pending software interrupts and compare with current IRQL */
673 PendingIrqlMask = Pcr->IRR & FindHigherIrqlMask[OldIrql];
674 if (PendingIrqlMask)
675 {
676 /* Check if pending IRQL affects hardware state */
677 BitScanReverse(&PendingIrql, PendingIrqlMask);
678 if (PendingIrql > DISPATCH_LEVEL)
679 {
680 /* Set new PIC mask */
681 Mask.Both = Pcr->IDR & 0xFFFF;
682 __outbyte(PIC1_DATA_PORT, Mask.Master);
683 __outbyte(PIC2_DATA_PORT, Mask.Slave);
684
685 /* Clear IRR bit */
686 Pcr->IRR ^= (1 << PendingIrql);
687 }
688
689 /* Now handle pending interrupt */
690 SWInterruptHandlerTable[PendingIrql]();
691 }
692 }
693
694 /* Restore interrupt state */
695 __writeeflags(EFlags);
696 }
697
698 /* SOFTWARE INTERRUPTS ********************************************************/
699
700 /*
701 * @implemented
702 */
703 VOID
704 FASTCALL
705 HalRequestSoftwareInterrupt(IN KIRQL Irql)
706 {
707 ULONG EFlags;
708 PKPCR Pcr = KeGetPcr();
709 KIRQL PendingIrql;
710
711 /* Save EFlags and disable interrupts */
712 EFlags = __readeflags();
713 _disable();
714
715 /* Mask out the requested bit */
716 Pcr->IRR |= (1 << Irql);
717
718 /* Check for pending software interrupts and compare with current IRQL */
719 PendingIrql = SWInterruptLookUpTable[Pcr->IRR & 3];
720 if (PendingIrql > Pcr->Irql) SWInterruptHandlerTable[PendingIrql]();
721
722 /* Restore interrupt state */
723 __writeeflags(EFlags);
724 }
725
726 /*
727 * @implemented
728 */
729 VOID
730 FASTCALL
731 HalClearSoftwareInterrupt(IN KIRQL Irql)
732 {
733 /* Mask out the requested bit */
734 KeGetPcr()->IRR &= ~(1 << Irql);
735 }
736
737 VOID
738 NTAPI
739 HalpEndSoftwareInterrupt(IN KIRQL OldIrql,
740 IN PKTRAP_FRAME TrapFrame)
741 {
742 ULONG PendingIrql, PendingIrqlMask, PendingIrqMask;
743 PKPCR Pcr = KeGetPcr();
744 PIC_MASK Mask;
745
746 /* Set old IRQL */
747 Pcr->Irql = OldIrql;
748
749 /* Loop checking for pending interrupts */
750 while (TRUE)
751 {
752 /* Check for pending software interrupts and compare with current IRQL */
753 PendingIrqlMask = Pcr->IRR & FindHigherIrqlMask[OldIrql];
754 if (!PendingIrqlMask) return;
755
756 /* Check for in-service delayed interrupt */
757 if (Pcr->IrrActive & 0xFFFFFFF0) return;
758
759 /* Check if pending IRQL affects hardware state */
760 BitScanReverse(&PendingIrql, PendingIrqlMask);
761 if (PendingIrql > DISPATCH_LEVEL)
762 {
763 /* Set new PIC mask */
764 Mask.Both = Pcr->IDR & 0xFFFF;
765 __outbyte(PIC1_DATA_PORT, Mask.Master);
766 __outbyte(PIC2_DATA_PORT, Mask.Slave);
767
768 /* Set active bit otherwise, and clear it from IRR */
769 PendingIrqMask = (1 << PendingIrql);
770 Pcr->IrrActive |= PendingIrqMask;
771 Pcr->IRR ^= PendingIrqMask;
772
773 /* Handle delayed hardware interrupt */
774 SWInterruptHandlerTable[PendingIrql]();
775
776 /* Handling complete */
777 Pcr->IrrActive ^= PendingIrqMask;
778 }
779 else
780 {
781 /* No need to loop checking for hardware interrupts */
782 SWInterruptHandlerTable2[PendingIrql](TrapFrame);
783 }
784 }
785 }
786
787 /* EDGE INTERRUPT DISMISSAL FUNCTIONS *****************************************/
788
789 BOOLEAN
790 FORCEINLINE
791 _HalpDismissIrqGeneric(IN KIRQL Irql,
792 IN ULONG Irq,
793 OUT PKIRQL OldIrql)
794 {
795 PIC_MASK Mask;
796 KIRQL CurrentIrql;
797 I8259_OCW2 Ocw2;
798 PKPCR Pcr = KeGetPcr();
799
800 /* First save current IRQL and compare it to the requested one */
801 CurrentIrql = Pcr->Irql;
802
803 /* Check if this interrupt is really allowed to happen */
804 if (Irql > CurrentIrql)
805 {
806 /* Set the new IRQL and return the current one */
807 Pcr->Irql = Irql;
808 *OldIrql = CurrentIrql;
809
810 /* Prepare OCW2 for EOI */
811 Ocw2.Bits = 0;
812 Ocw2.EoiMode = SpecificEoi;
813
814 /* Check which PIC needs the EOI */
815 if (Irq > 8)
816 {
817 /* Send the EOI for the IRQ */
818 __outbyte(PIC2_CONTROL_PORT, Ocw2.Bits | ((Irq - 8) & 0xFF));
819
820 /* Send the EOI for IRQ2 on the master because this was cascaded */
821 __outbyte(PIC1_CONTROL_PORT, Ocw2.Bits | 2);
822 }
823 else
824 {
825 /* Send the EOI for the IRQ */
826 __outbyte(PIC1_CONTROL_PORT, Ocw2.Bits | (Irq &0xFF));
827 }
828
829 /* Enable interrupts and return success */
830 _enable();
831 return TRUE;
832 }
833
834 /* Update the IRR so that we deliver this interrupt when the IRQL is proper */
835 Pcr->IRR |= (1 << (Irq + 4));
836
837 /* Set new PIC mask to real IRQL level, since the optimization is lost now */
838 Mask.Both = (KiI8259MaskTable[CurrentIrql] | Pcr->IDR) & 0xFFFF;
839 __outbyte(PIC1_DATA_PORT, Mask.Master);
840 __outbyte(PIC2_DATA_PORT, Mask.Slave);
841
842 /* Now lie and say this was spurious */
843 return FALSE;
844 }
845
846 BOOLEAN
847 REGISTERCALL
848 HalpDismissIrqGeneric(IN KIRQL Irql,
849 IN ULONG Irq,
850 OUT PKIRQL OldIrql)
851 {
852 /* Run the inline code */
853 return _HalpDismissIrqGeneric(Irql, Irq, OldIrql);
854 }
855
856 BOOLEAN
857 REGISTERCALL
858 HalpDismissIrq15(IN KIRQL Irql,
859 IN ULONG Irq,
860 OUT PKIRQL OldIrql)
861 {
862 I8259_OCW3 Ocw3;
863 I8259_OCW2 Ocw2;
864 I8259_ISR Isr;
865
866 /* Request the ISR */
867 Ocw3.Bits = 0;
868 Ocw3.Sbo = 1; /* This encodes an OCW3 vs. an OCW2 */
869 Ocw3.ReadRequest = ReadIsr;
870 __outbyte(PIC2_CONTROL_PORT, Ocw3.Bits);
871
872 /* Read the ISR */
873 Isr.Bits = __inbyte(PIC2_CONTROL_PORT);
874
875 /* Is IRQ15 really active (this is IR7) */
876 if (Isr.Irq7 == FALSE)
877 {
878 /* It isn't, so we have to EOI IRQ2 because this was cascaded */
879 Ocw2.Bits = 0;
880 Ocw2.EoiMode = SpecificEoi;
881 __outbyte(PIC1_CONTROL_PORT, Ocw2.Bits | 2);
882
883 /* And now fail since this was spurious */
884 return FALSE;
885 }
886
887 /* Do normal interrupt dismiss */
888 return _HalpDismissIrqGeneric(Irql, Irq, OldIrql);
889 }
890
891
892 BOOLEAN
893 REGISTERCALL
894 HalpDismissIrq13(IN KIRQL Irql,
895 IN ULONG Irq,
896 OUT PKIRQL OldIrql)
897 {
898 /* Clear the FPU busy latch */
899 __outbyte(0xF0, 0);
900
901 /* Do normal interrupt dismiss */
902 return _HalpDismissIrqGeneric(Irql, Irq, OldIrql);
903 }
904
905 BOOLEAN
906 REGISTERCALL
907 HalpDismissIrq07(IN KIRQL Irql,
908 IN ULONG Irq,
909 OUT PKIRQL OldIrql)
910 {
911 I8259_OCW3 Ocw3;
912 I8259_ISR Isr;
913
914 /* Request the ISR */
915 Ocw3.Bits = 0;
916 Ocw3.Sbo = 1;
917 Ocw3.ReadRequest = ReadIsr;
918 __outbyte(PIC1_CONTROL_PORT, Ocw3.Bits);
919
920 /* Read the ISR */
921 Isr.Bits = __inbyte(PIC1_CONTROL_PORT);
922
923 /* Is IRQ 7 really active? If it isn't, this is spurious so fail */
924 if (Isr.Irq7 == FALSE) return FALSE;
925
926 /* Do normal interrupt dismiss */
927 return _HalpDismissIrqGeneric(Irql, Irq, OldIrql);
928 }
929
930 /* LEVEL INTERRUPT DISMISSAL FUNCTIONS ****************************************/
931
932 BOOLEAN
933 FORCEINLINE
934 _HalpDismissIrqLevel(IN KIRQL Irql,
935 IN ULONG Irq,
936 OUT PKIRQL OldIrql)
937 {
938 PIC_MASK Mask;
939 KIRQL CurrentIrql;
940 I8259_OCW2 Ocw2;
941 PKPCR Pcr = KeGetPcr();
942
943 /* Update the PIC */
944 Mask.Both = (KiI8259MaskTable[Irql] | Pcr->IDR) & 0xFFFF;
945 __outbyte(PIC1_DATA_PORT, Mask.Master);
946 __outbyte(PIC2_DATA_PORT, Mask.Slave);
947
948 /* Update the IRR so that we clear this interrupt when the IRQL is proper */
949 Pcr->IRR |= (1 << (Irq + 4));
950
951 /* Save current IRQL */
952 CurrentIrql = Pcr->Irql;
953
954 /* Prepare OCW2 for EOI */
955 Ocw2.Bits = 0;
956 Ocw2.EoiMode = SpecificEoi;
957
958 /* Check which PIC needs the EOI */
959 if (Irq > 8)
960 {
961 /* Send the EOI for the IRQ */
962 __outbyte(PIC2_CONTROL_PORT, Ocw2.Bits | ((Irq - 8) & 0xFF));
963
964 /* Send the EOI for IRQ2 on the master because this was cascaded */
965 __outbyte(PIC1_CONTROL_PORT, Ocw2.Bits | 2);
966 }
967 else
968 {
969 /* Send the EOI for the IRQ */
970 __outbyte(PIC1_CONTROL_PORT, Ocw2.Bits | (Irq & 0xFF));
971 }
972
973 /* Check if this interrupt should be allowed to happen */
974 if (Irql > CurrentIrql)
975 {
976 /* Set the new IRQL and return the current one */
977 Pcr->Irql = Irql;
978 *OldIrql = CurrentIrql;
979
980 /* Enable interrupts and return success */
981 _enable();
982 return TRUE;
983 }
984
985 /* Now lie and say this was spurious */
986 return FALSE;
987 }
988
989 BOOLEAN
990 REGISTERCALL
991 HalpDismissIrqLevel(IN KIRQL Irql,
992 IN ULONG Irq,
993 OUT PKIRQL OldIrql)
994 {
995 /* Run the inline code */
996 return _HalpDismissIrqLevel(Irql, Irq, OldIrql);
997 }
998
999 BOOLEAN
1000 REGISTERCALL
1001 HalpDismissIrq15Level(IN KIRQL Irql,
1002 IN ULONG Irq,
1003 OUT PKIRQL OldIrql)
1004 {
1005 I8259_OCW3 Ocw3;
1006 I8259_OCW2 Ocw2;
1007 I8259_ISR Isr;
1008
1009 /* Request the ISR */
1010 Ocw3.Bits = 0;
1011 Ocw3.Sbo = 1; /* This encodes an OCW3 vs. an OCW2 */
1012 Ocw3.ReadRequest = ReadIsr;
1013 __outbyte(PIC2_CONTROL_PORT, Ocw3.Bits);
1014
1015 /* Read the ISR */
1016 Isr.Bits = __inbyte(PIC2_CONTROL_PORT);
1017
1018 /* Is IRQ15 really active (this is IR7) */
1019 if (Isr.Irq7 == FALSE)
1020 {
1021 /* It isn't, so we have to EOI IRQ2 because this was cascaded */
1022 Ocw2.Bits = 0;
1023 Ocw2.EoiMode = SpecificEoi;
1024 __outbyte(PIC1_CONTROL_PORT, Ocw2.Bits | 2);
1025
1026 /* And now fail since this was spurious */
1027 return FALSE;
1028 }
1029
1030 /* Do normal interrupt dismiss */
1031 return _HalpDismissIrqLevel(Irql, Irq, OldIrql);
1032 }
1033
1034 BOOLEAN
1035 REGISTERCALL
1036 HalpDismissIrq13Level(IN KIRQL Irql,
1037 IN ULONG Irq,
1038 OUT PKIRQL OldIrql)
1039 {
1040 /* Clear the FPU busy latch */
1041 __outbyte(0xF0, 0);
1042
1043 /* Do normal interrupt dismiss */
1044 return _HalpDismissIrqLevel(Irql, Irq, OldIrql);
1045 }
1046
1047 BOOLEAN
1048 REGISTERCALL
1049 HalpDismissIrq07Level(IN KIRQL Irql,
1050 IN ULONG Irq,
1051 OUT PKIRQL OldIrql)
1052 {
1053 I8259_OCW3 Ocw3;
1054 I8259_ISR Isr;
1055
1056 /* Request the ISR */
1057 Ocw3.Bits = 0;
1058 Ocw3.Sbo = 1;
1059 Ocw3.ReadRequest = ReadIsr;
1060 __outbyte(PIC1_CONTROL_PORT, Ocw3.Bits);
1061
1062 /* Read the ISR */
1063 Isr.Bits = __inbyte(PIC1_CONTROL_PORT);
1064
1065 /* Is IRQ 7 really active? If it isn't, this is spurious so fail */
1066 if (Isr.Irq7 == FALSE) return FALSE;
1067
1068 /* Do normal interrupt dismiss */
1069 return _HalpDismissIrqLevel(Irql, Irq, OldIrql);
1070 }
1071
1072 VOID
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 }
1249 }
1250 }
1251 }
1252
1253 /* SOFTWARE INTERRUPT TRAPS ***************************************************/
1254
1255 VOID
1256 FORCEINLINE
1257 DECLSPEC_NORETURN
1258 _HalpApcInterruptHandler(IN PKTRAP_FRAME TrapFrame)
1259 {
1260 KIRQL CurrentIrql;
1261 PKPCR Pcr = KeGetPcr();
1262
1263 /* Save the current IRQL and update it */
1264 CurrentIrql = Pcr->Irql;
1265 Pcr->Irql = APC_LEVEL;
1266
1267 /* Remove DPC from IRR */
1268 Pcr->IRR &= ~(1 << APC_LEVEL);
1269
1270 /* Enable interrupts and call the kernel's APC interrupt handler */
1271 _enable();
1272 KiDeliverApc(((KiUserTrap(TrapFrame)) || (TrapFrame->EFlags & EFLAGS_V86_MASK)) ?
1273 UserMode : KernelMode,
1274 NULL,
1275 TrapFrame);
1276
1277 /* Disable interrupts and end the interrupt */
1278 _disable();
1279 HalpEndSoftwareInterrupt(CurrentIrql, TrapFrame);
1280
1281 /* Exit the interrupt */
1282 KiEoiHelper(TrapFrame);
1283 }
1284
1285 VOID
1286 DECLSPEC_NORETURN
1287 FASTCALL
1288 HalpApcInterrupt2ndEntry(IN PKTRAP_FRAME TrapFrame)
1289 {
1290 /* Do the work */
1291 _HalpApcInterruptHandler(TrapFrame);
1292 }
1293
1294 VOID
1295 DECLSPEC_NORETURN
1296 FASTCALL
1297 HalpApcInterruptHandler(IN PKTRAP_FRAME TrapFrame)
1298 {
1299 /* Set up a fake INT Stack */
1300 TrapFrame->EFlags = __readeflags();
1301 TrapFrame->SegCs = KGDT_R0_CODE;
1302 TrapFrame->Eip = TrapFrame->Eax;
1303
1304 /* Build the trap frame */
1305 KiEnterInterruptTrap(TrapFrame);
1306
1307 /* Do the work */
1308 _HalpApcInterruptHandler(TrapFrame);
1309 }
1310
1311 KIRQL
1312 FORCEINLINE
1313 _HalpDispatchInterruptHandler(VOID)
1314 {
1315 KIRQL CurrentIrql;
1316 PKPCR Pcr = KeGetPcr();
1317
1318 /* Save the current IRQL and update it */
1319 CurrentIrql = Pcr->Irql;
1320 Pcr->Irql = DISPATCH_LEVEL;
1321
1322 /* Remove DPC from IRR */
1323 Pcr->IRR &= ~(1 << DISPATCH_LEVEL);
1324
1325 /* Enable interrupts and call the kernel's DPC interrupt handler */
1326 _enable();
1327 KiDispatchInterrupt();
1328 _disable();
1329
1330 /* Return IRQL */
1331 return CurrentIrql;
1332 }
1333
1334 VOID
1335 DECLSPEC_NORETURN
1336 FASTCALL
1337 HalpDispatchInterrupt2ndEntry(IN PKTRAP_FRAME TrapFrame)
1338 {
1339 KIRQL CurrentIrql;
1340
1341 /* Do the work */
1342 CurrentIrql = _HalpDispatchInterruptHandler();
1343
1344 /* End the interrupt */
1345 HalpEndSoftwareInterrupt(CurrentIrql, TrapFrame);
1346
1347 /* Exit the interrupt */
1348 KiEoiHelper(TrapFrame);
1349 }
1350
1351 VOID
1352 HalpDispatchInterrupt2(VOID)
1353 {
1354 ULONG PendingIrqlMask, PendingIrql;
1355 KIRQL OldIrql;
1356 PIC_MASK Mask;
1357 PKPCR Pcr = KeGetPcr();
1358
1359 /* Do the work */
1360 OldIrql = _HalpDispatchInterruptHandler();
1361
1362 /* Restore IRQL */
1363 Pcr->Irql = OldIrql;
1364
1365 /* Check for pending software interrupts and compare with current IRQL */
1366 PendingIrqlMask = Pcr->IRR & FindHigherIrqlMask[OldIrql];
1367 if (PendingIrqlMask)
1368 {
1369 /* Check if pending IRQL affects hardware state */
1370 BitScanReverse(&PendingIrql, PendingIrqlMask);
1371 if (PendingIrql > DISPATCH_LEVEL)
1372 {
1373 /* Set new PIC mask */
1374 Mask.Both = Pcr->IDR & 0xFFFF;
1375 __outbyte(PIC1_DATA_PORT, Mask.Master);
1376 __outbyte(PIC2_DATA_PORT, Mask.Slave);
1377
1378 /* Clear IRR bit */
1379 Pcr->IRR ^= (1 << PendingIrql);
1380 }
1381
1382 /* Now handle pending interrupt */
1383 SWInterruptHandlerTable[PendingIrql]();
1384 }
1385 }
1386
1387 #else
1388
1389 KIRQL
1390 NTAPI
1391 KeGetCurrentIrql(VOID)
1392 {
1393 return PASSIVE_LEVEL;
1394 }
1395
1396 VOID
1397 FASTCALL
1398 KfLowerIrql(
1399 IN KIRQL OldIrql)
1400 {
1401 }
1402
1403 KIRQL
1404 FASTCALL
1405 KfRaiseIrql(
1406 IN KIRQL NewIrql)
1407 {
1408 return NewIrql;
1409 }
1410
1411 #endif