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 *****************************************************************/
16 /* GLOBALS ******************************************************************/
19 * FIXME: Use EISA_CONTROL STRUCTURE INSTEAD OF HARD-CODED OFFSETS
34 * PURPOSE: - Mask for HalEnableSystemInterrupt and HalDisableSystemInterrupt
35 * - At startup enable timer and cascade
38 static PIC_MASK pic_mask
= {.both
= 0xFFFA};
40 static PIC_MASK pic_mask
= { 0xFFFA };
45 * PURPOSE: Mask for disabling of acknowledged interrupts
48 static PIC_MASK pic_mask_intr
= {.both
= 0x0000};
50 static PIC_MASK pic_mask_intr
= { 0 };
53 static ULONG HalpPendingInterruptCount
[NR_IRQS
];
55 #define DIRQL_TO_IRQ(x) (PROFILE_LEVEL - x)
56 #define IRQ_TO_DIRQL(x) (PROFILE_LEVEL - x)
59 KiInterruptDispatch2 (ULONG Irq
, KIRQL old_level
);
61 /* FUNCTIONS ****************************************************************/
63 #undef KeGetCurrentIrql
64 KIRQL STDCALL
KeGetCurrentIrql (VOID
)
66 * PURPOSE: Returns the current irq level
67 * RETURNS: The current irq level
70 return(KeGetCurrentKPCR()->Irql
);
73 VOID
HalpInitPICs(VOID
)
75 memset(HalpPendingInterruptCount
, 0, sizeof(HalpPendingInterruptCount
));
77 /* Initialization sequence */
78 WRITE_PORT_UCHAR((PUCHAR
)0x20, 0x11);
79 WRITE_PORT_UCHAR((PUCHAR
)0xa0, 0x11);
80 /* Start of hardware irqs (0x24) */
81 WRITE_PORT_UCHAR((PUCHAR
)0x21, IRQ_BASE
);
82 WRITE_PORT_UCHAR((PUCHAR
)0xa1, IRQ_BASE
+ 8);
83 /* 8259-1 is master */
84 WRITE_PORT_UCHAR((PUCHAR
)0x21, 0x4);
86 WRITE_PORT_UCHAR((PUCHAR
)0xa1, 0x2);
88 WRITE_PORT_UCHAR((PUCHAR
)0x21, 0x1);
89 WRITE_PORT_UCHAR((PUCHAR
)0xa1, 0x1);
90 /* Enable interrupts */
91 WRITE_PORT_UCHAR((PUCHAR
)0x21, pic_mask
.master
);
92 WRITE_PORT_UCHAR((PUCHAR
)0xa1, pic_mask
.slave
);
94 /* We can now enable interrupts */
95 Ki386EnableInterrupts();
98 VOID
HalpEndSystemInterrupt(KIRQL Irql
)
100 * 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 Ki386SaveFlags(flags
);
114 Ki386DisableInterrupts();
116 pic_mask_intr
.both
&= mask
[Irql
];
117 WRITE_PORT_UCHAR((PUCHAR
)0x21, (UCHAR
)(pic_mask
.master
|pic_mask_intr
.master
));
118 WRITE_PORT_UCHAR((PUCHAR
)0xa1, (UCHAR
)(pic_mask
.slave
|pic_mask_intr
.slave
));
121 Ki386RestoreFlags(flags
);
125 HalpExecuteIrqs(KIRQL NewIrql
)
129 IrqLimit
= min(PROFILE_LEVEL
- NewIrql
, NR_IRQS
);
132 * For each irq if there have been any deferred interrupts then now
135 for (i
= 0; i
< IrqLimit
; i
++)
137 if (HalpPendingInterruptCount
[i
] > 0)
139 KeGetCurrentKPCR()->Irql
= (KIRQL
)IRQ_TO_DIRQL(i
);
141 while (HalpPendingInterruptCount
[i
] > 0)
144 * For each deferred interrupt execute all the handlers at DIRQL.
146 HalpPendingInterruptCount
[i
]--;
147 KiInterruptDispatch2(i
+ IRQ_BASE
, NewIrql
);
149 KeGetCurrentKPCR()->Irql
--;
150 HalpEndSystemInterrupt(KeGetCurrentKPCR()->Irql
);
157 HalpLowerIrql(KIRQL NewIrql
)
159 if (NewIrql
>= PROFILE_LEVEL
)
161 KeGetCurrentKPCR()->Irql
= NewIrql
;
164 HalpExecuteIrqs(NewIrql
);
165 if (NewIrql
>= DISPATCH_LEVEL
)
167 KeGetCurrentKPCR()->Irql
= NewIrql
;
170 KeGetCurrentKPCR()->Irql
= DISPATCH_LEVEL
;
171 if (((PKIPCR
)KeGetCurrentKPCR())->HalReserved
[HAL_DPC_REQUEST
])
173 ((PKIPCR
)KeGetCurrentKPCR())->HalReserved
[HAL_DPC_REQUEST
] = FALSE
;
174 KiDispatchInterrupt();
176 KeGetCurrentKPCR()->Irql
= APC_LEVEL
;
177 if (NewIrql
== APC_LEVEL
)
181 if (KeGetCurrentThread() != NULL
&&
182 KeGetCurrentThread()->ApcState
.KernelApcPending
)
184 KiDeliverApc(KernelMode
, NULL
, NULL
);
186 KeGetCurrentKPCR()->Irql
= PASSIVE_LEVEL
;
189 /**********************************************************************
194 * Restores the irq level on the current processor
197 * NewIrql = Irql to lower to
203 * Uses fastcall convention
206 KfLowerIrql (KIRQL NewIrql
)
208 DPRINT("KfLowerIrql(NewIrql %d)\n", NewIrql
);
210 if (NewIrql
> KeGetCurrentKPCR()->Irql
)
212 DbgPrint ("(%s:%d) NewIrql %x CurrentIrql %x\n",
213 __FILE__
, __LINE__
, NewIrql
, KeGetCurrentKPCR()->Irql
);
218 HalpLowerIrql(NewIrql
);
222 /**********************************************************************
227 * Restores the irq level on the current processor
230 * NewIrql = Irql to lower to
239 KeLowerIrql (KIRQL NewIrql
)
241 KfLowerIrql (NewIrql
);
245 /**********************************************************************
250 * Raises the hardware priority (irql)
253 * NewIrql = Irql to raise to
259 * Uses fastcall convention
263 KfRaiseIrql (KIRQL NewIrql
)
267 DPRINT("KfRaiseIrql(NewIrql %d)\n", NewIrql
);
269 if (NewIrql
< KeGetCurrentKPCR()->Irql
)
271 DbgPrint ("%s:%d CurrentIrql %x NewIrql %x\n",
272 __FILE__
,__LINE__
,KeGetCurrentKPCR()->Irql
,NewIrql
);
277 OldIrql
= KeGetCurrentKPCR()->Irql
;
278 KeGetCurrentKPCR()->Irql
= NewIrql
;
283 /**********************************************************************
288 * Raises the hardware priority (irql)
291 * NewIrql = Irql to raise to
292 * OldIrql (OUT) = Caller supplied storage for the previous irql
302 KeRaiseIrql (KIRQL NewIrql
,
305 *OldIrql
= KfRaiseIrql (NewIrql
);
309 /**********************************************************************
311 * KeRaiseIrqlToDpcLevel
314 * Raises the hardware priority (irql) to DISPATCH level
327 KeRaiseIrqlToDpcLevel (VOID
)
329 return KfRaiseIrql (DISPATCH_LEVEL
);
333 /**********************************************************************
335 * KeRaiseIrqlToSynchLevel
338 * Raises the hardware priority (irql) to CLOCK2 level
351 KeRaiseIrqlToSynchLevel (VOID
)
353 return KfRaiseIrql (CLOCK2_LEVEL
);
358 HalBeginSystemInterrupt (ULONG Vector
,
363 if (Vector
< IRQ_BASE
|| Vector
>= IRQ_BASE
+ NR_IRQS
)
367 irq
= Vector
- IRQ_BASE
;
368 pic_mask_intr
.both
|= ((1 << irq
) & 0xfffe); // do not disable the timer interrupt
372 WRITE_PORT_UCHAR((PUCHAR
)0x21, (UCHAR
)(pic_mask
.master
|pic_mask_intr
.master
));
373 WRITE_PORT_UCHAR((PUCHAR
)0x20, 0x20);
377 WRITE_PORT_UCHAR((PUCHAR
)0xa1, (UCHAR
)(pic_mask
.slave
|pic_mask_intr
.slave
));
378 /* Send EOI to the PICs */
379 WRITE_PORT_UCHAR((PUCHAR
)0x20,0x20);
380 WRITE_PORT_UCHAR((PUCHAR
)0xa0,0x20);
383 if (KeGetCurrentKPCR()->Irql
>= Irql
)
385 HalpPendingInterruptCount
[irq
]++;
388 *OldIrql
= KeGetCurrentKPCR()->Irql
;
389 KeGetCurrentKPCR()->Irql
= Irql
;
395 VOID STDCALL
HalEndSystemInterrupt (KIRQL Irql
, ULONG Unknown2
)
397 * FUNCTION: Finish a system interrupt and restore the specified irq level.
401 HalpEndSystemInterrupt(Irql
);
406 HalDisableSystemInterrupt(
412 if (Vector
< IRQ_BASE
|| Vector
>= IRQ_BASE
+ NR_IRQS
)
415 irq
= Vector
- IRQ_BASE
;
416 pic_mask
.both
|= (1 << irq
);
419 WRITE_PORT_UCHAR((PUCHAR
)0x21, (UCHAR
)(pic_mask
.master
|pic_mask_intr
.slave
));
423 WRITE_PORT_UCHAR((PUCHAR
)0xa1, (UCHAR
)(pic_mask
.slave
|pic_mask_intr
.slave
));
432 HalEnableSystemInterrupt(
435 KINTERRUPT_MODE InterruptMode
)
439 if (Vector
< IRQ_BASE
|| Vector
>= IRQ_BASE
+ NR_IRQS
)
442 irq
= Vector
- IRQ_BASE
;
443 pic_mask
.both
&= ~(1 << irq
);
446 WRITE_PORT_UCHAR((PUCHAR
)0x21, (UCHAR
)(pic_mask
.master
|pic_mask_intr
.master
));
450 WRITE_PORT_UCHAR((PUCHAR
)0xa1, (UCHAR
)(pic_mask
.slave
|pic_mask_intr
.slave
));
458 HalRequestSoftwareInterrupt(
464 ((PKIPCR
)KeGetCurrentKPCR())->HalReserved
[HAL_APC_REQUEST
] = TRUE
;
468 ((PKIPCR
)KeGetCurrentKPCR())->HalReserved
[HAL_DPC_REQUEST
] = TRUE
;