:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[reactos.git] / hal / halx86 / irql.c
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS kernel
4  * FILE:            ntoskrnl/hal/x86/irql.c
5  * PURPOSE:         Implements IRQLs
6  * PROGRAMMER:      David Welch (welch@cwcom.net)
7  */
8
9 /* INCLUDES *****************************************************************/
10
11 #include <ddk/ntddk.h>
12 #include <internal/ke.h>
13 #include <internal/ps.h>
14 #include <ntos/minmax.h>
15
16 #define NDEBUG
17 #include <internal/debug.h>
18
19 /* GLOBALS ******************************************************************/
20
21 #define NR_IRQS         (16)
22 #define IRQ_BASE        (0x40)
23
24 /*
25  * PURPOSE: Current irq level
26  */
27 static KIRQL CurrentIrql = HIGH_LEVEL;
28
29 extern IMPORTED ULONG DpcQueueSize;
30
31 static ULONG HalpPendingInterruptCount[NR_IRQS];
32
33 #define DIRQL_TO_IRQ(x)  (PROFILE_LEVEL - x)
34 #define IRQ_TO_DIRQL(x)  (PROFILE_LEVEL - x)
35
36 VOID STDCALL
37 KiInterruptDispatch2 (ULONG Irq, KIRQL old_level);
38
39 /* FUNCTIONS ****************************************************************/
40
41 KIRQL STDCALL KeGetCurrentIrql (VOID)
42 /*
43  * PURPOSE: Returns the current irq level
44  * RETURNS: The current irq level
45  */
46 {
47   return(CurrentIrql);
48 }
49
50 VOID HalpInitPICs(VOID)
51 {
52   memset(HalpPendingInterruptCount, 0, sizeof(HalpPendingInterruptCount));
53
54   /* Initialization sequence */
55   WRITE_PORT_UCHAR((PUCHAR)0x20, 0x11);
56   WRITE_PORT_UCHAR((PUCHAR)0xa0, 0x11);
57   /* Start of hardware irqs (0x24) */
58   WRITE_PORT_UCHAR((PUCHAR)0x21, 0x40);
59   WRITE_PORT_UCHAR((PUCHAR)0xa1, 0x48);
60   /* 8259-1 is master */
61   WRITE_PORT_UCHAR((PUCHAR)0x21, 0x4);
62   /* 8259-2 is slave */
63   WRITE_PORT_UCHAR((PUCHAR)0xa1, 0x2);
64   /* 8086 mode */
65   WRITE_PORT_UCHAR((PUCHAR)0x21, 0x1);
66   WRITE_PORT_UCHAR((PUCHAR)0xa1, 0x1);   
67   /* Enable all interrupts from PICs */
68   WRITE_PORT_UCHAR((PUCHAR)0x21, 0x0);
69   WRITE_PORT_UCHAR((PUCHAR)0xa1, 0x0);
70   
71   /* We can now enable interrupts */
72   __asm__ __volatile__ ("sti\n\t");
73 }
74
75 VOID STATIC
76 HalpExecuteIrqs(KIRQL NewIrql)
77 {
78   ULONG IrqLimit, i;
79   
80   IrqLimit = min(PROFILE_LEVEL - NewIrql, NR_IRQS);
81
82   /*
83    * For each irq if there have been any deferred interrupts then now
84    * dispatch them.
85    */
86   for (i = 0; i < IrqLimit; i++)
87     {
88       while (HalpPendingInterruptCount[i] > 0)
89         {
90           /*
91            * For each deferred interrupt execute all the handlers at DIRQL.
92            */
93           CurrentIrql = IRQ_TO_DIRQL(i);
94           KiInterruptDispatch2(i, NewIrql);
95           HalpPendingInterruptCount[i]--;
96         }
97     }
98 }
99
100 VOID STATIC
101 HalpLowerIrql(KIRQL NewIrql)
102 {
103   if (NewIrql > PROFILE_LEVEL)
104     {
105       CurrentIrql = NewIrql;
106       return;
107     }
108   HalpExecuteIrqs(NewIrql);
109   if (NewIrql >= DISPATCH_LEVEL)
110     {
111       CurrentIrql = NewIrql;
112       return;
113     }
114   CurrentIrql = DISPATCH_LEVEL;
115   if (DpcQueueSize > 0)
116     {
117       KiDispatchInterrupt();
118     }
119   if (NewIrql == APC_LEVEL)
120     {
121       CurrentIrql = NewIrql;
122       return;
123     }
124   CurrentIrql = APC_LEVEL;
125   if (KeGetCurrentThread() != NULL && 
126       KeGetCurrentThread()->ApcState.KernelApcPending)
127     {
128       KiDeliverApc(0, 0, 0);
129     }
130   CurrentIrql = PASSIVE_LEVEL;
131 }
132
133 /**********************************************************************
134  * NAME                                                 EXPORTED
135  *      KfLowerIrql
136  *
137  * DESCRIPTION
138  *      Restores the irq level on the current processor
139  *
140  * ARGUMENTS
141  *      NewIrql = Irql to lower to
142  *
143  * RETURN VALUE
144  *      None
145  *
146  * NOTES
147  *      Uses fastcall convention
148  */
149 VOID FASTCALL
150 KfLowerIrql (KIRQL      NewIrql)
151 {
152   KIRQL OldIrql;
153   
154   DPRINT("KfLowerIrql(NewIrql %d)\n", NewIrql);
155   
156   if (NewIrql > CurrentIrql)
157     {
158       DbgPrint ("(%s:%d) NewIrql %x CurrentIrql %x\n",
159                 __FILE__, __LINE__, NewIrql, CurrentIrql);
160       KeBugCheck(0);
161       for(;;);
162     }
163   
164   HalpLowerIrql(NewIrql);
165 }
166
167
168 /**********************************************************************
169  * NAME                                                 EXPORTED
170  *      KeLowerIrql
171  *
172  * DESCRIPTION
173  *      Restores the irq level on the current processor
174  *
175  * ARGUMENTS
176  *      NewIrql = Irql to lower to
177  *
178  * RETURN VALUE
179  *      None
180  *
181  * NOTES
182  */
183
184 VOID STDCALL
185 KeLowerIrql (KIRQL NewIrql)
186 {
187   KfLowerIrql (NewIrql);
188 }
189
190
191 /**********************************************************************
192  * NAME                                                 EXPORTED
193  *      KfRaiseIrql
194  *
195  * DESCRIPTION
196  *      Raises the hardware priority (irql)
197  *
198  * ARGUMENTS
199  *      NewIrql = Irql to raise to
200  *
201  * RETURN VALUE
202  *      previous irq level
203  *
204  * NOTES
205  *      Uses fastcall convention
206  */
207
208 KIRQL FASTCALL
209 KfRaiseIrql (KIRQL      NewIrql)
210 {
211   KIRQL OldIrql;
212   
213   DPRINT("KfRaiseIrql(NewIrql %d)\n", NewIrql);
214   
215   if (NewIrql < CurrentIrql)
216     {
217       DbgPrint ("%s:%d CurrentIrql %x NewIrql %x\n",
218                 __FILE__,__LINE__,CurrentIrql,NewIrql);
219       KeBugCheck (0);
220       for(;;);
221     }
222   
223   OldIrql = CurrentIrql;
224   CurrentIrql = NewIrql;
225   return OldIrql;
226 }
227
228
229 /**********************************************************************
230  * NAME                                                 EXPORTED
231  *      KeRaiseIrql
232  *
233  * DESCRIPTION
234  *      Raises the hardware priority (irql)
235  *
236  * ARGUMENTS
237  *      NewIrql = Irql to raise to
238  *      OldIrql (OUT) = Caller supplied storage for the previous irql
239  *
240  * RETURN VALUE
241  *      None
242  *
243  * NOTES
244  *      Calls KfRaiseIrql
245  */
246 VOID STDCALL
247 KeRaiseIrql (KIRQL      NewIrql,
248              PKIRQL     OldIrql)
249 {
250   *OldIrql = KfRaiseIrql (NewIrql);
251 }
252
253
254 /**********************************************************************
255  * NAME                                                 EXPORTED
256  *      KeRaiseIrqlToDpcLevel
257  *
258  * DESCRIPTION
259  *      Raises the hardware priority (irql) to DISPATCH level
260  *
261  * ARGUMENTS
262  *      None
263  *
264  * RETURN VALUE
265  *      Previous irq level
266  *
267  * NOTES
268  *      Calls KfRaiseIrql
269  */
270
271 KIRQL STDCALL
272 KeRaiseIrqlToDpcLevel (VOID)
273 {
274   return KfRaiseIrql (DISPATCH_LEVEL);
275 }
276
277
278 /**********************************************************************
279  * NAME                                                 EXPORTED
280  *      KeRaiseIrqlToSynchLevel
281  *
282  * DESCRIPTION
283  *      Raises the hardware priority (irql) to CLOCK2 level
284  *
285  * ARGUMENTS
286  *      None
287  *
288  * RETURN VALUE
289  *      Previous irq level
290  *
291  * NOTES
292  *      Calls KfRaiseIrql
293  */
294
295 KIRQL STDCALL
296 KeRaiseIrqlToSynchLevel (VOID)
297 {
298   return KfRaiseIrql (CLOCK2_LEVEL);
299 }
300
301
302 BOOLEAN STDCALL 
303 HalBeginSystemInterrupt (ULONG Vector,
304                          KIRQL Irql,
305                          PKIRQL OldIrql)
306 {
307   if (Vector < IRQ_BASE || Vector > IRQ_BASE + NR_IRQS)
308     {
309       return(FALSE);
310     }
311   
312   /* Send EOI to the PICs */
313   WRITE_PORT_UCHAR((PUCHAR)0x20,0x20);
314   if ((Vector-IRQ_BASE)>=8)
315     {
316       WRITE_PORT_UCHAR((PUCHAR)0xa0,0x20);
317     }
318   
319   if (CurrentIrql >= Irql)
320     {
321       HalpPendingInterruptCount[Vector - IRQ_BASE]++;
322       return(FALSE);
323     }
324   *OldIrql = CurrentIrql;
325   CurrentIrql = Irql;
326
327   return(TRUE);
328 }
329
330
331 VOID STDCALL HalEndSystemInterrupt (KIRQL Irql, ULONG Unknown2)
332 /*
333  * FUNCTION: Finish a system interrupt and restore the specified irq level.
334  */
335 {
336   HalpLowerIrql(Irql);
337 }
338
339 BOOLEAN STDCALL HalDisableSystemInterrupt (ULONG Vector,
340                                            ULONG Unknown2)
341 {
342   ULONG irq;
343   
344   if (Vector < IRQ_BASE || Vector > IRQ_BASE + NR_IRQS)
345     return FALSE;
346
347   irq = Vector - IRQ_BASE;
348   if (irq < 8)
349      {
350        WRITE_PORT_UCHAR((PUCHAR)0x21, 
351                         READ_PORT_UCHAR((PUCHAR)0x21)|(1<<irq));
352      }
353   else
354     {
355       WRITE_PORT_UCHAR((PUCHAR)0xa1, 
356                        READ_PORT_UCHAR((PUCHAR)0xa1)|(1<<(irq-8)));
357     }
358   
359   return TRUE;
360 }
361
362
363 BOOLEAN STDCALL HalEnableSystemInterrupt (ULONG Vector,
364                                           ULONG Unknown2,
365                                           ULONG Unknown3)
366 {
367   ULONG irq;
368
369   if (Vector < IRQ_BASE || Vector > IRQ_BASE + NR_IRQS)
370     return FALSE;
371
372   irq = Vector - IRQ_BASE;
373   if (irq < 8)
374     {
375       WRITE_PORT_UCHAR((PUCHAR)0x21, 
376                        READ_PORT_UCHAR((PUCHAR)0x21)&(~(1<<irq)));
377     }
378   else
379      {
380        WRITE_PORT_UCHAR((PUCHAR)0xa1, 
381                         READ_PORT_UCHAR((PUCHAR)0xa1)&(~(1<<(irq-8))));
382      }
383
384   return TRUE;
385 }
386
387 /* EOF */