1 /* $Id: irql.c,v 1.22 2004/11/21 21:53:06 ion Exp $
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 *****************************************************************/
13 #include <ddk/ntddk.h>
14 #include <internal/ps.h>
15 #include <ntos/minmax.h>
20 #include <internal/debug.h>
22 /* GLOBALS ******************************************************************/
25 * FIXME: Use EISA_CONTROL STRUCTURE INSTEAD OF HARD-CODED OFFSETS
40 * PURPOSE: - Mask for HalEnableSystemInterrupt and HalDisableSystemInterrupt
41 * - At startup enable timer and cascade
44 static PIC_MASK pic_mask
= {.both
= 0xFFFA};
46 static PIC_MASK pic_mask
= { 0xFFFA };
51 * PURPOSE: Mask for disabling of acknowledged interrupts
54 static PIC_MASK pic_mask_intr
= {.both
= 0x0000};
56 static PIC_MASK pic_mask_intr
= { 0 };
59 static ULONG HalpPendingInterruptCount
[NR_IRQS
];
61 #define DIRQL_TO_IRQ(x) (PROFILE_LEVEL - x)
62 #define IRQ_TO_DIRQL(x) (PROFILE_LEVEL - x)
65 KiInterruptDispatch2 (ULONG Irq
, KIRQL old_level
);
67 /* FUNCTIONS ****************************************************************/
69 KIRQL STDCALL
KeGetCurrentIrql (VOID
)
71 * PURPOSE: Returns the current irq level
72 * RETURNS: The current irq level
75 return(KeGetCurrentKPCR()->Irql
);
78 VOID
HalpInitPICs(VOID
)
80 memset(HalpPendingInterruptCount
, 0, sizeof(HalpPendingInterruptCount
));
82 /* Initialization sequence */
83 WRITE_PORT_UCHAR((PUCHAR
)0x20, 0x11);
84 WRITE_PORT_UCHAR((PUCHAR
)0xa0, 0x11);
85 /* Start of hardware irqs (0x24) */
86 WRITE_PORT_UCHAR((PUCHAR
)0x21, IRQ_BASE
);
87 WRITE_PORT_UCHAR((PUCHAR
)0xa1, IRQ_BASE
+ 8);
88 /* 8259-1 is master */
89 WRITE_PORT_UCHAR((PUCHAR
)0x21, 0x4);
91 WRITE_PORT_UCHAR((PUCHAR
)0xa1, 0x2);
93 WRITE_PORT_UCHAR((PUCHAR
)0x21, 0x1);
94 WRITE_PORT_UCHAR((PUCHAR
)0xa1, 0x1);
95 /* Enable interrupts */
96 WRITE_PORT_UCHAR((PUCHAR
)0x21, pic_mask
.master
);
97 WRITE_PORT_UCHAR((PUCHAR
)0xa1, pic_mask
.slave
);
99 /* We can now enable interrupts */
100 Ki386EnableInterrupts();
103 VOID
HalpEndSystemInterrupt(KIRQL Irql
)
105 * FUNCTION: Enable all irqs with higher priority.
109 const USHORT mask
[] =
111 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
112 0x0000, 0x0000, 0x0000, 0x0000, 0x8000, 0xc000, 0xe000, 0xf000,
113 0xf800, 0xfc00, 0xfe00, 0xff00, 0xff80, 0xffc0, 0xffe0, 0xfff0,
114 0xfff8, 0xfffc, 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
117 /* Interrupts should be disable while enabling irqs of both pics */
118 Ki386SaveFlags(flags
);
119 Ki386DisableInterrupts();
121 pic_mask_intr
.both
&= mask
[Irql
];
122 WRITE_PORT_UCHAR((PUCHAR
)0x21, (UCHAR
)(pic_mask
.master
|pic_mask_intr
.master
));
123 WRITE_PORT_UCHAR((PUCHAR
)0xa1, (UCHAR
)(pic_mask
.slave
|pic_mask_intr
.slave
));
126 Ki386RestoreFlags(flags
);
130 HalpExecuteIrqs(KIRQL NewIrql
)
134 IrqLimit
= min(PROFILE_LEVEL
- NewIrql
, NR_IRQS
);
137 * For each irq if there have been any deferred interrupts then now
140 for (i
= 0; i
< IrqLimit
; i
++)
142 if (HalpPendingInterruptCount
[i
] > 0)
144 KeGetCurrentKPCR()->Irql
= (KIRQL
)IRQ_TO_DIRQL(i
);
146 while (HalpPendingInterruptCount
[i
] > 0)
149 * For each deferred interrupt execute all the handlers at DIRQL.
151 HalpPendingInterruptCount
[i
]--;
152 KiInterruptDispatch2(i
+ IRQ_BASE
, NewIrql
);
154 KeGetCurrentKPCR()->Irql
--;
155 HalpEndSystemInterrupt(KeGetCurrentKPCR()->Irql
);
162 HalpLowerIrql(KIRQL NewIrql
)
164 if (NewIrql
>= PROFILE_LEVEL
)
166 KeGetCurrentKPCR()->Irql
= NewIrql
;
169 HalpExecuteIrqs(NewIrql
);
170 if (NewIrql
>= DISPATCH_LEVEL
)
172 KeGetCurrentKPCR()->Irql
= NewIrql
;
175 KeGetCurrentKPCR()->Irql
= DISPATCH_LEVEL
;
176 if (KeGetCurrentKPCR()->HalReserved
[HAL_DPC_REQUEST
])
178 KeGetCurrentKPCR()->HalReserved
[HAL_DPC_REQUEST
] = FALSE
;
179 KiDispatchInterrupt();
181 KeGetCurrentKPCR()->Irql
= APC_LEVEL
;
182 if (NewIrql
== APC_LEVEL
)
186 if (KeGetCurrentThread() != NULL
&&
187 KeGetCurrentThread()->ApcState
.KernelApcPending
)
189 KiDeliverApc(KernelMode
, NULL
, NULL
);
191 KeGetCurrentKPCR()->Irql
= PASSIVE_LEVEL
;
194 /**********************************************************************
199 * Restores the irq level on the current processor
202 * NewIrql = Irql to lower to
208 * Uses fastcall convention
211 KfLowerIrql (KIRQL NewIrql
)
213 DPRINT("KfLowerIrql(NewIrql %d)\n", NewIrql
);
215 if (NewIrql
> KeGetCurrentKPCR()->Irql
)
217 DbgPrint ("(%s:%d) NewIrql %x CurrentIrql %x\n",
218 __FILE__
, __LINE__
, NewIrql
, KeGetCurrentKPCR()->Irql
);
223 HalpLowerIrql(NewIrql
);
227 /**********************************************************************
232 * Restores the irq level on the current processor
235 * NewIrql = Irql to lower to
244 KeLowerIrql (KIRQL NewIrql
)
246 KfLowerIrql (NewIrql
);
250 /**********************************************************************
255 * Raises the hardware priority (irql)
258 * NewIrql = Irql to raise to
264 * Uses fastcall convention
268 KfRaiseIrql (KIRQL NewIrql
)
272 DPRINT("KfRaiseIrql(NewIrql %d)\n", NewIrql
);
274 if (NewIrql
< KeGetCurrentKPCR()->Irql
)
276 DbgPrint ("%s:%d CurrentIrql %x NewIrql %x\n",
277 __FILE__
,__LINE__
,KeGetCurrentKPCR()->Irql
,NewIrql
);
282 OldIrql
= KeGetCurrentKPCR()->Irql
;
283 KeGetCurrentKPCR()->Irql
= NewIrql
;
288 /**********************************************************************
293 * Raises the hardware priority (irql)
296 * NewIrql = Irql to raise to
297 * OldIrql (OUT) = Caller supplied storage for the previous irql
306 KeRaiseIrql (KIRQL NewIrql
,
309 *OldIrql
= KfRaiseIrql (NewIrql
);
313 /**********************************************************************
315 * KeRaiseIrqlToDpcLevel
318 * Raises the hardware priority (irql) to DISPATCH level
331 KeRaiseIrqlToDpcLevel (VOID
)
333 return KfRaiseIrql (DISPATCH_LEVEL
);
337 /**********************************************************************
339 * KeRaiseIrqlToSynchLevel
342 * Raises the hardware priority (irql) to CLOCK2 level
355 KeRaiseIrqlToSynchLevel (VOID
)
357 return KfRaiseIrql (CLOCK2_LEVEL
);
362 HalBeginSystemInterrupt (ULONG Vector
,
367 if (Vector
< IRQ_BASE
|| Vector
>= IRQ_BASE
+ NR_IRQS
)
371 irq
= Vector
- IRQ_BASE
;
372 pic_mask_intr
.both
|= ((1 << irq
) & 0xfffe); // do not disable the timer interrupt
376 WRITE_PORT_UCHAR((PUCHAR
)0x21, (UCHAR
)(pic_mask
.master
|pic_mask_intr
.master
));
377 WRITE_PORT_UCHAR((PUCHAR
)0x20, 0x20);
381 WRITE_PORT_UCHAR((PUCHAR
)0xa1, (UCHAR
)(pic_mask
.slave
|pic_mask_intr
.slave
));
382 /* Send EOI to the PICs */
383 WRITE_PORT_UCHAR((PUCHAR
)0x20,0x20);
384 WRITE_PORT_UCHAR((PUCHAR
)0xa0,0x20);
387 if (KeGetCurrentKPCR()->Irql
>= Irql
)
389 HalpPendingInterruptCount
[irq
]++;
392 *OldIrql
= KeGetCurrentKPCR()->Irql
;
393 KeGetCurrentKPCR()->Irql
= Irql
;
399 VOID STDCALL
HalEndSystemInterrupt (KIRQL Irql
, ULONG Unknown2
)
401 * FUNCTION: Finish a system interrupt and restore the specified irq level.
405 HalpEndSystemInterrupt(Irql
);
410 HalDisableSystemInterrupt(
416 if (Vector
< IRQ_BASE
|| Vector
>= IRQ_BASE
+ NR_IRQS
)
419 irq
= Vector
- IRQ_BASE
;
420 pic_mask
.both
|= (1 << irq
);
423 WRITE_PORT_UCHAR((PUCHAR
)0x21, (UCHAR
)(pic_mask
.master
|pic_mask_intr
.slave
));
427 WRITE_PORT_UCHAR((PUCHAR
)0xa1, (UCHAR
)(pic_mask
.slave
|pic_mask_intr
.slave
));
436 HalEnableSystemInterrupt(
439 KINTERRUPT_MODE InterruptMode
)
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, (UCHAR
)(pic_mask
.master
|pic_mask_intr
.master
));
454 WRITE_PORT_UCHAR((PUCHAR
)0xa1, (UCHAR
)(pic_mask
.slave
|pic_mask_intr
.slave
));
462 HalRequestSoftwareInterrupt(
468 KeGetCurrentKPCR()->HalReserved
[HAL_APC_REQUEST
] = TRUE
;
472 KeGetCurrentKPCR()->HalReserved
[HAL_DPC_REQUEST
] = TRUE
;