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