Added calibration of KeStallExecutionProcessor delay
[reactos.git] / reactos / ntoskrnl / hal / x86 / 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/bitops.h>
13 #include <internal/halio.h>
14 #include <internal/ke.h>
15 #include <internal/ps.h>
16
17 #define NDEBUG
18 #include <internal/debug.h>
19
20 /* GLOBALS ******************************************************************/
21
22 /* FIXME: this should be in a header file */
23 #define NR_IRQS (16)
24 #define IRQ_BASE (0x40)
25
26 /*
27 * PURPOSE: Current irq level
28 */
29 static KIRQL CurrentIrql = HIGH_LEVEL;
30
31 extern ULONG DpcQueueSize;
32
33 static VOID KeSetCurrentIrql(KIRQL newlvl);
34
35 /* FUNCTIONS ****************************************************************/
36
37 VOID HalpInitPICs(VOID)
38 {
39 /* Mask off all interrupts from PICs */
40 outb(0x21,0xff);
41 outb(0xa1,0xff);
42 }
43
44 #if 0
45 static unsigned int HiGetCurrentPICMask(void)
46 {
47 unsigned int mask;
48
49 mask = inb_p(0x21);
50 mask = mask | (inb_p(0xa1)<<8);
51
52 return mask;
53 }
54 #endif
55
56 static unsigned int HiSetCurrentPICMask(unsigned int mask)
57 {
58 outb_p(0x21,mask & 0xff);
59 outb_p(0xa1,(mask >> 8) & 0xff);
60
61 return mask;
62 }
63
64 static VOID HiSwitchIrql(KIRQL oldIrql)
65 /*
66 * FUNCTION: Switches to the current irql
67 * NOTE: Must be called with interrupt disabled
68 */
69 {
70 unsigned int i;
71 PKTHREAD CurrentThread;
72
73 CurrentThread = KeGetCurrentThread();
74
75 if (CurrentIrql == HIGH_LEVEL)
76 {
77 HiSetCurrentPICMask(0xffff);
78 return;
79 }
80 if (CurrentIrql > DISPATCH_LEVEL)
81 {
82 unsigned int current_mask = 0;
83
84 for (i=CurrentIrql; i>DISPATCH_LEVEL; i--)
85 {
86 current_mask = current_mask | (1 << (HIGH_LEVEL - i));
87 }
88
89 HiSetCurrentPICMask(current_mask);
90 __asm__("sti\n\t");
91 return;
92 }
93
94 if (CurrentIrql == DISPATCH_LEVEL)
95 {
96 HiSetCurrentPICMask(0);
97 __asm__("sti\n\t");
98 return;
99 }
100
101 HiSetCurrentPICMask(0);
102 if (CurrentIrql == APC_LEVEL)
103 {
104 if (DpcQueueSize > 0 )
105 {
106 KeSetCurrentIrql(DISPATCH_LEVEL);
107 __asm__("sti\n\t");
108 KiDispatchInterrupt();
109 __asm__("cli\n\t");
110 KeSetCurrentIrql(PASSIVE_LEVEL);
111 }
112 __asm__("sti\n\t");
113 return;
114 }
115
116 if (CurrentIrql == PASSIVE_LEVEL &&
117 CurrentThread != NULL &&
118 CurrentThread->ApcState.KernelApcPending)
119 {
120 KeSetCurrentIrql(APC_LEVEL);
121 __asm__("sti\n\t");
122 KiDeliverApc(0, 0, 0);
123 __asm__("cli\n\t");
124 KeSetCurrentIrql(PASSIVE_LEVEL);
125 __asm__("sti\n\t");
126 }
127 else
128 {
129 __asm__("sti\n\t");
130 }
131 }
132
133
134 KIRQL STDCALL KeGetCurrentIrql (VOID)
135 /*
136 * PURPOSE: Returns the current irq level
137 * RETURNS: The current irq level
138 */
139 {
140 return(CurrentIrql);
141 }
142
143
144 static VOID KeSetCurrentIrql(KIRQL newlvl)
145 /*
146 * PURPOSE: Sets the current irq level without taking any action
147 */
148 {
149 // DPRINT("KeSetCurrentIrql(newlvl %x)\n",newlvl);
150 CurrentIrql = newlvl;
151 }
152
153
154 /**********************************************************************
155 * NAME EXPORTED
156 * KfLowerIrql
157 *
158 * DESCRIPTION
159 * Restores the irq level on the current processor
160 *
161 * ARGUMENTS
162 * NewIrql = Irql to lower to
163 *
164 * RETURN VALUE
165 * None
166 *
167 * NOTES
168 * Uses fastcall convention
169 */
170
171 VOID
172 FASTCALL
173 KfLowerIrql (
174 KIRQL NewIrql
175 )
176 {
177 KIRQL OldIrql;
178
179 __asm__("cli\n\t");
180
181 DPRINT("KfLowerIrql(NewIrql %d)\n", NewIrql);
182
183 if (NewIrql > CurrentIrql)
184 {
185 DbgPrint ("(%s:%d) NewIrql %x CurrentIrql %x\n",
186 __FILE__, __LINE__, NewIrql, CurrentIrql);
187 KeDumpStackFrames (0, 32);
188 for(;;);
189 }
190
191 OldIrql = CurrentIrql;
192 CurrentIrql = NewIrql;
193 HiSwitchIrql(OldIrql);
194 }
195
196
197 /**********************************************************************
198 * NAME EXPORTED
199 * KeLowerIrql
200 *
201 * DESCRIPTION
202 * Restores the irq level on the current processor
203 *
204 * ARGUMENTS
205 * NewIrql = Irql to lower to
206 *
207 * RETURN VALUE
208 * None
209 *
210 * NOTES
211 */
212
213 VOID
214 STDCALL
215 KeLowerIrql (
216 KIRQL NewIrql
217 )
218 {
219 KfLowerIrql (NewIrql);
220 }
221
222
223 /**********************************************************************
224 * NAME EXPORTED
225 * KfRaiseIrql
226 *
227 * DESCRIPTION
228 * Raises the hardware priority (irql)
229 *
230 * ARGUMENTS
231 * NewIrql = Irql to raise to
232 *
233 * RETURN VALUE
234 * previous irq level
235 *
236 * NOTES
237 * Uses fastcall convention
238 */
239
240 KIRQL
241 FASTCALL
242 KfRaiseIrql (
243 KIRQL NewIrql
244 )
245 {
246 KIRQL OldIrql;
247
248 DPRINT("KfRaiseIrql(NewIrql %d)\n", NewIrql);
249
250 if (NewIrql < CurrentIrql)
251 {
252 DbgPrint ("%s:%d CurrentIrql %x NewIrql %x\n",
253 __FILE__,__LINE__,CurrentIrql,NewIrql);
254 KeBugCheck (0);
255 for(;;);
256 }
257
258 __asm__("cli\n\t");
259 OldIrql = CurrentIrql;
260 CurrentIrql = NewIrql;
261
262 DPRINT ("NewIrql %x OldIrql %x CurrentIrql %x\n",
263 NewIrql, OldIrql, CurrentIrql);
264 HiSwitchIrql(OldIrql);
265
266 return OldIrql;
267 }
268
269
270 /**********************************************************************
271 * NAME EXPORTED
272 * KeRaiseIrql
273 *
274 * DESCRIPTION
275 * Raises the hardware priority (irql)
276 *
277 * ARGUMENTS
278 * NewIrql = Irql to raise to
279 * OldIrql (OUT) = Caller supplied storage for the previous irql
280 *
281 * RETURN VALUE
282 * None
283 *
284 * NOTES
285 * Calls KfRaiseIrql
286 */
287
288 VOID
289 STDCALL
290 KeRaiseIrql (
291 KIRQL NewIrql,
292 PKIRQL OldIrql
293 )
294 {
295 *OldIrql = KfRaiseIrql (NewIrql);
296 }
297
298
299 BOOLEAN STDCALL HalBeginSystemInterrupt (ULONG Vector,
300 KIRQL Irql,
301 PKIRQL OldIrql)
302 {
303 if (Vector < IRQ_BASE || Vector > IRQ_BASE + NR_IRQS)
304 return FALSE;
305
306 /* Send EOI to the PICs */
307 outb(0x20,0x20);
308 if ((Vector-IRQ_BASE)>=8)
309 {
310 outb(0xa0,0x20);
311 }
312
313 *OldIrql = KeGetCurrentIrql();
314 if (Vector-IRQ_BASE != 0)
315 {
316 DPRINT("old_level %d\n",*OldIrql);
317 }
318 KeSetCurrentIrql(Irql);
319
320 return TRUE;
321 }
322
323
324 VOID STDCALL HalEndSystemInterrupt (KIRQL Irql,
325 ULONG Unknown2)
326 {
327 KeSetCurrentIrql(Irql);
328 }
329
330
331 BOOLEAN STDCALL HalDisableSystemInterrupt (ULONG Vector,
332 ULONG Unknown2)
333 {
334 ULONG irq;
335
336 if (Vector < IRQ_BASE || Vector > IRQ_BASE + NR_IRQS)
337 return FALSE;
338
339 irq = Vector - IRQ_BASE;
340 if (irq<8)
341 {
342 outb(0x21,inb(0x21)|(1<<irq));
343 }
344 else
345 {
346 outb(0xa1,inb(0xa1)|(1<<(irq-8)));
347 }
348
349 return TRUE;
350 }
351
352
353 BOOLEAN STDCALL HalEnableSystemInterrupt (ULONG Vector,
354 ULONG Unknown2,
355 ULONG Unknown3)
356 {
357 ULONG irq;
358
359 if (Vector < IRQ_BASE || Vector > IRQ_BASE + NR_IRQS)
360 return FALSE;
361
362 irq = Vector - IRQ_BASE;
363 if (irq<8)
364 {
365 outb(0x21,inb(0x21)&(~(1<<irq)));
366 }
367 else
368 {
369 outb(0xa1,inb(0xa1)&(~(1<<(irq-8))));
370 }
371
372 return TRUE;
373 }
374
375 /* EOF */