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