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