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