:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[reactos.git] / hal / halx86 / mpsirql.c
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS kernel
4  * FILE:            ntoskrnl/hal/x86/mpsirql.c
5  * PURPOSE:         Implements IRQLs for multiprocessor systems
6  * PROGRAMMERS:     David Welch (welch@cwcom.net)
7  *                  Casper S. Hornstrup (chorns@users.sourceforge.net)
8  * UPDATE HISTORY:
9  *     12/04/2001  CSH  Created
10  */
11
12 /* INCLUDES *****************************************************************/
13
14 #include <ddk/ntddk.h>
15 #include <internal/ke.h>
16 #include <internal/ps.h>
17 #include <mps.h>
18
19 #define NDEBUG
20 #include <internal/debug.h>
21
22 /* GLOBALS ******************************************************************/;
23
24 extern IMPORTED ULONG DpcQueueSize;
25
26 static VOID KeSetCurrentIrql(KIRQL newlvl);
27
28 /* FUNCTIONS ****************************************************************/
29
30 #define IRQL2TPR(irql) (APIC_TPR_MIN + ((irql - DISPATCH_LEVEL - 1) * 8))
31
32 static VOID HiSetCurrentPriority(
33   ULONG Priority)
34 {
35   //DbgPrint(" P(0x%X)\n", Priority);
36   APICWrite(APIC_TPR, Priority & APIC_TPR_PRI);
37 }
38
39
40 static VOID HiSwitchIrql(KIRQL OldIrql, ULONG Flags)
41 /*
42  * FUNCTION: Switches to the current irql
43  * NOTE: Must be called with interrupt disabled
44  */
45 {
46    PKTHREAD CurrentThread;
47    KIRQL CurrentIrql;
48
49    //DbgPrint("HiSwitchIrql(OldIrql %d)\n", OldIrql);
50
51    CurrentIrql = KeGetCurrentKPCR()->Irql;
52
53    if (CurrentIrql >= IPI_LEVEL)
54      {
55   /* Block all interrupts */
56   HiSetCurrentPriority(APIC_TPR_MAX);
57         return;
58      }
59
60   if (CurrentIrql == CLOCK2_LEVEL)
61      {
62         HiSetCurrentPriority(APIC_TPR_MAX - 16);
63         popfl(Flags);
64         return;
65      }
66
67    if (CurrentIrql > DISPATCH_LEVEL)
68      {
69         HiSetCurrentPriority(IRQL2TPR(CurrentIrql));
70         popfl(Flags);
71         return;
72      }
73
74    /* Pass all interrupts */
75    HiSetCurrentPriority(0);
76
77    if (CurrentIrql == DISPATCH_LEVEL)
78      {
79         popfl(Flags);
80         return;
81      }
82
83    if (CurrentIrql == APC_LEVEL)
84      {
85         if (DpcQueueSize > 0 )
86           {
87              KeSetCurrentIrql(DISPATCH_LEVEL);
88              __asm__("sti\n\t");
89              KiDispatchInterrupt();
90              __asm__("cli\n\t");
91              KeSetCurrentIrql(PASSIVE_LEVEL);
92           }
93         popfl(Flags);
94         return;
95      }
96
97   CurrentThread = KeGetCurrentThread();
98
99   if (CurrentIrql == PASSIVE_LEVEL && 
100        CurrentThread != NULL && 
101        CurrentThread->ApcState.KernelApcPending)
102      {
103         KeSetCurrentIrql(APC_LEVEL);
104         __asm__("sti\n\t");
105         KiDeliverApc(0, 0, 0);
106         __asm__("cli\n\t");
107         KeSetCurrentIrql(PASSIVE_LEVEL);
108         popfl(Flags);
109      }
110    else
111      {
112         popfl(Flags);
113      }
114 }
115
116
117 KIRQL STDCALL KeGetCurrentIrql (VOID)
118 /*
119  * PURPOSE: Returns the current irq level
120  * RETURNS: The current irq level
121  */
122 {
123    return(KeGetCurrentKPCR()->Irql);
124 }
125
126
127 static VOID KeSetCurrentIrql(KIRQL newlvl)
128 /*
129  * PURPOSE: Sets the current irq level without taking any action
130  */
131 {
132 //   DPRINT("KeSetCurrentIrql(newlvl %x)\n",newlvl);
133
134    KeGetCurrentKPCR()->Irql = newlvl;
135 }
136
137
138 /**********************************************************************
139  * NAME                                                 EXPORTED
140  *      KfLowerIrql
141  *
142  * DESCRIPTION
143  *      Restores the irq level on the current processor
144  *
145  * ARGUMENTS
146  *      NewIrql = Irql to lower to
147  *
148  * RETURN VALUE
149  *      None
150  *
151  * NOTES
152  *      Uses fastcall convention
153  */
154
155 VOID FASTCALL
156 KfLowerIrql (
157         KIRQL   NewIrql
158         )
159 {
160   KIRQL CurrentIrql;
161   KIRQL OldIrql;
162   ULONG Flags;
163
164   //DbgPrint("KfLowerIrql(NewIrql %d)\n", NewIrql);
165
166   pushfl(Flags);
167   __asm__ ("\n\tcli\n\t");
168
169   CurrentIrql = KeGetCurrentKPCR()->Irql;
170   
171   if (NewIrql > CurrentIrql)
172     {
173       DbgPrint ("(%s:%d) NewIrql %x CurrentIrql %x\n",
174                 __FILE__, __LINE__, NewIrql, CurrentIrql);
175       KeBugCheck(0);
176       for(;;);
177     }
178   
179   OldIrql = CurrentIrql;
180   KeGetCurrentKPCR()->Irql = NewIrql;
181   HiSwitchIrql(OldIrql, Flags);
182 }
183
184
185 /**********************************************************************
186  * NAME                                                 EXPORTED
187  *      KeLowerIrql
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  */
200
201 VOID
202 STDCALL
203 KeLowerIrql (
204         KIRQL   NewIrql
205         )
206 {
207         KfLowerIrql (NewIrql);
208 }
209
210
211 /**********************************************************************
212  * NAME                                                 EXPORTED
213  *      KfRaiseIrql
214  *
215  * DESCRIPTION
216  *      Raises the hardware priority (irql)
217  *
218  * ARGUMENTS
219  *      NewIrql = Irql to raise to
220  *
221  * RETURN VALUE
222  *      previous irq level
223  *
224  * NOTES
225  *      Uses fastcall convention
226  */
227
228 KIRQL
229 FASTCALL
230 KfRaiseIrql (
231         KIRQL   NewIrql
232         )
233 {
234   KIRQL CurrentIrql;
235   KIRQL OldIrql;
236   ULONG Flags;
237
238   //DbgPrint("KfRaiseIrql(NewIrql %d)\n", NewIrql);
239
240   pushfl(Flags);
241    __asm__ ("\n\tcli\n\t");
242
243   CurrentIrql = KeGetCurrentKPCR()->Irql;
244
245         if (NewIrql < CurrentIrql)
246         {
247                 DbgPrint ("%s:%d CurrentIrql %x NewIrql %x\n",
248                           __FILE__,__LINE__,CurrentIrql,NewIrql);
249                 KeBugCheck (0);
250                 for(;;);
251         }
252
253         OldIrql = CurrentIrql;
254         KeGetCurrentKPCR()->Irql = NewIrql;
255
256   //DPRINT("NewIrql %x OldIrql %x\n", NewIrql, OldIrql);
257         HiSwitchIrql(OldIrql, Flags);
258         return OldIrql;
259 }
260
261
262 /**********************************************************************
263  * NAME                                                 EXPORTED
264  *      KeRaiseIrql
265  *
266  * DESCRIPTION
267  *      Raises the hardware priority (irql)
268  *
269  * ARGUMENTS
270  *      NewIrql = Irql to raise to
271  *      OldIrql (OUT) = Caller supplied storage for the previous irql
272  *
273  * RETURN VALUE
274  *      None
275  *
276  * NOTES
277  *      Calls KfRaiseIrql
278  */
279
280 VOID
281 STDCALL
282 KeRaiseIrql (
283         KIRQL   NewIrql,
284         PKIRQL  OldIrql
285         )
286 {
287         *OldIrql = KfRaiseIrql (NewIrql);
288 }
289
290
291 /**********************************************************************
292  * NAME                                                 EXPORTED
293  *      KeRaiseIrqlToDpcLevel
294  *
295  * DESCRIPTION
296  *      Raises the hardware priority (irql) to DISPATCH level
297  *
298  * ARGUMENTS
299  *      None
300  *
301  * RETURN VALUE
302  *      Previous irq level
303  *
304  * NOTES
305  *      Calls KfRaiseIrql
306  */
307
308 KIRQL
309 STDCALL
310 KeRaiseIrqlToDpcLevel (VOID)
311 {
312         return KfRaiseIrql (DISPATCH_LEVEL);
313 }
314
315
316 /**********************************************************************
317  * NAME                                                 EXPORTED
318  *      KeRaiseIrqlToSynchLevel
319  *
320  * DESCRIPTION
321  *      Raises the hardware priority (irql) to CLOCK2 level
322  *
323  * ARGUMENTS
324  *      None
325  *
326  * RETURN VALUE
327  *      Previous irq level
328  *
329  * NOTES
330  *      Calls KfRaiseIrql
331  */
332
333 KIRQL
334 STDCALL
335 KeRaiseIrqlToSynchLevel (VOID)
336 {
337         return KfRaiseIrql (CLOCK2_LEVEL);
338 }
339
340
341 BOOLEAN STDCALL HalBeginSystemInterrupt (ULONG Vector,
342                                          KIRQL Irql,
343                                          PKIRQL OldIrql)
344 {
345   DPRINT("Vector (0x%X)  Irql (0x%X)\n",
346     Vector, Irql);
347
348   if (Vector < FIRST_DEVICE_VECTOR ||
349     Vector > FIRST_DEVICE_VECTOR + NUMBER_DEVICE_VECTORS) {
350     DPRINT("Not a device interrupt\n");
351           return FALSE;
352   }
353
354   /*
355    * Acknowledge the interrupt
356    */
357   APICSendEOI();
358
359   *OldIrql = KeGetCurrentIrql();
360
361   KeSetCurrentIrql(Irql);
362
363   return TRUE;
364 }
365
366
367 VOID STDCALL HalEndSystemInterrupt (KIRQL Irql,
368                                     ULONG Unknown2)
369 {
370    KeSetCurrentIrql(Irql);
371 }
372
373
374 BOOLEAN STDCALL HalDisableSystemInterrupt (ULONG Vector,
375                                            ULONG Unknown2)
376 {
377   ULONG irq;
378
379   DPRINT("Vector (0x%X)\n", Vector);
380
381   if (Vector < FIRST_DEVICE_VECTOR ||
382     Vector > FIRST_DEVICE_VECTOR + NUMBER_DEVICE_VECTORS)  {
383     DPRINT("Not a device interrupt\n");
384           return FALSE;
385   }
386
387   irq = VECTOR2IRQ(Vector);
388
389   IOAPICMaskIrq(0, irq);
390
391   return TRUE;
392 }
393
394
395 BOOLEAN STDCALL HalEnableSystemInterrupt (ULONG Vector,
396                                           ULONG Unknown2,
397                                           ULONG Unknown3)
398 {
399   ULONG irq;
400
401   DPRINT("Vector (0x%X)\n", Vector);
402
403   if (Vector < FIRST_DEVICE_VECTOR ||
404     Vector > FIRST_DEVICE_VECTOR + NUMBER_DEVICE_VECTORS) {
405     DPRINT("Not a device interrupt\n");
406           return FALSE;
407   }
408
409   irq = VECTOR2IRQ(Vector);
410
411   IOAPICUnmaskIrq(0, irq);
412
413   return TRUE;
414 }
415
416 /* EOF */