3a39a3322db308cbf75747679c7c7593c6819e4e
[reactos.git] / reactos / hal / halx86 / irql.c
1 /* $Id: irql.c,v 1.22 2004/11/21 21:53:06 ion Exp $
2 *
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)
8 */
9
10 /* INCLUDES *****************************************************************/
11
12 #include <roscfg.h>
13 #include <ddk/ntddk.h>
14 #include <internal/ps.h>
15 #include <ntos/minmax.h>
16 #include <hal.h>
17 #include <halirq.h>
18
19 #define NDEBUG
20 #include <internal/debug.h>
21
22 /* GLOBALS ******************************************************************/
23
24 /*
25 * FIXME: Use EISA_CONTROL STRUCTURE INSTEAD OF HARD-CODED OFFSETS
26 */
27
28 typedef union
29 {
30 USHORT both;
31 struct
32 {
33 BYTE master;
34 BYTE slave;
35 };
36 }
37 PIC_MASK;
38
39 /*
40 * PURPOSE: - Mask for HalEnableSystemInterrupt and HalDisableSystemInterrupt
41 * - At startup enable timer and cascade
42 */
43 #if defined(__GNUC__)
44 static PIC_MASK pic_mask = {.both = 0xFFFA};
45 #else
46 static PIC_MASK pic_mask = { 0xFFFA };
47 #endif
48
49
50 /*
51 * PURPOSE: Mask for disabling of acknowledged interrupts
52 */
53 #if defined(__GNUC__)
54 static PIC_MASK pic_mask_intr = {.both = 0x0000};
55 #else
56 static PIC_MASK pic_mask_intr = { 0 };
57 #endif
58
59 static ULONG HalpPendingInterruptCount[NR_IRQS];
60
61 #define DIRQL_TO_IRQ(x) (PROFILE_LEVEL - x)
62 #define IRQ_TO_DIRQL(x) (PROFILE_LEVEL - x)
63
64 VOID STDCALL
65 KiInterruptDispatch2 (ULONG Irq, KIRQL old_level);
66
67 /* FUNCTIONS ****************************************************************/
68
69 KIRQL STDCALL KeGetCurrentIrql (VOID)
70 /*
71 * PURPOSE: Returns the current irq level
72 * RETURNS: The current irq level
73 */
74 {
75 return(KeGetCurrentKPCR()->Irql);
76 }
77
78 VOID HalpInitPICs(VOID)
79 {
80 memset(HalpPendingInterruptCount, 0, sizeof(HalpPendingInterruptCount));
81
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);
90 /* 8259-2 is slave */
91 WRITE_PORT_UCHAR((PUCHAR)0xa1, 0x2);
92 /* 8086 mode */
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);
98
99 /* We can now enable interrupts */
100 Ki386EnableInterrupts();
101 }
102
103 VOID HalpEndSystemInterrupt(KIRQL Irql)
104 /*
105 * FUNCTION: Enable all irqs with higher priority.
106 */
107 {
108 ULONG flags;
109 const USHORT mask[] =
110 {
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,
115 };
116
117 /* Interrupts should be disable while enabling irqs of both pics */
118 Ki386SaveFlags(flags);
119 Ki386DisableInterrupts();
120
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));
124
125 /* restore flags */
126 Ki386RestoreFlags(flags);
127 }
128
129 VOID STATIC
130 HalpExecuteIrqs(KIRQL NewIrql)
131 {
132 ULONG IrqLimit, i;
133
134 IrqLimit = min(PROFILE_LEVEL - NewIrql, NR_IRQS);
135
136 /*
137 * For each irq if there have been any deferred interrupts then now
138 * dispatch them.
139 */
140 for (i = 0; i < IrqLimit; i++)
141 {
142 if (HalpPendingInterruptCount[i] > 0)
143 {
144 KeGetCurrentKPCR()->Irql = (KIRQL)IRQ_TO_DIRQL(i);
145
146 while (HalpPendingInterruptCount[i] > 0)
147 {
148 /*
149 * For each deferred interrupt execute all the handlers at DIRQL.
150 */
151 HalpPendingInterruptCount[i]--;
152 KiInterruptDispatch2(i + IRQ_BASE, NewIrql);
153 }
154 KeGetCurrentKPCR()->Irql--;
155 HalpEndSystemInterrupt(KeGetCurrentKPCR()->Irql);
156 }
157 }
158
159 }
160
161 VOID STATIC
162 HalpLowerIrql(KIRQL NewIrql)
163 {
164 if (NewIrql >= PROFILE_LEVEL)
165 {
166 KeGetCurrentKPCR()->Irql = NewIrql;
167 return;
168 }
169 HalpExecuteIrqs(NewIrql);
170 if (NewIrql >= DISPATCH_LEVEL)
171 {
172 KeGetCurrentKPCR()->Irql = NewIrql;
173 return;
174 }
175 KeGetCurrentKPCR()->Irql = DISPATCH_LEVEL;
176 if (KeGetCurrentKPCR()->HalReserved[HAL_DPC_REQUEST])
177 {
178 KeGetCurrentKPCR()->HalReserved[HAL_DPC_REQUEST] = FALSE;
179 KiDispatchInterrupt();
180 }
181 KeGetCurrentKPCR()->Irql = APC_LEVEL;
182 if (NewIrql == APC_LEVEL)
183 {
184 return;
185 }
186 if (KeGetCurrentThread() != NULL &&
187 KeGetCurrentThread()->ApcState.KernelApcPending)
188 {
189 KiDeliverApc(KernelMode, NULL, NULL);
190 }
191 KeGetCurrentKPCR()->Irql = PASSIVE_LEVEL;
192 }
193
194 /**********************************************************************
195 * NAME EXPORTED
196 * KfLowerIrql
197 *
198 * DESCRIPTION
199 * Restores the irq level on the current processor
200 *
201 * ARGUMENTS
202 * NewIrql = Irql to lower to
203 *
204 * RETURN VALUE
205 * None
206 *
207 * NOTES
208 * Uses fastcall convention
209 */
210 VOID FASTCALL
211 KfLowerIrql (KIRQL NewIrql)
212 {
213 DPRINT("KfLowerIrql(NewIrql %d)\n", NewIrql);
214
215 if (NewIrql > KeGetCurrentKPCR()->Irql)
216 {
217 DbgPrint ("(%s:%d) NewIrql %x CurrentIrql %x\n",
218 __FILE__, __LINE__, NewIrql, KeGetCurrentKPCR()->Irql);
219 KEBUGCHECK(0);
220 for(;;);
221 }
222
223 HalpLowerIrql(NewIrql);
224 }
225
226
227 /**********************************************************************
228 * NAME EXPORTED
229 * KeLowerIrql
230 *
231 * DESCRIPTION
232 * Restores the irq level on the current processor
233 *
234 * ARGUMENTS
235 * NewIrql = Irql to lower to
236 *
237 * RETURN VALUE
238 * None
239 *
240 * NOTES
241 */
242
243 VOID STDCALL
244 KeLowerIrql (KIRQL NewIrql)
245 {
246 KfLowerIrql (NewIrql);
247 }
248
249
250 /**********************************************************************
251 * NAME EXPORTED
252 * KfRaiseIrql
253 *
254 * DESCRIPTION
255 * Raises the hardware priority (irql)
256 *
257 * ARGUMENTS
258 * NewIrql = Irql to raise to
259 *
260 * RETURN VALUE
261 * previous irq level
262 *
263 * NOTES
264 * Uses fastcall convention
265 */
266
267 KIRQL FASTCALL
268 KfRaiseIrql (KIRQL NewIrql)
269 {
270 KIRQL OldIrql;
271
272 DPRINT("KfRaiseIrql(NewIrql %d)\n", NewIrql);
273
274 if (NewIrql < KeGetCurrentKPCR()->Irql)
275 {
276 DbgPrint ("%s:%d CurrentIrql %x NewIrql %x\n",
277 __FILE__,__LINE__,KeGetCurrentKPCR()->Irql,NewIrql);
278 KEBUGCHECK (0);
279 for(;;);
280 }
281
282 OldIrql = KeGetCurrentKPCR()->Irql;
283 KeGetCurrentKPCR()->Irql = NewIrql;
284 return OldIrql;
285 }
286
287
288 /**********************************************************************
289 * NAME EXPORTED
290 * KeRaiseIrql
291 *
292 * DESCRIPTION
293 * Raises the hardware priority (irql)
294 *
295 * ARGUMENTS
296 * NewIrql = Irql to raise to
297 * OldIrql (OUT) = Caller supplied storage for the previous irql
298 *
299 * RETURN VALUE
300 * None
301 *
302 * NOTES
303 * Calls KfRaiseIrql
304 */
305 VOID STDCALL
306 KeRaiseIrql (KIRQL NewIrql,
307 PKIRQL OldIrql)
308 {
309 *OldIrql = KfRaiseIrql (NewIrql);
310 }
311
312
313 /**********************************************************************
314 * NAME EXPORTED
315 * KeRaiseIrqlToDpcLevel
316 *
317 * DESCRIPTION
318 * Raises the hardware priority (irql) to DISPATCH level
319 *
320 * ARGUMENTS
321 * None
322 *
323 * RETURN VALUE
324 * Previous irq level
325 *
326 * NOTES
327 * Calls KfRaiseIrql
328 */
329
330 KIRQL STDCALL
331 KeRaiseIrqlToDpcLevel (VOID)
332 {
333 return KfRaiseIrql (DISPATCH_LEVEL);
334 }
335
336
337 /**********************************************************************
338 * NAME EXPORTED
339 * KeRaiseIrqlToSynchLevel
340 *
341 * DESCRIPTION
342 * Raises the hardware priority (irql) to CLOCK2 level
343 *
344 * ARGUMENTS
345 * None
346 *
347 * RETURN VALUE
348 * Previous irq level
349 *
350 * NOTES
351 * Calls KfRaiseIrql
352 */
353
354 KIRQL STDCALL
355 KeRaiseIrqlToSynchLevel (VOID)
356 {
357 return KfRaiseIrql (CLOCK2_LEVEL);
358 }
359
360
361 BOOLEAN STDCALL
362 HalBeginSystemInterrupt (ULONG Vector,
363 KIRQL Irql,
364 PKIRQL OldIrql)
365 {
366 ULONG irq;
367 if (Vector < IRQ_BASE || Vector >= IRQ_BASE + NR_IRQS)
368 {
369 return(FALSE);
370 }
371 irq = Vector - IRQ_BASE;
372 pic_mask_intr.both |= ((1 << irq) & 0xfffe); // do not disable the timer interrupt
373
374 if (irq < 8)
375 {
376 WRITE_PORT_UCHAR((PUCHAR)0x21, (UCHAR)(pic_mask.master|pic_mask_intr.master));
377 WRITE_PORT_UCHAR((PUCHAR)0x20, 0x20);
378 }
379 else
380 {
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);
385 }
386
387 if (KeGetCurrentKPCR()->Irql >= Irql)
388 {
389 HalpPendingInterruptCount[irq]++;
390 return(FALSE);
391 }
392 *OldIrql = KeGetCurrentKPCR()->Irql;
393 KeGetCurrentKPCR()->Irql = Irql;
394
395 return(TRUE);
396 }
397
398
399 VOID STDCALL HalEndSystemInterrupt (KIRQL Irql, ULONG Unknown2)
400 /*
401 * FUNCTION: Finish a system interrupt and restore the specified irq level.
402 */
403 {
404 HalpLowerIrql(Irql);
405 HalpEndSystemInterrupt(Irql);
406 }
407
408 BOOLEAN
409 STDCALL
410 HalDisableSystemInterrupt(
411 ULONG Vector,
412 KIRQL Irql)
413 {
414 ULONG irq;
415
416 if (Vector < IRQ_BASE || Vector >= IRQ_BASE + NR_IRQS)
417 return FALSE;
418
419 irq = Vector - IRQ_BASE;
420 pic_mask.both |= (1 << irq);
421 if (irq < 8)
422 {
423 WRITE_PORT_UCHAR((PUCHAR)0x21, (UCHAR)(pic_mask.master|pic_mask_intr.slave));
424 }
425 else
426 {
427 WRITE_PORT_UCHAR((PUCHAR)0xa1, (UCHAR)(pic_mask.slave|pic_mask_intr.slave));
428 }
429
430 return TRUE;
431 }
432
433
434 BOOLEAN
435 STDCALL
436 HalEnableSystemInterrupt(
437 ULONG Vector,
438 KIRQL Irql,
439 KINTERRUPT_MODE InterruptMode)
440 {
441 ULONG irq;
442
443 if (Vector < IRQ_BASE || Vector >= IRQ_BASE + NR_IRQS)
444 return FALSE;
445
446 irq = Vector - IRQ_BASE;
447 pic_mask.both &= ~(1 << irq);
448 if (irq < 8)
449 {
450 WRITE_PORT_UCHAR((PUCHAR)0x21, (UCHAR)(pic_mask.master|pic_mask_intr.master));
451 }
452 else
453 {
454 WRITE_PORT_UCHAR((PUCHAR)0xa1, (UCHAR)(pic_mask.slave|pic_mask_intr.slave));
455 }
456
457 return TRUE;
458 }
459
460
461 VOID FASTCALL
462 HalRequestSoftwareInterrupt(
463 IN KIRQL Request)
464 {
465 switch (Request)
466 {
467 case APC_LEVEL:
468 KeGetCurrentKPCR()->HalReserved[HAL_APC_REQUEST] = TRUE;
469 break;
470
471 case DISPATCH_LEVEL:
472 KeGetCurrentKPCR()->HalReserved[HAL_DPC_REQUEST] = TRUE;
473 break;
474
475 default:
476 KEBUGCHECK(0);
477 }
478 }
479
480 /* EOF */