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