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)
212 DPRINT("KfLowerIrql(NewIrql %d)\n", NewIrql);
214 if (NewIrql > CurrentIrql)
216 DbgPrint ("(%s:%d) NewIrql %x CurrentIrql %x\n",
217 __FILE__, __LINE__, NewIrql, CurrentIrql);
223 HalpLowerIrql(NewIrql);
224 #else /* LIBCAPTIVE */
225 CurrentIrql = NewIrql;
226 #endif /* LIBCAPTIVE */
230 /**********************************************************************
235 * Restores the irq level on the current processor
238 * NewIrql = Irql to lower to
247 KeLowerIrql (KIRQL NewIrql)
249 KfLowerIrql (NewIrql);
253 /**********************************************************************
258 * Raises the hardware priority (irql)
261 * NewIrql = Irql to raise to
267 * Uses fastcall convention
271 KfRaiseIrql (KIRQL NewIrql)
275 DPRINT("KfRaiseIrql(NewIrql %d)\n", NewIrql);
277 if (NewIrql < CurrentIrql)
279 DbgPrint ("%s:%d CurrentIrql %x NewIrql %x\n",
280 __FILE__,__LINE__,CurrentIrql,NewIrql);
285 OldIrql = CurrentIrql;
286 CurrentIrql = NewIrql;
291 /**********************************************************************
296 * Raises the hardware priority (irql)
299 * NewIrql = Irql to raise to
300 * OldIrql (OUT) = Caller supplied storage for the previous irql
309 KeRaiseIrql (KIRQL NewIrql,
312 *OldIrql = KfRaiseIrql (NewIrql);
317 /**********************************************************************
319 * KeRaiseIrqlToDpcLevel
322 * Raises the hardware priority (irql) to DISPATCH level
335 KeRaiseIrqlToDpcLevel (VOID)
337 return KfRaiseIrql (DISPATCH_LEVEL);
341 /**********************************************************************
343 * KeRaiseIrqlToSynchLevel
346 * Raises the hardware priority (irql) to CLOCK2 level
359 KeRaiseIrqlToSynchLevel (VOID)
361 return KfRaiseIrql (CLOCK2_LEVEL);
366 HalBeginSystemInterrupt (ULONG Vector,
371 if (Vector < IRQ_BASE || Vector >= IRQ_BASE + NR_IRQS)
375 irq = Vector - IRQ_BASE;
376 pic_mask_intr.both |= ((1 << irq) & 0xfffe); // do not disable the timer interrupt
380 WRITE_PORT_UCHAR((PUCHAR)0x21, pic_mask.master|pic_mask_intr.master);
381 WRITE_PORT_UCHAR((PUCHAR)0x20, 0x20);
385 WRITE_PORT_UCHAR((PUCHAR)0xa1, pic_mask.slave|pic_mask_intr.slave);
386 /* Send EOI to the PICs */
387 WRITE_PORT_UCHAR((PUCHAR)0x20,0x20);
388 WRITE_PORT_UCHAR((PUCHAR)0xa0,0x20);
391 if (CurrentIrql >= Irql)
393 HalpPendingInterruptCount[irq]++;
396 *OldIrql = CurrentIrql;
403 VOID STDCALL HalEndSystemInterrupt (KIRQL Irql, ULONG Unknown2)
405 * FUNCTION: Finish a system interrupt and restore the specified irq level.
409 HalpEndSystemInterrupt(Irql);
412 BOOLEAN STDCALL HalDisableSystemInterrupt (ULONG Vector,
417 if (Vector < IRQ_BASE || Vector >= IRQ_BASE + NR_IRQS)
420 irq = Vector - IRQ_BASE;
421 pic_mask.both |= (1 << irq);
424 WRITE_PORT_UCHAR((PUCHAR)0x21, pic_mask.master|pic_mask_intr.slave);
428 WRITE_PORT_UCHAR((PUCHAR)0xa1, pic_mask.slave|pic_mask_intr.slave);
435 BOOLEAN STDCALL HalEnableSystemInterrupt (ULONG Vector,
441 if (Vector < IRQ_BASE || Vector >= IRQ_BASE + NR_IRQS)
444 irq = Vector - IRQ_BASE;
445 pic_mask.both &= ~(1 << irq);
448 WRITE_PORT_UCHAR((PUCHAR)0x21, pic_mask.master|pic_mask_intr.master);
452 WRITE_PORT_UCHAR((PUCHAR)0xa1, pic_mask.slave|pic_mask_intr.slave);
458 #endif /* LIBCAPTIVE */