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