- Remove KeAttachProcess and KeDetachProcess prototypes from winddk.h.
[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 <ddk/ntddk.h>
13 #include <internal/ob.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 #undef KeGetCurrentIrql
70 KIRQL STDCALL KeGetCurrentIrql (VOID)
71 /*
72 * PURPOSE: Returns the current irq level
73 * RETURNS: The current irq level
74 */
75 {
76 return(KeGetCurrentKPCR()->Irql);
77 }
78
79 VOID HalpInitPICs(VOID)
80 {
81 memset(HalpPendingInterruptCount, 0, sizeof(HalpPendingInterruptCount));
82
83 /* Initialization sequence */
84 WRITE_PORT_UCHAR((PUCHAR)0x20, 0x11);
85 WRITE_PORT_UCHAR((PUCHAR)0xa0, 0x11);
86 /* Start of hardware irqs (0x24) */
87 WRITE_PORT_UCHAR((PUCHAR)0x21, IRQ_BASE);
88 WRITE_PORT_UCHAR((PUCHAR)0xa1, IRQ_BASE + 8);
89 /* 8259-1 is master */
90 WRITE_PORT_UCHAR((PUCHAR)0x21, 0x4);
91 /* 8259-2 is slave */
92 WRITE_PORT_UCHAR((PUCHAR)0xa1, 0x2);
93 /* 8086 mode */
94 WRITE_PORT_UCHAR((PUCHAR)0x21, 0x1);
95 WRITE_PORT_UCHAR((PUCHAR)0xa1, 0x1);
96 /* Enable interrupts */
97 WRITE_PORT_UCHAR((PUCHAR)0x21, pic_mask.master);
98 WRITE_PORT_UCHAR((PUCHAR)0xa1, pic_mask.slave);
99
100 /* We can now enable interrupts */
101 Ki386EnableInterrupts();
102 }
103
104 VOID HalpEndSystemInterrupt(KIRQL Irql)
105 /*
106 * FUNCTION: Enable all irqs with higher priority.
107 */
108 {
109 ULONG flags;
110 const USHORT mask[] =
111 {
112 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
113 0x0000, 0x0000, 0x0000, 0x0000, 0x8000, 0xc000, 0xe000, 0xf000,
114 0xf800, 0xfc00, 0xfe00, 0xff00, 0xff80, 0xffc0, 0xffe0, 0xfff0,
115 0xfff8, 0xfffc, 0xfffe, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
116 };
117
118 /* Interrupts should be disable while enabling irqs of both pics */
119 Ki386SaveFlags(flags);
120 Ki386DisableInterrupts();
121
122 pic_mask_intr.both &= mask[Irql];
123 WRITE_PORT_UCHAR((PUCHAR)0x21, (UCHAR)(pic_mask.master|pic_mask_intr.master));
124 WRITE_PORT_UCHAR((PUCHAR)0xa1, (UCHAR)(pic_mask.slave|pic_mask_intr.slave));
125
126 /* restore flags */
127 Ki386RestoreFlags(flags);
128 }
129
130 VOID STATIC
131 HalpExecuteIrqs(KIRQL NewIrql)
132 {
133 ULONG IrqLimit, i;
134
135 IrqLimit = min(PROFILE_LEVEL - NewIrql, NR_IRQS);
136
137 /*
138 * For each irq if there have been any deferred interrupts then now
139 * dispatch them.
140 */
141 for (i = 0; i < IrqLimit; i++)
142 {
143 if (HalpPendingInterruptCount[i] > 0)
144 {
145 KeGetCurrentKPCR()->Irql = (KIRQL)IRQ_TO_DIRQL(i);
146
147 while (HalpPendingInterruptCount[i] > 0)
148 {
149 /*
150 * For each deferred interrupt execute all the handlers at DIRQL.
151 */
152 HalpPendingInterruptCount[i]--;
153 KiInterruptDispatch2(i + IRQ_BASE, NewIrql);
154 }
155 KeGetCurrentKPCR()->Irql--;
156 HalpEndSystemInterrupt(KeGetCurrentKPCR()->Irql);
157 }
158 }
159
160 }
161
162 VOID STATIC
163 HalpLowerIrql(KIRQL NewIrql)
164 {
165 if (NewIrql >= PROFILE_LEVEL)
166 {
167 KeGetCurrentKPCR()->Irql = NewIrql;
168 return;
169 }
170 HalpExecuteIrqs(NewIrql);
171 if (NewIrql >= DISPATCH_LEVEL)
172 {
173 KeGetCurrentKPCR()->Irql = NewIrql;
174 return;
175 }
176 KeGetCurrentKPCR()->Irql = DISPATCH_LEVEL;
177 if (KeGetCurrentKPCR()->HalReserved[HAL_DPC_REQUEST])
178 {
179 KeGetCurrentKPCR()->HalReserved[HAL_DPC_REQUEST] = FALSE;
180 KiDispatchInterrupt();
181 }
182 KeGetCurrentKPCR()->Irql = APC_LEVEL;
183 if (NewIrql == APC_LEVEL)
184 {
185 return;
186 }
187 if (KeGetCurrentThread() != NULL &&
188 KeGetCurrentThread()->ApcState.KernelApcPending)
189 {
190 KiDeliverApc(KernelMode, NULL, NULL);
191 }
192 KeGetCurrentKPCR()->Irql = PASSIVE_LEVEL;
193 }
194
195 /**********************************************************************
196 * NAME EXPORTED
197 * KfLowerIrql
198 *
199 * DESCRIPTION
200 * Restores the irq level on the current processor
201 *
202 * ARGUMENTS
203 * NewIrql = Irql to lower to
204 *
205 * RETURN VALUE
206 * None
207 *
208 * NOTES
209 * Uses fastcall convention
210 */
211 VOID FASTCALL
212 KfLowerIrql (KIRQL NewIrql)
213 {
214 DPRINT("KfLowerIrql(NewIrql %d)\n", NewIrql);
215
216 if (NewIrql > KeGetCurrentKPCR()->Irql)
217 {
218 DbgPrint ("(%s:%d) NewIrql %x CurrentIrql %x\n",
219 __FILE__, __LINE__, NewIrql, KeGetCurrentKPCR()->Irql);
220 KEBUGCHECK(0);
221 for(;;);
222 }
223
224 HalpLowerIrql(NewIrql);
225 }
226
227
228 /**********************************************************************
229 * NAME EXPORTED
230 * KeLowerIrql
231 *
232 * DESCRIPTION
233 * Restores the irq level on the current processor
234 *
235 * ARGUMENTS
236 * NewIrql = Irql to lower to
237 *
238 * RETURN VALUE
239 * None
240 *
241 * NOTES
242 */
243
244 VOID STDCALL
245 KeLowerIrql (KIRQL NewIrql)
246 {
247 KfLowerIrql (NewIrql);
248 }
249
250
251 /**********************************************************************
252 * NAME EXPORTED
253 * KfRaiseIrql
254 *
255 * DESCRIPTION
256 * Raises the hardware priority (irql)
257 *
258 * ARGUMENTS
259 * NewIrql = Irql to raise to
260 *
261 * RETURN VALUE
262 * previous irq level
263 *
264 * NOTES
265 * Uses fastcall convention
266 */
267
268 KIRQL FASTCALL
269 KfRaiseIrql (KIRQL NewIrql)
270 {
271 KIRQL OldIrql;
272
273 DPRINT("KfRaiseIrql(NewIrql %d)\n", NewIrql);
274
275 if (NewIrql < KeGetCurrentKPCR()->Irql)
276 {
277 DbgPrint ("%s:%d CurrentIrql %x NewIrql %x\n",
278 __FILE__,__LINE__,KeGetCurrentKPCR()->Irql,NewIrql);
279 KEBUGCHECK (0);
280 for(;;);
281 }
282
283 OldIrql = KeGetCurrentKPCR()->Irql;
284 KeGetCurrentKPCR()->Irql = NewIrql;
285 return OldIrql;
286 }
287
288
289 /**********************************************************************
290 * NAME EXPORTED
291 * KeRaiseIrql
292 *
293 * DESCRIPTION
294 * Raises the hardware priority (irql)
295 *
296 * ARGUMENTS
297 * NewIrql = Irql to raise to
298 * OldIrql (OUT) = Caller supplied storage for the previous irql
299 *
300 * RETURN VALUE
301 * None
302 *
303 * NOTES
304 * Calls KfRaiseIrql
305 */
306 VOID STDCALL
307 KeRaiseIrql (KIRQL NewIrql,
308 PKIRQL OldIrql)
309 {
310 *OldIrql = KfRaiseIrql (NewIrql);
311 }
312
313
314 /**********************************************************************
315 * NAME EXPORTED
316 * KeRaiseIrqlToDpcLevel
317 *
318 * DESCRIPTION
319 * Raises the hardware priority (irql) to DISPATCH level
320 *
321 * ARGUMENTS
322 * None
323 *
324 * RETURN VALUE
325 * Previous irq level
326 *
327 * NOTES
328 * Calls KfRaiseIrql
329 */
330
331 KIRQL STDCALL
332 KeRaiseIrqlToDpcLevel (VOID)
333 {
334 return KfRaiseIrql (DISPATCH_LEVEL);
335 }
336
337
338 /**********************************************************************
339 * NAME EXPORTED
340 * KeRaiseIrqlToSynchLevel
341 *
342 * DESCRIPTION
343 * Raises the hardware priority (irql) to CLOCK2 level
344 *
345 * ARGUMENTS
346 * None
347 *
348 * RETURN VALUE
349 * Previous irq level
350 *
351 * NOTES
352 * Calls KfRaiseIrql
353 */
354
355 KIRQL STDCALL
356 KeRaiseIrqlToSynchLevel (VOID)
357 {
358 return KfRaiseIrql (CLOCK2_LEVEL);
359 }
360
361
362 BOOLEAN STDCALL
363 HalBeginSystemInterrupt (ULONG Vector,
364 KIRQL Irql,
365 PKIRQL OldIrql)
366 {
367 ULONG irq;
368 if (Vector < IRQ_BASE || Vector >= IRQ_BASE + NR_IRQS)
369 {
370 return(FALSE);
371 }
372 irq = Vector - IRQ_BASE;
373 pic_mask_intr.both |= ((1 << irq) & 0xfffe); // do not disable the timer interrupt
374
375 if (irq < 8)
376 {
377 WRITE_PORT_UCHAR((PUCHAR)0x21, (UCHAR)(pic_mask.master|pic_mask_intr.master));
378 WRITE_PORT_UCHAR((PUCHAR)0x20, 0x20);
379 }
380 else
381 {
382 WRITE_PORT_UCHAR((PUCHAR)0xa1, (UCHAR)(pic_mask.slave|pic_mask_intr.slave));
383 /* Send EOI to the PICs */
384 WRITE_PORT_UCHAR((PUCHAR)0x20,0x20);
385 WRITE_PORT_UCHAR((PUCHAR)0xa0,0x20);
386 }
387
388 if (KeGetCurrentKPCR()->Irql >= Irql)
389 {
390 HalpPendingInterruptCount[irq]++;
391 return(FALSE);
392 }
393 *OldIrql = KeGetCurrentKPCR()->Irql;
394 KeGetCurrentKPCR()->Irql = Irql;
395
396 return(TRUE);
397 }
398
399
400 VOID STDCALL HalEndSystemInterrupt (KIRQL Irql, ULONG Unknown2)
401 /*
402 * FUNCTION: Finish a system interrupt and restore the specified irq level.
403 */
404 {
405 HalpLowerIrql(Irql);
406 HalpEndSystemInterrupt(Irql);
407 }
408
409 BOOLEAN
410 STDCALL
411 HalDisableSystemInterrupt(
412 ULONG Vector,
413 KIRQL Irql)
414 {
415 ULONG irq;
416
417 if (Vector < IRQ_BASE || Vector >= IRQ_BASE + NR_IRQS)
418 return FALSE;
419
420 irq = Vector - IRQ_BASE;
421 pic_mask.both |= (1 << irq);
422 if (irq < 8)
423 {
424 WRITE_PORT_UCHAR((PUCHAR)0x21, (UCHAR)(pic_mask.master|pic_mask_intr.slave));
425 }
426 else
427 {
428 WRITE_PORT_UCHAR((PUCHAR)0xa1, (UCHAR)(pic_mask.slave|pic_mask_intr.slave));
429 }
430
431 return TRUE;
432 }
433
434
435 BOOLEAN
436 STDCALL
437 HalEnableSystemInterrupt(
438 ULONG Vector,
439 KIRQL Irql,
440 KINTERRUPT_MODE InterruptMode)
441 {
442 ULONG irq;
443
444 if (Vector < IRQ_BASE || Vector >= IRQ_BASE + NR_IRQS)
445 return FALSE;
446
447 irq = Vector - IRQ_BASE;
448 pic_mask.both &= ~(1 << irq);
449 if (irq < 8)
450 {
451 WRITE_PORT_UCHAR((PUCHAR)0x21, (UCHAR)(pic_mask.master|pic_mask_intr.master));
452 }
453 else
454 {
455 WRITE_PORT_UCHAR((PUCHAR)0xa1, (UCHAR)(pic_mask.slave|pic_mask_intr.slave));
456 }
457
458 return TRUE;
459 }
460
461
462 VOID FASTCALL
463 HalRequestSoftwareInterrupt(
464 IN KIRQL Request)
465 {
466 switch (Request)
467 {
468 case APC_LEVEL:
469 KeGetCurrentKPCR()->HalReserved[HAL_APC_REQUEST] = TRUE;
470 break;
471
472 case DISPATCH_LEVEL:
473 KeGetCurrentKPCR()->HalReserved[HAL_DPC_REQUEST] = TRUE;
474 break;
475
476 default:
477 KEBUGCHECK(0);
478 }
479 }
480
481 /* EOF */