3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/hal/x86/irql.c
6 * PURPOSE: Implements IRQLs
7 * PROGRAMMER: David Welch (welch@cwcom.net)
10 /* INCLUDES *****************************************************************/
12 #include <ddk/ntddk.h>
13 #include <internal/ke.h>
14 #include <internal/ps.h>
15 #include <ntos/minmax.h>
18 #include <internal/debug.h>
20 /* GLOBALS ******************************************************************/
23 #define IRQ_BASE (0x40)
26 * PURPOSE: Current irq level
28 static KIRQL CurrentIrql = HIGH_LEVEL;
42 * PURPOSE: - Mask for HalEnableSystemInterrupt and HalDisableSystemInterrupt
43 * - At startup enable timer and cascade
45 static PIC_MASK pic_mask = {.both = 0xFFFA};
49 * PURPOSE: Mask for disabling of acknowledged interrupts
51 static PIC_MASK pic_mask_intr = {.both = 0x0000};
53 extern IMPORTED ULONG DpcQueueSize;
55 static ULONG HalpPendingInterruptCount[NR_IRQS];
57 #define DIRQL_TO_IRQ(x) (PROFILE_LEVEL - x)
58 #define IRQ_TO_DIRQL(x) (PROFILE_LEVEL - x)
61 KiInterruptDispatch2 (ULONG Irq, KIRQL old_level);
63 /* FUNCTIONS ****************************************************************/
65 KIRQL STDCALL KeGetCurrentIrql (VOID)
67 * PURPOSE: Returns the current irq level
68 * RETURNS: The current irq level
74 VOID HalpInitPICs(VOID)
76 memset(HalpPendingInterruptCount, 0, sizeof(HalpPendingInterruptCount));
78 /* Initialization sequence */
79 WRITE_PORT_UCHAR((PUCHAR)0x20, 0x11);
80 WRITE_PORT_UCHAR((PUCHAR)0xa0, 0x11);
81 /* Start of hardware irqs (0x24) */
82 WRITE_PORT_UCHAR((PUCHAR)0x21, 0x40);
83 WRITE_PORT_UCHAR((PUCHAR)0xa1, 0x48);
84 /* 8259-1 is master */
85 WRITE_PORT_UCHAR((PUCHAR)0x21, 0x4);
87 WRITE_PORT_UCHAR((PUCHAR)0xa1, 0x2);
89 WRITE_PORT_UCHAR((PUCHAR)0x21, 0x1);
90 WRITE_PORT_UCHAR((PUCHAR)0xa1, 0x1);
91 /* Enable interrupts */
92 WRITE_PORT_UCHAR((PUCHAR)0x21, pic_mask.master);
93 WRITE_PORT_UCHAR((PUCHAR)0xa1, pic_mask.slave);
95 /* We can now enable interrupts */
96 __asm__ __volatile__ ("sti\n\t");
99 VOID HalpEndSystemInterrupt(KIRQL Irql)
101 * FUNCTION: Enable all irqs with higher priority.
104 const USHORT mask[] =
106 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
107 0x0000, 0x0000, 0x0000, 0x0000, 0x8000, 0xc000, 0xe000, 0xf000,
108 0xf800, 0xfc00, 0xfe00, 0xff00, 0xff80, 0xffc0, 0xffe0, 0xfff0,
109 0xfff8, 0xfffc, 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
112 /* Interrupts should be disable while enabling irqs of both pics */
113 __asm__("pushf\n\t");
115 pic_mask_intr.both &= mask[Irql];
116 WRITE_PORT_UCHAR((PUCHAR)0x21, pic_mask.master|pic_mask_intr.master);
117 WRITE_PORT_UCHAR((PUCHAR)0xa1, pic_mask.slave|pic_mask_intr.slave);
122 HalpExecuteIrqs(KIRQL NewIrql)
126 IrqLimit = min(PROFILE_LEVEL - NewIrql, NR_IRQS);
129 * For each irq if there have been any deferred interrupts then now
132 for (i = 0; i < IrqLimit; i++)
134 if (HalpPendingInterruptCount[i] > 0)
136 CurrentIrql = IRQ_TO_DIRQL(i);
138 while (HalpPendingInterruptCount[i] > 0)
141 * For each deferred interrupt execute all the handlers at DIRQL.
143 KiInterruptDispatch2(i, NewIrql);
144 HalpPendingInterruptCount[i]--;
147 HalpEndSystemInterrupt(CurrentIrql);
154 HalpLowerIrql(KIRQL NewIrql)
156 if (NewIrql >= PROFILE_LEVEL)
158 CurrentIrql = NewIrql;
161 HalpExecuteIrqs(NewIrql);
162 if (NewIrql >= DISPATCH_LEVEL)
164 CurrentIrql = NewIrql;
167 CurrentIrql = DISPATCH_LEVEL;
168 if (DpcQueueSize > 0)
170 KiDispatchInterrupt();
172 CurrentIrql = APC_LEVEL;
173 if (NewIrql == APC_LEVEL)
177 if (KeGetCurrentThread() != NULL &&
178 KeGetCurrentThread()->ApcState.KernelApcPending)
180 KiDeliverApc(0, 0, 0);
182 CurrentIrql = PASSIVE_LEVEL;
185 /**********************************************************************
190 * Restores the irq level on the current processor
193 * NewIrql = Irql to lower to
199 * Uses fastcall convention
202 KfLowerIrql (KIRQL NewIrql)
206 DPRINT("KfLowerIrql(NewIrql %d)\n", NewIrql);
208 if (NewIrql > CurrentIrql)
210 DbgPrint ("(%s:%d) NewIrql %x CurrentIrql %x\n",
211 __FILE__, __LINE__, NewIrql, CurrentIrql);
216 HalpLowerIrql(NewIrql);
220 /**********************************************************************
225 * Restores the irq level on the current processor
228 * NewIrql = Irql to lower to
237 KeLowerIrql (KIRQL NewIrql)
239 KfLowerIrql (NewIrql);
243 /**********************************************************************
248 * Raises the hardware priority (irql)
251 * NewIrql = Irql to raise to
257 * Uses fastcall convention
261 KfRaiseIrql (KIRQL NewIrql)
265 DPRINT("KfRaiseIrql(NewIrql %d)\n", NewIrql);
267 if (NewIrql < CurrentIrql)
269 DbgPrint ("%s:%d CurrentIrql %x NewIrql %x\n",
270 __FILE__,__LINE__,CurrentIrql,NewIrql);
275 OldIrql = CurrentIrql;
276 CurrentIrql = NewIrql;
281 /**********************************************************************
286 * Raises the hardware priority (irql)
289 * NewIrql = Irql to raise to
290 * OldIrql (OUT) = Caller supplied storage for the previous irql
299 KeRaiseIrql (KIRQL NewIrql,
302 *OldIrql = KfRaiseIrql (NewIrql);
306 /**********************************************************************
308 * KeRaiseIrqlToDpcLevel
311 * Raises the hardware priority (irql) to DISPATCH level
324 KeRaiseIrqlToDpcLevel (VOID)
326 return KfRaiseIrql (DISPATCH_LEVEL);
330 /**********************************************************************
332 * KeRaiseIrqlToSynchLevel
335 * Raises the hardware priority (irql) to CLOCK2 level
348 KeRaiseIrqlToSynchLevel (VOID)
350 return KfRaiseIrql (CLOCK2_LEVEL);
355 HalBeginSystemInterrupt (ULONG Vector,
360 if (Vector < IRQ_BASE || Vector >= IRQ_BASE + NR_IRQS)
364 irq = Vector - IRQ_BASE;
365 pic_mask_intr.both |= ((1 << irq) & 0xfffe); // do not disable the timer interrupt
369 WRITE_PORT_UCHAR((PUCHAR)0x21, pic_mask.master|pic_mask_intr.master);
370 WRITE_PORT_UCHAR((PUCHAR)0x20, 0x20);
374 WRITE_PORT_UCHAR((PUCHAR)0xa1, pic_mask.slave|pic_mask_intr.slave);
375 /* Send EOI to the PICs */
376 WRITE_PORT_UCHAR((PUCHAR)0x20,0x20);
377 WRITE_PORT_UCHAR((PUCHAR)0xa0,0x20);
380 if (CurrentIrql >= Irql)
382 HalpPendingInterruptCount[irq]++;
385 *OldIrql = CurrentIrql;
392 VOID STDCALL HalEndSystemInterrupt (KIRQL Irql, ULONG Unknown2)
394 * FUNCTION: Finish a system interrupt and restore the specified irq level.
398 HalpEndSystemInterrupt(Irql);
401 BOOLEAN STDCALL HalDisableSystemInterrupt (ULONG Vector,
406 if (Vector < IRQ_BASE || Vector >= IRQ_BASE + NR_IRQS)
409 irq = Vector - IRQ_BASE;
410 pic_mask.both |= (1 << irq);
413 WRITE_PORT_UCHAR((PUCHAR)0x21, pic_mask.master|pic_mask_intr.slave);
417 WRITE_PORT_UCHAR((PUCHAR)0xa1, pic_mask.slave|pic_mask_intr.slave);
424 BOOLEAN STDCALL HalEnableSystemInterrupt (ULONG Vector,
430 if (Vector < IRQ_BASE || Vector >= IRQ_BASE + NR_IRQS)
433 irq = Vector - IRQ_BASE;
434 pic_mask.both &= ~(1 << irq);
437 WRITE_PORT_UCHAR((PUCHAR)0x21, pic_mask.master|pic_mask_intr.master);
441 WRITE_PORT_UCHAR((PUCHAR)0xa1, pic_mask.slave|pic_mask_intr.slave);