Copy wininet to branch
[reactos.git] / reactos / hal / halx86 / mp / 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 <ntos/minmax.h>
18 #include <halirq.h>
19 #include <hal.h>
20 #include <mps.h>
21 #include <apic.h>
22 #include <ioapic.h>
23
24 #define NDEBUG
25 #include <internal/debug.h>
26
27 /* GLOBALS ******************************************************************/;
28
29
30 /* FUNCTIONS ****************************************************************/
31
32 KIRQL STDCALL KeGetCurrentIrql (VOID)
33 /*
34 * PURPOSE: Returns the current irq level
35 * RETURNS: The current irq level
36 */
37 {
38 KIRQL irql;
39 ULONG Flags;
40
41 Ki386SaveFlags(Flags);
42 Ki386DisableInterrupts();
43
44 irql = Ki386ReadFsByte(offsetof(KPCR, Irql));
45 if (irql > HIGH_LEVEL)
46 {
47 DPRINT1 ("CurrentIrql %x\n", irql);
48 KEBUGCHECK (0);
49 }
50 if (Flags & X86_EFLAGS_IF)
51 {
52 Ki386EnableInterrupts();
53 }
54 return irql;
55 }
56
57
58 VOID KeSetCurrentIrql (KIRQL NewIrql)
59 /*
60 * PURPOSE: Sets the current irq level without taking any action
61 */
62 {
63 ULONG Flags;
64 if (NewIrql > HIGH_LEVEL)
65 {
66 DPRINT1 ("NewIrql %x\n", NewIrql);
67 KEBUGCHECK (0);
68 }
69 Ki386SaveFlags(Flags);
70 Ki386DisableInterrupts();
71 Ki386WriteFsByte(offsetof(KPCR, Irql), NewIrql);
72 if (Flags & X86_EFLAGS_IF)
73 {
74 Ki386EnableInterrupts();
75 }
76 }
77
78 VOID
79 HalpLowerIrql(KIRQL NewIrql, BOOL FromHalEndSystemInterrupt)
80 {
81 ULONG Flags;
82 if (NewIrql >= DISPATCH_LEVEL)
83 {
84 KeSetCurrentIrql (NewIrql);
85 APICWrite(APIC_TPR, IRQL2TPR (NewIrql) & APIC_TPR_PRI);
86 return;
87 }
88 Ki386SaveFlags(Flags);
89 if (KeGetCurrentIrql() > APC_LEVEL)
90 {
91 KeSetCurrentIrql (DISPATCH_LEVEL);
92 APICWrite(APIC_TPR, IRQL2TPR (DISPATCH_LEVEL) & APIC_TPR_PRI);
93 if (FromHalEndSystemInterrupt || Ki386ReadFsByte(offsetof(KPCR, HalReserved[HAL_DPC_REQUEST])))
94 {
95 Ki386WriteFsByte(offsetof(KPCR, HalReserved[HAL_DPC_REQUEST]), 0);
96 Ki386EnableInterrupts();
97 KiDispatchInterrupt();
98 if (!(Flags & X86_EFLAGS_IF))
99 {
100 Ki386DisableInterrupts();
101 }
102 }
103 KeSetCurrentIrql (APC_LEVEL);
104 }
105 if (NewIrql == APC_LEVEL)
106 {
107 return;
108 }
109 if (KeGetCurrentThread () != NULL &&
110 KeGetCurrentThread ()->ApcState.KernelApcPending)
111 {
112 Ki386EnableInterrupts();
113 KiDeliverApc(KernelMode, NULL, NULL);
114 if (!(Flags & X86_EFLAGS_IF))
115 {
116 Ki386DisableInterrupts();
117 }
118 }
119 KeSetCurrentIrql (PASSIVE_LEVEL);
120 }
121
122
123 /**********************************************************************
124 * NAME EXPORTED
125 * KfLowerIrql
126 *
127 * DESCRIPTION
128 * Restores the irq level on the current processor
129 *
130 * ARGUMENTS
131 * NewIrql = Irql to lower to
132 *
133 * RETURN VALUE
134 * None
135 *
136 * NOTES
137 * Uses fastcall convention
138 */
139 VOID FASTCALL
140 KfLowerIrql (KIRQL NewIrql)
141 {
142 KIRQL oldIrql = KeGetCurrentIrql();
143 if (NewIrql > oldIrql)
144 {
145 DPRINT1 ("NewIrql %x CurrentIrql %x\n", NewIrql, oldIrql);
146 KEBUGCHECK (0);
147 }
148 HalpLowerIrql (NewIrql, FALSE);
149 }
150
151
152 /**********************************************************************
153 * NAME EXPORTED
154 * KeLowerIrql
155 *
156 * DESCRIPTION
157 * Restores the irq level on the current processor
158 *
159 * ARGUMENTS
160 * NewIrql = Irql to lower to
161 *
162 * RETURN VALUE
163 * None
164 *
165 * NOTES
166 */
167
168 VOID STDCALL
169 KeLowerIrql (KIRQL NewIrql)
170 {
171 KfLowerIrql (NewIrql);
172 }
173
174
175 /**********************************************************************
176 * NAME EXPORTED
177 * KfRaiseIrql
178 *
179 * DESCRIPTION
180 * Raises the hardware priority (irql)
181 *
182 * ARGUMENTS
183 * NewIrql = Irql to raise to
184 *
185 * RETURN VALUE
186 * previous irq level
187 *
188 * NOTES
189 * Uses fastcall convention
190 */
191
192 KIRQL FASTCALL
193 KfRaiseIrql (KIRQL NewIrql)
194 {
195 KIRQL OldIrql;
196 ULONG Flags;
197
198 Ki386SaveFlags(Flags);
199 Ki386DisableInterrupts();
200
201 OldIrql = KeGetCurrentIrql ();
202
203 if (NewIrql < OldIrql)
204 {
205 DPRINT1 ("CurrentIrql %x NewIrql %x\n", KeGetCurrentIrql (), NewIrql);
206 KEBUGCHECK (0);
207 }
208
209
210 if (NewIrql > DISPATCH_LEVEL)
211 {
212 APICWrite (APIC_TPR, IRQL2TPR(NewIrql) & APIC_TPR_PRI);
213 }
214 KeSetCurrentIrql (NewIrql);
215 if (Flags & X86_EFLAGS_IF)
216 {
217 Ki386EnableInterrupts();
218 }
219
220 return OldIrql;
221 }
222
223
224 /**********************************************************************
225 * NAME EXPORTED
226 * KeRaiseIrql
227 *
228 * DESCRIPTION
229 * Raises the hardware priority (irql)
230 *
231 * ARGUMENTS
232 * NewIrql = Irql to raise to
233 * OldIrql (OUT) = Caller supplied storage for the previous irql
234 *
235 * RETURN VALUE
236 * None
237 *
238 * NOTES
239 * Calls KfRaiseIrql
240 */
241 VOID STDCALL
242 KeRaiseIrql (KIRQL NewIrql,
243 PKIRQL OldIrql)
244 {
245 *OldIrql = KfRaiseIrql (NewIrql);
246 }
247
248
249 /**********************************************************************
250 * NAME EXPORTED
251 * KeRaiseIrqlToDpcLevel
252 *
253 * DESCRIPTION
254 * Raises the hardware priority (irql) to DISPATCH level
255 *
256 * ARGUMENTS
257 * None
258 *
259 * RETURN VALUE
260 * Previous irq level
261 *
262 * NOTES
263 * Calls KfRaiseIrql
264 */
265
266 KIRQL STDCALL
267 KeRaiseIrqlToDpcLevel (VOID)
268 {
269 return KfRaiseIrql (DISPATCH_LEVEL);
270 }
271
272
273 /**********************************************************************
274 * NAME EXPORTED
275 * KeRaiseIrqlToSynchLevel
276 *
277 * DESCRIPTION
278 * Raises the hardware priority (irql) to CLOCK2 level
279 *
280 * ARGUMENTS
281 * None
282 *
283 * RETURN VALUE
284 * Previous irq level
285 *
286 * NOTES
287 * Calls KfRaiseIrql
288 */
289
290 KIRQL STDCALL
291 KeRaiseIrqlToSynchLevel (VOID)
292 {
293 return KfRaiseIrql (CLOCK2_LEVEL);
294 }
295
296
297 BOOLEAN STDCALL
298 HalBeginSystemInterrupt (ULONG Vector,
299 KIRQL Irql,
300 PKIRQL OldIrql)
301 {
302 ULONG Flags;
303 DPRINT("Vector (0x%X) Irql (0x%X)\n", Vector, Irql);
304
305 if (KeGetCurrentIrql () >= Irql)
306 {
307 DPRINT1("current irql %d, new irql %d\n", KeGetCurrentIrql(), Irql);
308 KEBUGCHECK(0);
309 }
310
311 Ki386SaveFlags(Flags);
312 if (Flags & X86_EFLAGS_IF)
313 {
314 DPRINT1("HalBeginSystemInterrupt was called with interrupt's enabled\n");
315 KEBUGCHECK(0);
316 }
317 APICWrite (APIC_TPR, IRQL2TPR (Irql) & APIC_TPR_PRI);
318 *OldIrql = KeGetCurrentIrql ();
319 KeSetCurrentIrql (Irql);
320 return(TRUE);
321 }
322
323
324 VOID STDCALL
325 HalEndSystemInterrupt (KIRQL Irql,
326 ULONG Unknown2)
327 /*
328 * FUNCTION: Finish a system interrupt and restore the specified irq level.
329 */
330 {
331 ULONG Flags;
332 Ki386SaveFlags(Flags);
333
334 if (Flags & X86_EFLAGS_IF)
335 {
336 DPRINT1("HalEndSystemInterrupt was called with interrupt's enabled\n");
337 KEBUGCHECK(0);
338 }
339 APICSendEOI();
340 HalpLowerIrql (Irql, TRUE);
341 }
342
343 BOOLEAN STDCALL
344 HalDisableSystemInterrupt (ULONG Vector,
345 KIRQL Irql)
346 {
347 ULONG irq;
348
349 DPRINT ("Vector (0x%X)\n", Vector);
350
351 if (Vector < FIRST_DEVICE_VECTOR ||
352 Vector >= FIRST_DEVICE_VECTOR + NUMBER_DEVICE_VECTORS)
353 {
354 DPRINT1("Not a device interrupt, vector=%x\n", Vector);
355 return FALSE;
356 }
357
358 irq = VECTOR2IRQ (Vector);
359 IOAPICMaskIrq (irq);
360
361 return TRUE;
362 }
363
364
365 BOOLEAN STDCALL
366 HalEnableSystemInterrupt (ULONG Vector,
367 KIRQL Irql,
368 KINTERRUPT_MODE InterruptMode)
369 {
370 ULONG irq;
371
372 if (Vector < FIRST_DEVICE_VECTOR ||
373 Vector >= FIRST_DEVICE_VECTOR + NUMBER_DEVICE_VECTORS)
374 {
375 DPRINT("Not a device interrupt\n");
376 return FALSE;
377 }
378
379 /* FIXME: We must check if the requested and the assigned interrupt mode is the same */
380
381 irq = VECTOR2IRQ (Vector);
382 IOAPICUnmaskIrq (irq);
383
384 return TRUE;
385 }
386
387 VOID FASTCALL
388 HalRequestSoftwareInterrupt(IN KIRQL Request)
389 {
390 switch (Request)
391 {
392 case APC_LEVEL:
393 Ki386WriteFsByte(offsetof(KPCR, HalReserved[HAL_APC_REQUEST]), 1);
394 break;
395
396 case DISPATCH_LEVEL:
397 Ki386WriteFsByte(offsetof(KPCR, HalReserved[HAL_DPC_REQUEST]), 1);
398 break;
399
400 default:
401 KEBUGCHECK(0);
402 }
403 }