957cffd8f98078c31589e0b11949df11cbe11da1
[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 NTAPI 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 Flags = __readeflags();
34 _disable();
35
36 irql = __readfsbyte(FIELD_OFFSET(KPCR, Irql));
37 if (irql > HIGH_LEVEL)
38 {
39 DPRINT1 ("CurrentIrql %x\n", irql);
40 ASSERT(FALSE);
41 }
42 if (Flags & EFLAGS_INTERRUPT_MASK)
43 {
44 _enable();
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 ASSERT(FALSE);
61 }
62 Flags = __readeflags();
63 _disable();
64 __writefsbyte(FIELD_OFFSET(KPCR, Irql), NewIrql);
65 if (Flags & EFLAGS_INTERRUPT_MASK)
66 {
67 _enable();
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 Flags = __readeflags();
83 if (KeGetCurrentIrql() > APC_LEVEL)
84 {
85 KeSetCurrentIrql (DISPATCH_LEVEL);
86 APICWrite(APIC_TPR, IRQL2TPR (DISPATCH_LEVEL) & APIC_TPR_PRI);
87 DpcRequested = __readfsbyte(FIELD_OFFSET(KIPCR, HalReserved[HAL_DPC_REQUEST]));
88 if (FromHalEndSystemInterrupt || DpcRequested)
89 {
90 __writefsbyte(FIELD_OFFSET(KIPCR, HalReserved[HAL_DPC_REQUEST]), 0);
91 _enable();
92 KiDispatchInterrupt();
93 if (!(Flags & EFLAGS_INTERRUPT_MASK))
94 {
95 _disable();
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 _enable();
108 KiDeliverApc(KernelMode, NULL, NULL);
109 if (!(Flags & EFLAGS_INTERRUPT_MASK))
110 {
111 _disable();
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 ASSERT(FALSE);
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 NTAPI
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 Flags = __readeflags();
194 _disable();
195
196 OldIrql = KeGetCurrentIrql ();
197
198 if (NewIrql < OldIrql)
199 {
200 DPRINT1 ("CurrentIrql %x NewIrql %x\n", KeGetCurrentIrql (), NewIrql);
201 ASSERT(FALSE);
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 _enable();
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 NTAPI
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 NTAPI
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 NTAPI
287 KeRaiseIrqlToSynchLevel (VOID)
288 {
289 return KfRaiseIrql (CLOCK2_LEVEL);
290 }
291
292
293 BOOLEAN NTAPI
294 HalBeginSystemInterrupt (KIRQL Irql,
295 ULONG Vector,
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 ASSERT(FALSE);
305 }
306
307 Flags = __readeflags();
308 if (Flags & EFLAGS_INTERRUPT_MASK)
309 {
310 DPRINT1("HalBeginSystemInterrupt was called with interrupt's enabled\n");
311 ASSERT(FALSE);
312 }
313 APICWrite (APIC_TPR, IRQL2TPR (Irql) & APIC_TPR_PRI);
314 *OldIrql = KeGetCurrentIrql ();
315 KeSetCurrentIrql (Irql);
316 return(TRUE);
317 }
318
319
320 VOID NTAPI
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 Flags = __readeflags();
329
330 if (Flags & EFLAGS_INTERRUPT_MASK)
331 {
332 DPRINT1("HalEndSystemInterrupt was called with interrupt's enabled\n");
333 ASSERT(FALSE);
334 }
335 APICSendEOI();
336 HalpLowerIrql (Irql, TRUE);
337 }
338
339 VOID
340 NTAPI
341 HalDisableSystemInterrupt(ULONG Vector,
342 KIRQL Irql)
343 {
344 ULONG irq;
345
346 DPRINT ("Vector (0x%X)\n", Vector);
347
348 if (Vector < FIRST_DEVICE_VECTOR ||
349 Vector >= FIRST_DEVICE_VECTOR + NUMBER_DEVICE_VECTORS)
350 {
351 DPRINT1("Not a device interrupt, vector=%x\n", Vector);
352 ASSERT(FALSE);
353 return;
354 }
355
356 irq = VECTOR2IRQ (Vector);
357 IOAPICMaskIrq (irq);
358
359 return;
360 }
361
362
363 BOOLEAN NTAPI
364 HalEnableSystemInterrupt (ULONG Vector,
365 KIRQL Irql,
366 KINTERRUPT_MODE InterruptMode)
367 {
368 ULONG irq;
369
370 if (Vector < FIRST_DEVICE_VECTOR ||
371 Vector >= FIRST_DEVICE_VECTOR + NUMBER_DEVICE_VECTORS)
372 {
373 DPRINT("Not a device interrupt\n");
374 return FALSE;
375 }
376
377 /* FIXME: We must check if the requested and the assigned interrupt mode is the same */
378
379 irq = VECTOR2IRQ (Vector);
380 IOAPICUnmaskIrq (irq);
381
382 return TRUE;
383 }
384
385 VOID FASTCALL
386 HalRequestSoftwareInterrupt(IN KIRQL Request)
387 {
388 switch (Request)
389 {
390 case APC_LEVEL:
391 __writefsbyte(FIELD_OFFSET(KIPCR, HalReserved[HAL_APC_REQUEST]), 1);
392 break;
393
394 case DISPATCH_LEVEL:
395 __writefsbyte(FIELD_OFFSET(KIPCR, HalReserved[HAL_DPC_REQUEST]), 1);
396 break;
397
398 default:
399 ASSERT(FALSE);
400 }
401 }
402
403 VOID FASTCALL
404 HalClearSoftwareInterrupt(
405 IN KIRQL Request)
406 {
407 UNIMPLEMENTED;
408 }