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;
44 * PURPOSE: - Mask for HalEnableSystemInterrupt and HalDisableSystemInterrupt
45 * - At startup enable timer and cascade
47 static PIC_MASK pic_mask = {.both = 0xFFFA};
51 * PURPOSE: Mask for disabling of acknowledged interrupts
53 static PIC_MASK pic_mask_intr = {.both = 0x0000};
55 extern IMPORTED ULONG DpcQueueSize;
57 static ULONG HalpPendingInterruptCount[NR_IRQS];
59 #define DIRQL_TO_IRQ(x) (PROFILE_LEVEL - x)
60 #define IRQ_TO_DIRQL(x) (PROFILE_LEVEL - x)
63 KiInterruptDispatch2 (ULONG Irq, KIRQL old_level);
65 #endif /* LIBCAPTIVE */
67 /* FUNCTIONS ****************************************************************/
69 KIRQL STDCALL KeGetCurrentIrql (VOID)
71 * PURPOSE: Returns the current irq level
72 * RETURNS: The current irq level
80 VOID HalpInitPICs(VOID)
82 memset(HalpPendingInterruptCount, 0, sizeof(HalpPendingInterruptCount));
84 /* Initialization sequence */
85 WRITE_PORT_UCHAR((PUCHAR)0x20, 0x11);
86 WRITE_PORT_UCHAR((PUCHAR)0xa0, 0x11);
87 /* Start of hardware irqs (0x24) */
88 WRITE_PORT_UCHAR((PUCHAR)0x21, 0x40);
89 WRITE_PORT_UCHAR((PUCHAR)0xa1, 0x48);
90 /* 8259-1 is master */
91 WRITE_PORT_UCHAR((PUCHAR)0x21, 0x4);
93 WRITE_PORT_UCHAR((PUCHAR)0xa1, 0x2);
95 WRITE_PORT_UCHAR((PUCHAR)0x21, 0x1);
96 WRITE_PORT_UCHAR((PUCHAR)0xa1, 0x1);
97 /* Enable interrupts */
98 WRITE_PORT_UCHAR((PUCHAR)0x21, pic_mask.master);
99 WRITE_PORT_UCHAR((PUCHAR)0xa1, pic_mask.slave);
101 /* We can now enable interrupts */
102 __asm__ __volatile__ ("sti\n\t");
105 VOID HalpEndSystemInterrupt(KIRQL Irql)
107 * FUNCTION: Enable all irqs with higher priority.
110 const USHORT mask[] =
112 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
113 0x0000, 0x0000, 0x0000, 0x0000, 0x8000, 0xc000, 0xe000, 0xf000,
114 0xf800, 0xfc00, 0xfe00, 0xff00, 0xff80, 0xffc0, 0xffe0, 0xfff0,
115 0xfff8, 0xfffc, 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
118 /* Interrupts should be disable while enabling irqs of both pics */
119 __asm__("pushf\n\t");
121 pic_mask_intr.both &= mask[Irql];
122 WRITE_PORT_UCHAR((PUCHAR)0x21, pic_mask.master|pic_mask_intr.master);
123 WRITE_PORT_UCHAR((PUCHAR)0xa1, pic_mask.slave|pic_mask_intr.slave);
128 HalpExecuteIrqs(KIRQL NewIrql)
132 IrqLimit = min(PROFILE_LEVEL - NewIrql, NR_IRQS);
135 * For each irq if there have been any deferred interrupts then now
138 for (i = 0; i < IrqLimit; i++)
140 if (HalpPendingInterruptCount[i] > 0)
142 CurrentIrql = IRQ_TO_DIRQL(i);
144 while (HalpPendingInterruptCount[i] > 0)
147 * For each deferred interrupt execute all the handlers at DIRQL.
149 KiInterruptDispatch2(i, NewIrql);
150 HalpPendingInterruptCount[i]--;
153 HalpEndSystemInterrupt(CurrentIrql);
160 HalpLowerIrql(KIRQL NewIrql)
162 if (NewIrql >= PROFILE_LEVEL)
164 CurrentIrql = NewIrql;
167 HalpExecuteIrqs(NewIrql);
168 if (NewIrql >= DISPATCH_LEVEL)
170 CurrentIrql = NewIrql;
173 CurrentIrql = DISPATCH_LEVEL;
174 if (DpcQueueSize > 0)
176 KiDispatchInterrupt();
178 CurrentIrql = APC_LEVEL;
179 if (NewIrql == APC_LEVEL)
183 if (KeGetCurrentThread() != NULL &&
184 KeGetCurrentThread()->ApcState.KernelApcPending)
186 KiDeliverApc(0, 0, 0);
188 CurrentIrql = PASSIVE_LEVEL;
191 #endif /* LIBCAPTIVE */
193 /**********************************************************************
198 * Restores the irq level on the current processor
201 * NewIrql = Irql to lower to
207 * Uses fastcall convention
210 KfLowerIrql (KIRQL NewIrql)
214 DPRINT("KfLowerIrql(NewIrql %d)\n", NewIrql);
216 if (NewIrql > CurrentIrql)
218 DbgPrint ("(%s:%d) NewIrql %x CurrentIrql %x\n",
219 __FILE__, __LINE__, NewIrql, CurrentIrql);
225 HalpLowerIrql(NewIrql);
226 #else /* LIBCAPTIVE */
227 CurrentIrql = NewIrql;
228 #endif /* LIBCAPTIVE */
232 /**********************************************************************
237 * Restores the irq level on the current processor
240 * NewIrql = Irql to lower to
249 KeLowerIrql (KIRQL NewIrql)
251 KfLowerIrql (NewIrql);
255 /**********************************************************************
260 * Raises the hardware priority (irql)
263 * NewIrql = Irql to raise to
269 * Uses fastcall convention
273 KfRaiseIrql (KIRQL NewIrql)
277 DPRINT("KfRaiseIrql(NewIrql %d)\n", NewIrql);
279 if (NewIrql < CurrentIrql)
281 DbgPrint ("%s:%d CurrentIrql %x NewIrql %x\n",
282 __FILE__,__LINE__,CurrentIrql,NewIrql);
287 OldIrql = CurrentIrql;
288 CurrentIrql = NewIrql;
293 /**********************************************************************
298 * Raises the hardware priority (irql)
301 * NewIrql = Irql to raise to
302 * OldIrql (OUT) = Caller supplied storage for the previous irql
311 KeRaiseIrql (KIRQL NewIrql,
314 *OldIrql = KfRaiseIrql (NewIrql);
319 /**********************************************************************
321 * KeRaiseIrqlToDpcLevel
324 * Raises the hardware priority (irql) to DISPATCH level
337 KeRaiseIrqlToDpcLevel (VOID)
339 return KfRaiseIrql (DISPATCH_LEVEL);
343 /**********************************************************************
345 * KeRaiseIrqlToSynchLevel
348 * Raises the hardware priority (irql) to CLOCK2 level
361 KeRaiseIrqlToSynchLevel (VOID)
363 return KfRaiseIrql (CLOCK2_LEVEL);
368 HalBeginSystemInterrupt (ULONG Vector,
373 if (Vector < IRQ_BASE || Vector >= IRQ_BASE + NR_IRQS)
377 irq = Vector - IRQ_BASE;
378 pic_mask_intr.both |= ((1 << irq) & 0xfffe); // do not disable the timer interrupt
382 WRITE_PORT_UCHAR((PUCHAR)0x21, pic_mask.master|pic_mask_intr.master);
383 WRITE_PORT_UCHAR((PUCHAR)0x20, 0x20);
387 WRITE_PORT_UCHAR((PUCHAR)0xa1, pic_mask.slave|pic_mask_intr.slave);
388 /* Send EOI to the PICs */
389 WRITE_PORT_UCHAR((PUCHAR)0x20,0x20);
390 WRITE_PORT_UCHAR((PUCHAR)0xa0,0x20);
393 if (CurrentIrql >= Irql)
395 HalpPendingInterruptCount[irq]++;
398 *OldIrql = CurrentIrql;
405 VOID STDCALL HalEndSystemInterrupt (KIRQL Irql, ULONG Unknown2)
407 * FUNCTION: Finish a system interrupt and restore the specified irq level.
411 HalpEndSystemInterrupt(Irql);
414 BOOLEAN STDCALL HalDisableSystemInterrupt (ULONG Vector,
419 if (Vector < IRQ_BASE || Vector >= IRQ_BASE + NR_IRQS)
422 irq = Vector - IRQ_BASE;
423 pic_mask.both |= (1 << irq);
426 WRITE_PORT_UCHAR((PUCHAR)0x21, pic_mask.master|pic_mask_intr.slave);
430 WRITE_PORT_UCHAR((PUCHAR)0xa1, pic_mask.slave|pic_mask_intr.slave);
437 BOOLEAN STDCALL HalEnableSystemInterrupt (ULONG Vector,
443 if (Vector < IRQ_BASE || Vector >= IRQ_BASE + NR_IRQS)
446 irq = Vector - IRQ_BASE;
447 pic_mask.both &= ~(1 << irq);
450 WRITE_PORT_UCHAR((PUCHAR)0x21, pic_mask.master|pic_mask_intr.master);
454 WRITE_PORT_UCHAR((PUCHAR)0xa1, pic_mask.slave|pic_mask_intr.slave);
460 #endif /* LIBCAPTIVE */