Sync with trunk (r48414)
[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 /* Restore interrupt state */
511 if (EnableInterrupts) EFlags |= EFLAGS_INTERRUPT_MASK;
512 __writeeflags(EFlags);
513 }
514
515 /* IRQL MANAGEMENT ************************************************************/
516
517 /*
518 * @implemented
519 */
520 KIRQL
521 NTAPI
522 KeGetCurrentIrql(VOID)
523 {
524 /* Return the IRQL */
525 return KeGetPcr()->Irql;
526 }
527
528 /*
529 * @implemented
530 */
531 KIRQL
532 NTAPI
533 KeRaiseIrqlToDpcLevel(VOID)
534 {
535 PKPCR Pcr = KeGetPcr();
536 KIRQL CurrentIrql;
537
538 /* Save and update IRQL */
539 CurrentIrql = Pcr->Irql;
540 Pcr->Irql = DISPATCH_LEVEL;
541
542 #if DBG
543 /* Validate correct raise */
544 if (CurrentIrql > DISPATCH_LEVEL) KeBugCheck(IRQL_NOT_GREATER_OR_EQUAL);
545 #endif
546
547 /* Return the previous value */
548 return CurrentIrql;
549 }
550
551 /*
552 * @implemented
553 */
554 KIRQL
555 NTAPI
556 KeRaiseIrqlToSynchLevel(VOID)
557 {
558 PKPCR Pcr = KeGetPcr();
559 KIRQL CurrentIrql;
560
561 /* Save and update IRQL */
562 CurrentIrql = Pcr->Irql;
563 Pcr->Irql = SYNCH_LEVEL;
564
565 #if DBG
566 /* Validate correct raise */
567 if (CurrentIrql > SYNCH_LEVEL)
568 {
569 /* Crash system */
570 KeBugCheckEx(IRQL_NOT_GREATER_OR_EQUAL,
571 CurrentIrql,
572 SYNCH_LEVEL,
573 0,
574 1);
575 }
576 #endif
577
578 /* Return the previous value */
579 return CurrentIrql;
580 }
581
582 /*
583 * @implemented
584 */
585 KIRQL
586 FASTCALL
587 KfRaiseIrql(IN KIRQL NewIrql)
588 {
589 PKPCR Pcr = KeGetPcr();
590 KIRQL CurrentIrql;
591
592 /* Read current IRQL */
593 CurrentIrql = Pcr->Irql;
594
595 #if DBG
596 /* Validate correct raise */
597 if (CurrentIrql > NewIrql)
598 {
599 /* Crash system */
600 Pcr->Irql = PASSIVE_LEVEL;
601 KeBugCheck(IRQL_NOT_GREATER_OR_EQUAL);
602 }
603 #endif
604
605 /* Set new IRQL */
606 Pcr->Irql = NewIrql;
607
608 /* Return old IRQL */
609 return CurrentIrql;
610 }
611
612
613 /*
614 * @implemented
615 */
616 VOID
617 FASTCALL
618 KfLowerIrql(IN KIRQL OldIrql)
619 {
620 ULONG EFlags;
621 ULONG PendingIrql, PendingIrqlMask;
622 PKPCR Pcr = KeGetPcr();
623 PIC_MASK Mask;
624
625 #if DBG
626 /* Validate correct lower */
627 if (OldIrql > Pcr->Irql)
628 {
629 /* Crash system */
630 Pcr->Irql = HIGH_LEVEL;
631 KeBugCheck(IRQL_NOT_LESS_OR_EQUAL);
632 }
633 #endif
634
635 /* Save EFlags and disable interrupts */
636 EFlags = __readeflags();
637 _disable();
638
639 /* Set old IRQL */
640 Pcr->Irql = OldIrql;
641
642 /* Check for pending software interrupts and compare with current IRQL */
643 PendingIrqlMask = Pcr->IRR & FindHigherIrqlMask[OldIrql];
644 if (PendingIrqlMask)
645 {
646 /* Check if pending IRQL affects hardware state */
647 BitScanReverse(&PendingIrql, PendingIrqlMask);
648 if (PendingIrql > DISPATCH_LEVEL)
649 {
650 /* Set new PIC mask */
651 Mask.Both = Pcr->IDR;
652 __outbyte(PIC1_DATA_PORT, Mask.Master);
653 __outbyte(PIC2_DATA_PORT, Mask.Slave);
654
655 /* Clear IRR bit */
656 Pcr->IRR ^= (1 << PendingIrql);
657 }
658
659 /* Now handle pending interrupt */
660 SWInterruptHandlerTable[PendingIrql]();
661 }
662
663 /* Restore interrupt state */
664 __writeeflags(EFlags);
665 }
666
667 /* SOFTWARE INTERRUPTS ********************************************************/
668
669 /*
670 * @implemented
671 */
672 VOID
673 FASTCALL
674 HalRequestSoftwareInterrupt(IN KIRQL Irql)
675 {
676 ULONG EFlags;
677 PKPCR Pcr = KeGetPcr();
678 KIRQL PendingIrql;
679
680 /* Save EFlags and disable interrupts */
681 EFlags = __readeflags();
682 _disable();
683
684 /* Mask out the requested bit */
685 Pcr->IRR |= (1 << Irql);
686
687 /* Check for pending software interrupts and compare with current IRQL */
688 PendingIrql = SWInterruptLookUpTable[Pcr->IRR & 3];
689 if (PendingIrql > Pcr->Irql) SWInterruptHandlerTable[PendingIrql]();
690
691 /* Restore interrupt state */
692 __writeeflags(EFlags);
693 }
694
695 /*
696 * @implemented
697 */
698 VOID
699 FASTCALL
700 HalClearSoftwareInterrupt(IN KIRQL Irql)
701 {
702 /* Mask out the requested bit */
703 KeGetPcr()->IRR &= ~(1 << Irql);
704 }
705
706 VOID
707 NTAPI
708 HalpEndSoftwareInterrupt(IN KIRQL OldIrql,
709 IN PKTRAP_FRAME TrapFrame)
710 {
711 ULONG PendingIrql, PendingIrqlMask, PendingIrqMask;
712 PKPCR Pcr = KeGetPcr();
713 PIC_MASK Mask;
714
715 /* Set old IRQL */
716 Pcr->Irql = OldIrql;
717
718 /* Loop checking for pending interrupts */
719 while (TRUE)
720 {
721 /* Check for pending software interrupts and compare with current IRQL */
722 PendingIrqlMask = Pcr->IRR & FindHigherIrqlMask[OldIrql];
723 if (!PendingIrqlMask) return;
724
725 /* Check for in-service delayed interrupt */
726 if (Pcr->IrrActive & 0xFFFFFFF0) return;
727
728 /* Check if pending IRQL affects hardware state */
729 BitScanReverse(&PendingIrql, PendingIrqlMask);
730 if (PendingIrql > DISPATCH_LEVEL)
731 {
732 /* Set new PIC mask */
733 Mask.Both = Pcr->IDR;
734 __outbyte(PIC1_DATA_PORT, Mask.Master);
735 __outbyte(PIC2_DATA_PORT, Mask.Slave);
736
737 /* Set active bit otherwise, and clear it from IRR */
738 PendingIrqMask = (1 << PendingIrql);
739 Pcr->IrrActive |= PendingIrqMask;
740 Pcr->IRR ^= PendingIrqMask;
741
742 /* Handle delayed hardware interrupt */
743 SWInterruptHandlerTable[PendingIrql]();
744
745 /* Handling complete */
746 Pcr->IrrActive ^= PendingIrqMask;
747 }
748 else
749 {
750 /* No need to loop checking for hardware interrupts */
751 SWInterruptHandlerTable2[PendingIrql](TrapFrame);
752 }
753 }
754 }
755
756 /* EDGE INTERRUPT DISMISSAL FUNCTIONS *****************************************/
757
758 BOOLEAN
759 FORCEINLINE
760 _HalpDismissIrqGeneric(IN KIRQL Irql,
761 IN ULONG Irq,
762 OUT PKIRQL OldIrql)
763 {
764 PIC_MASK Mask;
765 KIRQL CurrentIrql;
766 I8259_OCW2 Ocw2;
767 PKPCR Pcr = KeGetPcr();
768
769 /* First save current IRQL and compare it to the requested one */
770 CurrentIrql = Pcr->Irql;
771
772 /* Check if this interrupt is really allowed to happen */
773 if (Irql > CurrentIrql)
774 {
775 /* Set the new IRQL and return the current one */
776 Pcr->Irql = Irql;
777 *OldIrql = CurrentIrql;
778
779 /* Prepare OCW2 for EOI */
780 Ocw2.Bits = 0;
781 Ocw2.EoiMode = SpecificEoi;
782
783 /* Check which PIC needs the EOI */
784 if (Irq > 8)
785 {
786 /* Send the EOI for the IRQ */
787 __outbyte(PIC2_CONTROL_PORT, Ocw2.Bits | (Irq - 8));
788
789 /* Send the EOI for IRQ2 on the master because this was cascaded */
790 __outbyte(PIC1_CONTROL_PORT, Ocw2.Bits | 2);
791 }
792 else
793 {
794 /* Send the EOI for the IRQ */
795 __outbyte(PIC1_CONTROL_PORT, Ocw2.Bits | Irq);
796 }
797
798 /* Enable interrupts and return success */
799 _enable();
800 return TRUE;
801 }
802
803 /* Update the IRR so that we deliver this interrupt when the IRQL is proper */
804 Pcr->IRR |= (1 << (Irq + 4));
805
806 /* Set new PIC mask to real IRQL level, since the optimization is lost now */
807 Mask.Both = KiI8259MaskTable[CurrentIrql] | Pcr->IDR;
808 __outbyte(PIC1_DATA_PORT, Mask.Master);
809 __outbyte(PIC2_DATA_PORT, Mask.Slave);
810
811 /* Now lie and say this was spurious */
812 return FALSE;
813 }
814
815 BOOLEAN
816 REGISTERCALL
817 HalpDismissIrqGeneric(IN KIRQL Irql,
818 IN ULONG Irq,
819 OUT PKIRQL OldIrql)
820 {
821 /* Run the inline code */
822 return _HalpDismissIrqGeneric(Irql, Irq, OldIrql);
823 }
824
825 BOOLEAN
826 REGISTERCALL
827 HalpDismissIrq15(IN KIRQL Irql,
828 IN ULONG Irq,
829 OUT PKIRQL OldIrql)
830 {
831 I8259_OCW3 Ocw3;
832 I8259_OCW2 Ocw2;
833 I8259_ISR Isr;
834
835 /* Request the ISR */
836 Ocw3.Bits = 0;
837 Ocw3.Sbo = 1; /* This encodes an OCW3 vs. an OCW2 */
838 Ocw3.ReadRequest = ReadIsr;
839 __outbyte(PIC2_CONTROL_PORT, Ocw3.Bits);
840
841 /* Read the ISR */
842 Isr.Bits = __inbyte(PIC2_CONTROL_PORT);
843
844 /* Is IRQ15 really active (this is IR7) */
845 if (Isr.Irq7 == FALSE)
846 {
847 /* It isn't, so we have to EOI IRQ2 because this was cascaded */
848 Ocw2.Bits = 0;
849 Ocw2.EoiMode = SpecificEoi;
850 __outbyte(PIC1_CONTROL_PORT, Ocw2.Bits | 2);
851
852 /* And now fail since this was spurious */
853 return FALSE;
854 }
855
856 /* Do normal interrupt dismiss */
857 return _HalpDismissIrqGeneric(Irql, Irq, OldIrql);
858 }
859
860
861 BOOLEAN
862 REGISTERCALL
863 HalpDismissIrq13(IN KIRQL Irql,
864 IN ULONG Irq,
865 OUT PKIRQL OldIrql)
866 {
867 /* Clear the FPU busy latch */
868 __outbyte(0xF0, 0);
869
870 /* Do normal interrupt dismiss */
871 return _HalpDismissIrqGeneric(Irql, Irq, OldIrql);
872 }
873
874 BOOLEAN
875 REGISTERCALL
876 HalpDismissIrq07(IN KIRQL Irql,
877 IN ULONG Irq,
878 OUT PKIRQL OldIrql)
879 {
880 I8259_OCW3 Ocw3;
881 I8259_ISR Isr;
882
883 /* Request the ISR */
884 Ocw3.Bits = 0;
885 Ocw3.Sbo = 1;
886 Ocw3.ReadRequest = ReadIsr;
887 __outbyte(PIC1_CONTROL_PORT, Ocw3.Bits);
888
889 /* Read the ISR */
890 Isr.Bits = __inbyte(PIC1_CONTROL_PORT);
891
892 /* Is IRQ 7 really active? If it isn't, this is spurious so fail */
893 if (Isr.Irq7 == FALSE) return FALSE;
894
895 /* Do normal interrupt dismiss */
896 return _HalpDismissIrqGeneric(Irql, Irq, OldIrql);
897 }
898
899 /* LEVEL INTERRUPT DISMISSAL FUNCTIONS ****************************************/
900
901 BOOLEAN
902 FORCEINLINE
903 _HalpDismissIrqLevel(IN KIRQL Irql,
904 IN ULONG Irq,
905 OUT PKIRQL OldIrql)
906 {
907 PIC_MASK Mask;
908 KIRQL CurrentIrql;
909 I8259_OCW2 Ocw2;
910 PKPCR Pcr = KeGetPcr();
911
912 /* Update the PIC */
913 Mask.Both = KiI8259MaskTable[Irql] | Pcr->IDR;
914 __outbyte(PIC1_DATA_PORT, Mask.Master);
915 __outbyte(PIC2_DATA_PORT, Mask.Slave);
916
917 /* Update the IRR so that we clear this interrupt when the IRQL is proper */
918 Pcr->IRR |= (1 << (Irq + 4));
919
920 /* Save current IRQL */
921 CurrentIrql = Pcr->Irql;
922
923 /* Prepare OCW2 for EOI */
924 Ocw2.Bits = 0;
925 Ocw2.EoiMode = SpecificEoi;
926
927 /* Check which PIC needs the EOI */
928 if (Irq > 8)
929 {
930 /* Send the EOI for the IRQ */
931 __outbyte(PIC2_CONTROL_PORT, Ocw2.Bits | (Irq - 8));
932
933 /* Send the EOI for IRQ2 on the master because this was cascaded */
934 __outbyte(PIC1_CONTROL_PORT, Ocw2.Bits | 2);
935 }
936 else
937 {
938 /* Send the EOI for the IRQ */
939 __outbyte(PIC1_CONTROL_PORT, Ocw2.Bits | Irq);
940 }
941
942 /* Check if this interrupt should be allowed to happen */
943 if (Irql > CurrentIrql)
944 {
945 /* Set the new IRQL and return the current one */
946 Pcr->Irql = Irql;
947 *OldIrql = CurrentIrql;
948
949 /* Enable interrupts and return success */
950 _enable();
951 return TRUE;
952 }
953
954 /* Now lie and say this was spurious */
955 return FALSE;
956 }
957
958 BOOLEAN
959 REGISTERCALL
960 HalpDismissIrqLevel(IN KIRQL Irql,
961 IN ULONG Irq,
962 OUT PKIRQL OldIrql)
963 {
964 /* Run the inline code */
965 return _HalpDismissIrqLevel(Irql, Irq, OldIrql);
966 }
967
968 BOOLEAN
969 REGISTERCALL
970 HalpDismissIrq15Level(IN KIRQL Irql,
971 IN ULONG Irq,
972 OUT PKIRQL OldIrql)
973 {
974 I8259_OCW3 Ocw3;
975 I8259_OCW2 Ocw2;
976 I8259_ISR Isr;
977
978 /* Request the ISR */
979 Ocw3.Bits = 0;
980 Ocw3.Sbo = 1; /* This encodes an OCW3 vs. an OCW2 */
981 Ocw3.ReadRequest = ReadIsr;
982 __outbyte(PIC2_CONTROL_PORT, Ocw3.Bits);
983
984 /* Read the ISR */
985 Isr.Bits = __inbyte(PIC2_CONTROL_PORT);
986
987 /* Is IRQ15 really active (this is IR7) */
988 if (Isr.Irq7 == FALSE)
989 {
990 /* It isn't, so we have to EOI IRQ2 because this was cascaded */
991 Ocw2.Bits = 0;
992 Ocw2.EoiMode = SpecificEoi;
993 __outbyte(PIC1_CONTROL_PORT, Ocw2.Bits | 2);
994
995 /* And now fail since this was spurious */
996 return FALSE;
997 }
998
999 /* Do normal interrupt dismiss */
1000 return _HalpDismissIrqLevel(Irql, Irq, OldIrql);
1001 }
1002
1003 BOOLEAN
1004 REGISTERCALL
1005 HalpDismissIrq13Level(IN KIRQL Irql,
1006 IN ULONG Irq,
1007 OUT PKIRQL OldIrql)
1008 {
1009 /* Clear the FPU busy latch */
1010 __outbyte(0xF0, 0);
1011
1012 /* Do normal interrupt dismiss */
1013 return _HalpDismissIrqLevel(Irql, Irq, OldIrql);
1014 }
1015
1016 BOOLEAN
1017 REGISTERCALL
1018 HalpDismissIrq07Level(IN KIRQL Irql,
1019 IN ULONG Irq,
1020 OUT PKIRQL OldIrql)
1021 {
1022 I8259_OCW3 Ocw3;
1023 I8259_ISR Isr;
1024
1025 /* Request the ISR */
1026 Ocw3.Bits = 0;
1027 Ocw3.Sbo = 1;
1028 Ocw3.ReadRequest = ReadIsr;
1029 __outbyte(PIC1_CONTROL_PORT, Ocw3.Bits);
1030
1031 /* Read the ISR */
1032 Isr.Bits = __inbyte(PIC1_CONTROL_PORT);
1033
1034 /* Is IRQ 7 really active? If it isn't, this is spurious so fail */
1035 if (Isr.Irq7 == FALSE) return FALSE;
1036
1037 /* Do normal interrupt dismiss */
1038 return _HalpDismissIrqLevel(Irql, Irq, OldIrql);
1039 }
1040
1041 VOID
1042 HalpHardwareInterruptLevel(VOID)
1043 {
1044 PKPCR Pcr = KeGetPcr();
1045 ULONG PendingIrqlMask, PendingIrql;
1046
1047 /* Check for pending software interrupts and compare with current IRQL */
1048 PendingIrqlMask = Pcr->IRR & FindHigherIrqlMask[Pcr->Irql];
1049 if (PendingIrqlMask)
1050 {
1051 /* Check for in-service delayed interrupt */
1052 if (Pcr->IrrActive & 0xFFFFFFF0) return;
1053
1054 /* Check if pending IRQL affects hardware state */
1055 BitScanReverse(&PendingIrql, PendingIrqlMask);
1056
1057 /* Clear IRR bit */
1058 Pcr->IRR ^= (1 << PendingIrql);
1059
1060 /* Now handle pending interrupt */
1061 SWInterruptHandlerTable[PendingIrql]();
1062 }
1063 }
1064
1065 /* SYSTEM INTERRUPTS **********************************************************/
1066
1067 /*
1068 * @implemented
1069 */
1070 BOOLEAN
1071 NTAPI
1072 HalEnableSystemInterrupt(IN UCHAR Vector,
1073 IN KIRQL Irql,
1074 IN KINTERRUPT_MODE InterruptMode)
1075 {
1076 ULONG Irq;
1077 PKPCR Pcr = KeGetPcr();
1078 PIC_MASK PicMask;
1079
1080 /* Validate the IRQ */
1081 Irq = Vector - PRIMARY_VECTOR_BASE;
1082 if (Irq >= CLOCK2_LEVEL) return FALSE;
1083
1084 /* Check for level interrupt */
1085 if (InterruptMode == LevelSensitive)
1086 {
1087 /* Switch handler to level */
1088 SWInterruptHandlerTable[Irq + 4] = HalpHardwareInterruptLevel;
1089
1090 /* Switch dismiss to level */
1091 HalpSpecialDismissTable[Irq] = HalpSpecialDismissLevelTable[Irq];
1092 }
1093
1094 /* Disable interrupts */
1095 _disable();
1096
1097 /* Update software IDR */
1098 Pcr->IDR &= ~(1 << Irq);
1099
1100 /* Set new PIC mask */
1101 PicMask.Both = KiI8259MaskTable[Pcr->Irql] | Pcr->IDR;
1102 __outbyte(PIC1_DATA_PORT, PicMask.Master);
1103 __outbyte(PIC2_DATA_PORT, PicMask.Slave);
1104
1105 /* Enable interrupts and exit */
1106 _enable();
1107 return TRUE;
1108 }
1109
1110 /*
1111 * @implemented
1112 */
1113 VOID
1114 NTAPI
1115 HalDisableSystemInterrupt(IN UCHAR Vector,
1116 IN KIRQL Irql)
1117 {
1118 ULONG IrqMask;
1119 PIC_MASK PicMask;
1120
1121 /* Compute new combined IRQ mask */
1122 IrqMask = 1 << (Vector - PRIMARY_VECTOR_BASE);
1123
1124 /* Disable interrupts */
1125 _disable();
1126
1127 /* Update software IDR */
1128 KeGetPcr()->IDR |= IrqMask;
1129
1130 /* Read current interrupt mask */
1131 PicMask.Master = __inbyte(PIC1_DATA_PORT);
1132 PicMask.Slave = __inbyte(PIC2_DATA_PORT);
1133
1134 /* Add the new disabled interrupt */
1135 PicMask.Both |= IrqMask;
1136
1137 /* Write new interrupt mask */
1138 __outbyte(PIC1_DATA_PORT, PicMask.Master);
1139 __outbyte(PIC2_DATA_PORT, PicMask.Slave);
1140
1141 /* Bring interrupts back */
1142 _enable();
1143 }
1144
1145 /*
1146 * @implemented
1147 */
1148 BOOLEAN
1149 NTAPI
1150 HalBeginSystemInterrupt(IN KIRQL Irql,
1151 IN UCHAR Vector,
1152 OUT PKIRQL OldIrql)
1153 {
1154 ULONG Irq;
1155
1156 /* Get the IRQ and call the proper routine to handle it */
1157 Irq = Vector - PRIMARY_VECTOR_BASE;
1158 return HalpSpecialDismissTable[Irq](Irql, Irq, OldIrql);
1159 }
1160
1161 /*
1162 * @implemented
1163 */
1164 VOID
1165 NTAPI
1166 HalEndSystemInterrupt(IN KIRQL OldIrql,
1167 IN PKTRAP_FRAME TrapFrame)
1168 {
1169 ULONG PendingIrql, PendingIrqlMask, PendingIrqMask;
1170 PKPCR Pcr = KeGetPcr();
1171 PIC_MASK Mask;
1172
1173 /* Set old IRQL */
1174 Pcr->Irql = OldIrql;
1175
1176 /* Check for pending software interrupts and compare with current IRQL */
1177 PendingIrqlMask = Pcr->IRR & FindHigherIrqlMask[OldIrql];
1178 if (PendingIrqlMask)
1179 {
1180 /* Check for in-service delayed interrupt */
1181 if (Pcr->IrrActive & 0xFFFFFFF0) return;
1182
1183 /* Loop checking for pending interrupts */
1184 while (TRUE)
1185 {
1186 /* Check if pending IRQL affects hardware state */
1187 BitScanReverse(&PendingIrql, PendingIrqlMask);
1188 if (PendingIrql > DISPATCH_LEVEL)
1189 {
1190 /* Set new PIC mask */
1191 Mask.Both = Pcr->IDR;
1192 __outbyte(PIC1_DATA_PORT, Mask.Master);
1193 __outbyte(PIC2_DATA_PORT, Mask.Slave);
1194
1195 /* Now check if this specific interrupt is already in-service */
1196 PendingIrqMask = (1 << PendingIrql);
1197 if (Pcr->IrrActive & PendingIrqMask) return;
1198
1199 /* Set active bit otherwise, and clear it from IRR */
1200 Pcr->IrrActive |= PendingIrqMask;
1201 Pcr->IRR ^= PendingIrqMask;
1202
1203 /* Handle delayed hardware interrupt */
1204 SWInterruptHandlerTable[PendingIrql]();
1205
1206 /* Handling complete */
1207 Pcr->IrrActive ^= PendingIrqMask;
1208
1209 /* Check if there's still interrupts pending */
1210 PendingIrqlMask = Pcr->IRR & FindHigherIrqlMask[Pcr->Irql];
1211 if (!PendingIrqlMask) break;
1212 }
1213 else
1214 {
1215 /* Now handle pending software interrupt */
1216 SWInterruptHandlerTable2[PendingIrql](TrapFrame);
1217 }
1218 }
1219 }
1220 }
1221
1222 /* SOFTWARE INTERRUPT TRAPS ***************************************************/
1223
1224 VOID
1225 FORCEINLINE
1226 DECLSPEC_NORETURN
1227 _HalpApcInterruptHandler(IN PKTRAP_FRAME TrapFrame)
1228 {
1229 KIRQL CurrentIrql;
1230 PKPCR Pcr = KeGetPcr();
1231
1232 /* Save the current IRQL and update it */
1233 CurrentIrql = Pcr->Irql;
1234 Pcr->Irql = APC_LEVEL;
1235
1236 /* Remove DPC from IRR */
1237 Pcr->IRR &= ~(1 << APC_LEVEL);
1238
1239 /* Enable interrupts and call the kernel's APC interrupt handler */
1240 _enable();
1241 KiDeliverApc(((KiUserTrap(TrapFrame)) || (TrapFrame->EFlags & EFLAGS_V86_MASK)) ?
1242 UserMode : KernelMode,
1243 NULL,
1244 TrapFrame);
1245
1246 /* Disable interrupts and end the interrupt */
1247 _disable();
1248 HalpEndSoftwareInterrupt(CurrentIrql, TrapFrame);
1249
1250 /* Exit the interrupt */
1251 KiEoiHelper(TrapFrame);
1252 }
1253
1254 VOID
1255 DECLSPEC_NORETURN
1256 FASTCALL
1257 HalpApcInterrupt2ndEntry(IN PKTRAP_FRAME TrapFrame)
1258 {
1259 /* Do the work */
1260 _HalpApcInterruptHandler(TrapFrame);
1261 }
1262
1263 VOID
1264 DECLSPEC_NORETURN
1265 FASTCALL
1266 HalpApcInterruptHandler(IN PKTRAP_FRAME TrapFrame)
1267 {
1268 /* Set up a fake INT Stack */
1269 TrapFrame->EFlags = __readeflags();
1270 TrapFrame->SegCs = KGDT_R0_CODE;
1271 TrapFrame->Eip = TrapFrame->Eax;
1272
1273 /* Build the trap frame */
1274 KiEnterInterruptTrap(TrapFrame);
1275
1276 /* Do the work */
1277 _HalpApcInterruptHandler(TrapFrame);
1278 }
1279
1280 KIRQL
1281 FORCEINLINE
1282 _HalpDispatchInterruptHandler(VOID)
1283 {
1284 KIRQL CurrentIrql;
1285 PKPCR Pcr = KeGetPcr();
1286
1287 /* Save the current IRQL and update it */
1288 CurrentIrql = Pcr->Irql;
1289 Pcr->Irql = DISPATCH_LEVEL;
1290
1291 /* Remove DPC from IRR */
1292 Pcr->IRR &= ~(1 << DISPATCH_LEVEL);
1293
1294 /* Enable interrupts and call the kernel's DPC interrupt handler */
1295 _enable();
1296 KiDispatchInterrupt();
1297 _disable();
1298
1299 /* Return IRQL */
1300 return CurrentIrql;
1301 }
1302
1303 VOID
1304 DECLSPEC_NORETURN
1305 FASTCALL
1306 HalpDispatchInterrupt2ndEntry(IN PKTRAP_FRAME TrapFrame)
1307 {
1308 KIRQL CurrentIrql;
1309
1310 /* Do the work */
1311 CurrentIrql = _HalpDispatchInterruptHandler();
1312
1313 /* End the interrupt */
1314 HalpEndSoftwareInterrupt(CurrentIrql, TrapFrame);
1315
1316 /* Exit the interrupt */
1317 KiEoiHelper(TrapFrame);
1318 }
1319
1320 VOID
1321 HalpDispatchInterrupt2(VOID)
1322 {
1323 ULONG PendingIrqlMask, PendingIrql;
1324 KIRQL OldIrql;
1325 PIC_MASK Mask;
1326 PKPCR Pcr = KeGetPcr();
1327
1328 /* Do the work */
1329 OldIrql = _HalpDispatchInterruptHandler();
1330
1331 /* Restore IRQL */
1332 Pcr->Irql = OldIrql;
1333
1334 /* Check for pending software interrupts and compare with current IRQL */
1335 PendingIrqlMask = Pcr->IRR & FindHigherIrqlMask[OldIrql];
1336 if (PendingIrqlMask)
1337 {
1338 /* Check if pending IRQL affects hardware state */
1339 BitScanReverse(&PendingIrql, PendingIrqlMask);
1340 if (PendingIrql > DISPATCH_LEVEL)
1341 {
1342 /* Set new PIC mask */
1343 Mask.Both = Pcr->IDR;
1344 __outbyte(PIC1_DATA_PORT, Mask.Master);
1345 __outbyte(PIC2_DATA_PORT, Mask.Slave);
1346
1347 /* Clear IRR bit */
1348 Pcr->IRR ^= (1 << PendingIrql);
1349 }
1350
1351 /* Now handle pending interrupt */
1352 SWInterruptHandlerTable[PendingIrql]();
1353 }
1354 }
1355
1356 #else
1357
1358 KIRQL
1359 NTAPI
1360 KeGetCurrentIrql(VOID)
1361 {
1362 return PASSIVE_LEVEL;
1363 }
1364
1365 VOID
1366 FASTCALL
1367 KfLowerIrql(
1368 IN KIRQL OldIrql)
1369 {
1370 }
1371
1372 KIRQL
1373 FASTCALL
1374 KfRaiseIrql(
1375 IN KIRQL NewIrql)
1376 {
1377 return NewIrql;
1378 }
1379
1380 #endif