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