2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/hal/x86/mpsirql.c
5 * PURPOSE: Implements IRQLs for multiprocessor systems
6 * PROGRAMMERS: David Welch (welch@cwcom.net)
7 * Casper S. Hornstrup (chorns@users.sourceforge.net)
9 * 12/04/2001 CSH Created
12 /* INCLUDES *****************************************************************/
14 #include <ddk/ntddk.h>
15 #include <internal/ke.h>
16 #include <internal/ps.h>
17 #include <ntos/minmax.h>
21 #include <internal/debug.h>
23 /* GLOBALS ******************************************************************/;
25 #define IRQ_BASE (0x30)
26 #define NR_VECTORS (0x100 - IRQ_BASE)
28 extern IMPORTED ULONG DpcQueueSize;
30 static ULONG HalpPendingInterruptCount[NR_VECTORS];
32 static VOID KeSetCurrentIrql (KIRQL newlvl);
35 KiInterruptDispatch2 (ULONG Irq, KIRQL old_level);
37 #define IRQL2TPR(irql) (FIRST_DEVICE_VECTOR + ((irql - DISPATCH_LEVEL /* 2 */ - 1) * 8))
39 /* FUNCTIONS ****************************************************************/
41 KIRQL STDCALL KeGetCurrentIrql (VOID)
43 * PURPOSE: Returns the current irq level
44 * RETURNS: The current irq level
47 if (KeGetCurrentKPCR ()->Irql > HIGH_LEVEL)
49 DPRINT1 ("CurrentIrql %x\n", KeGetCurrentKPCR ()->Irql);
54 return(KeGetCurrentKPCR ()->Irql);
58 static VOID KeSetCurrentIrql (KIRQL NewIrql)
60 * PURPOSE: Sets the current irq level without taking any action
63 if (NewIrql > HIGH_LEVEL)
65 DPRINT1 ("NewIrql %x\n", NewIrql);
70 KeGetCurrentKPCR ()->Irql = NewIrql;
74 VOID HalpEndSystemInterrupt (KIRQL Irql)
76 * FUNCTION: Enable all irqs with higher priority.
79 /* Interrupts should be disabled while enabling irqs */
82 APICWrite (APIC_TPR, IRQL2TPR (Irql) & APIC_TPR_PRI);
88 HalpExecuteIrqs(KIRQL NewIrql)
92 VectorLimit = min(IRQL2VECTOR (NewIrql), NR_VECTORS);
95 * For each vector if there have been any deferred interrupts then now
98 for (i = 0; i < VectorLimit; i++)
100 if (HalpPendingInterruptCount[i] > 0)
102 KeSetCurrentIrql (VECTOR2IRQL (i));
104 while (HalpPendingInterruptCount[i] > 0)
107 * For each deferred interrupt execute all the handlers at DIRQL.
109 KiInterruptDispatch2 (i, NewIrql);
110 HalpPendingInterruptCount[i]--;
112 KeSetCurrentIrql (KeGetCurrentIrql () - 1);
113 HalpEndSystemInterrupt (KeGetCurrentIrql ());
121 HalpLowerIrql(KIRQL NewIrql)
123 if (NewIrql >= PROFILE_LEVEL)
125 KeSetCurrentIrql (NewIrql);
128 HalpExecuteIrqs (NewIrql);
129 if (NewIrql >= DISPATCH_LEVEL)
131 KeSetCurrentIrql (NewIrql);
134 KeSetCurrentIrql (DISPATCH_LEVEL);
135 if (DpcQueueSize > 0)
137 KiDispatchInterrupt ();
139 KeSetCurrentIrql (APC_LEVEL);
140 if (NewIrql == APC_LEVEL)
144 if (KeGetCurrentThread () != NULL &&
145 KeGetCurrentThread ()->ApcState.KernelApcPending)
147 KiDeliverApc (0, 0, 0);
149 KeSetCurrentIrql (PASSIVE_LEVEL);
153 /**********************************************************************
158 * Restores the irq level on the current processor
161 * NewIrql = Irql to lower to
167 * Uses fastcall convention
170 KfLowerIrql (KIRQL NewIrql)
174 if (NewIrql > KeGetCurrentIrql ())
176 DPRINT1 ("NewIrql %x CurrentIrql %x\n", NewIrql, KeGetCurrentIrql ());
181 HalpLowerIrql (NewIrql);
185 /**********************************************************************
190 * Restores the irq level on the current processor
193 * NewIrql = Irql to lower to
202 KeLowerIrql (KIRQL NewIrql)
204 KfLowerIrql (NewIrql);
208 /**********************************************************************
213 * Raises the hardware priority (irql)
216 * NewIrql = Irql to raise to
222 * Uses fastcall convention
226 KfRaiseIrql (KIRQL NewIrql)
230 if (NewIrql < KeGetCurrentIrql ())
232 DPRINT1 ("CurrentIrql %x NewIrql %x\n", KeGetCurrentIrql (), NewIrql);
237 OldIrql = KeGetCurrentIrql ();
238 KeSetCurrentIrql (NewIrql);
243 /**********************************************************************
248 * Raises the hardware priority (irql)
251 * NewIrql = Irql to raise to
252 * OldIrql (OUT) = Caller supplied storage for the previous irql
261 KeRaiseIrql (KIRQL NewIrql,
264 *OldIrql = KfRaiseIrql (NewIrql);
268 /**********************************************************************
270 * KeRaiseIrqlToDpcLevel
273 * Raises the hardware priority (irql) to DISPATCH level
286 KeRaiseIrqlToDpcLevel (VOID)
288 return KfRaiseIrql (DISPATCH_LEVEL);
292 /**********************************************************************
294 * KeRaiseIrqlToSynchLevel
297 * Raises the hardware priority (irql) to CLOCK2 level
310 KeRaiseIrqlToSynchLevel (VOID)
312 return KfRaiseIrql (CLOCK2_LEVEL);
317 HalBeginSystemInterrupt (ULONG Vector,
321 DPRINT("Vector (0x%X) Irql (0x%X)\n", Vector, Irql);
323 if (Vector < FIRST_DEVICE_VECTOR ||
324 Vector >= FIRST_DEVICE_VECTOR + NUMBER_DEVICE_VECTORS) {
325 DPRINT("Not a device interrupt\n");
329 HalDisableSystemInterrupt (Vector, 0);
333 if (KeGetCurrentIrql () >= Irql)
335 HalpPendingInterruptCount[Vector]++;
338 *OldIrql = KeGetCurrentIrql ();
339 KeSetCurrentIrql (Irql);
346 HalEndSystemInterrupt (KIRQL Irql,
349 * FUNCTION: Finish a system interrupt and restore the specified irq level.
352 HalpLowerIrql (Irql);
353 HalpEndSystemInterrupt (Irql);
357 HalDisableSystemInterrupt (ULONG Vector,
362 DPRINT ("Vector (0x%X)\n", Vector);
364 if (Vector < FIRST_DEVICE_VECTOR ||
365 Vector >= FIRST_DEVICE_VECTOR + NUMBER_DEVICE_VECTORS) {
366 DPRINT("Not a device interrupt\n");
370 irq = VECTOR2IRQ (Vector);
371 IOAPICMaskIrq (ThisCPU (), irq);
378 HalEnableSystemInterrupt (ULONG Vector,
384 DPRINT ("Vector (0x%X)\n", Vector);
386 if (Vector < FIRST_DEVICE_VECTOR ||
387 Vector >= FIRST_DEVICE_VECTOR + NUMBER_DEVICE_VECTORS) {
388 DPRINT("Not a device interrupt\n");
392 irq = VECTOR2IRQ (Vector);
393 IOAPICUnmaskIrq (ThisCPU (), irq);