339cfa3c2d2de6417c745d39cb5d72d0b655d2d8
[reactos.git] / reactos / hal / halx86 / apic / apic.c
1 /*
2 * PROJECT: ReactOS HAL
3 * LICENSE: GNU GPL - See COPYING in the top level directory
4 * FILE: hal/halx86/generic/apic.c
5 * PURPOSE: HAL APIC Management and Control Code
6 * PROGRAMMERS: Timo Kreuzer (timo.kreuzer@reactos.org)
7 * REFERENCES: http://www.joseflores.com/docs/ExploringIrql.html
8 * http://www.codeproject.com/KB/system/soviet_kernel_hack.aspx
9 * http://bbs.unixmap.net/thread-2022-1-1.html
10 */
11
12 /* INCLUDES *******************************************************************/
13
14 #include <hal.h>
15 #define NDEBUG
16 #include <debug.h>
17
18 #include "apic.h"
19 void HackEoi(void);
20
21 /* GLOBALS ********************************************************************/
22
23 ULONG ApicVersion;
24 UCHAR HalpVectorToIndex[256];
25
26 #ifndef _M_AMD64
27 static const UCHAR
28 HalpIRQLtoTPR[32] =
29 {
30 0x00, /* 0 PASSIVE_LEVEL */
31 0x3d, /* 1 APC_LEVEL */
32 0x41, /* 2 DISPATCH_LEVEL */
33 0x41, /* 3 \ */
34 0x51, /* 4 \ */
35 0x61, /* 5 | */
36 0x71, /* 6 | */
37 0x81, /* 7 | */
38 0x91, /* 8 | */
39 0xa1, /* 9 | */
40 0xb1, /* 10 | */
41 0xb1, /* 11 | */
42 0xb1, /* 12 | */
43 0xb1, /* 13 | */
44 0xb1, /* 14 | */
45 0xb1, /* 15 DEVICE IRQL */
46 0xb1, /* 16 | */
47 0xb1, /* 17 | */
48 0xb1, /* 18 | */
49 0xb1, /* 19 | */
50 0xb1, /* 20 | */
51 0xb1, /* 21 | */
52 0xb1, /* 22 | */
53 0xb1, /* 23 | */
54 0xb1, /* 24 | */
55 0xb1, /* 25 / */
56 0xb1, /* 26 / */
57 0xc1, /* 27 PROFILE_LEVEL */
58 0xd1, /* 28 CLOCK2_LEVEL */
59 0xe1, /* 29 IPI_LEVEL */
60 0xef, /* 30 POWER_LEVEL */
61 0xff, /* 31 HIGH_LEVEL */
62 };
63
64 static const KIRQL
65 HalVectorToIRQL[16] =
66 {
67 0, /* 00 PASSIVE_LEVEL */
68 0xff, /* 10 */
69 0xff, /* 20 */
70 1, /* 3D APC_LEVEL */
71 2, /* 41 DISPATCH_LEVEL */
72 4, /* 50 \ */
73 5, /* 60 \ */
74 6, /* 70 | */
75 7, /* 80 DEVICE IRQL */
76 8, /* 90 | */
77 9, /* A0 / */
78 10, /* B0 / */
79 27, /* C1 PROFILE_LEVEL */
80 28, /* D1 CLOCK2_LEVEL */
81 29, /* E1 IPI_LEVEL / EF POWER_LEVEL */
82 31, /* FF HIGH_LEVEL */
83 };
84 #endif
85
86 /* PRIVATE FUNCTIONS **********************************************************/
87
88 ULONG
89 FORCEINLINE
90 IOApicRead(UCHAR Register)
91 {
92 /* Select the register, then do the read */
93 *(volatile UCHAR *)(IOAPIC_BASE + IOAPIC_IOREGSEL) = Register;
94 return *(volatile ULONG *)(IOAPIC_BASE + IOAPIC_IOWIN);
95 }
96
97 VOID
98 FORCEINLINE
99 IOApicWrite(UCHAR Register, ULONG Value)
100 {
101 /* Select the register, then do the write */
102 *(volatile UCHAR *)(IOAPIC_BASE + IOAPIC_IOREGSEL) = Register;
103 *(volatile ULONG *)(IOAPIC_BASE + IOAPIC_IOWIN) = Value;
104 }
105
106 VOID
107 FORCEINLINE
108 ApicSendEOI(void)
109 {
110 //ApicWrite(APIC_EOI, 0);
111 HackEoi();
112 }
113
114 KIRQL
115 FORCEINLINE
116 ApicGetProcessorIrql(VOID)
117 {
118 /* Read the TPR and convert it to an IRQL */
119 return TprToIrql(ApicRead(APIC_PPR));
120 }
121
122 KIRQL
123 FORCEINLINE
124 ApicGetCurrentIrql(VOID)
125 {
126 #ifdef _M_AMD64
127 return (KIRQL)__readcr8();
128 #else
129 // HACK: some magic to Sync VBox's APIC registers
130 ApicRead(APIC_VER);
131
132 /* Read the TPR and convert it to an IRQL */
133 return TprToIrql(ApicRead(APIC_TPR));
134 #endif
135 }
136
137 VOID
138 FORCEINLINE
139 ApicSetCurrentIrql(KIRQL Irql)
140 {
141 #ifdef _M_AMD64
142 __writecr8(Irql);
143 #else
144 /* Convert IRQL and write the TPR */
145 ApicWrite(APIC_TPR, IrqlToTpr(Irql));
146 #endif
147 }
148
149 UCHAR
150 FASTCALL
151 HalpIrqToVector(UCHAR Irq)
152 {
153 IOAPIC_REDIRECTION_REGISTER ReDirReg;
154
155 /* Read low dword of the redirection entry */
156 ReDirReg.Long0 = IOApicRead(IOAPIC_REDTBL + 2 * Irq);
157
158 /* Return the vector */
159 return (UCHAR)ReDirReg.Vector;
160 }
161
162 KIRQL
163 FASTCALL
164 HalpVectorToIrql(UCHAR Vector)
165 {
166 return TprToIrql(Vector);
167 }
168
169 UCHAR
170 FASTCALL
171 HalpVectorToIrq(UCHAR Vector)
172 {
173 return HalpVectorToIndex[Vector];
174 }
175
176 VOID
177 NTAPI
178 HalpInitializeLegacyPIC(VOID)
179 {
180 I8259_ICW1 Icw1;
181 I8259_ICW2 Icw2;
182 I8259_ICW3 Icw3;
183 I8259_ICW4 Icw4;
184
185 /* Initialize ICW1 for master, interval 8, edge-triggered mode with ICW4 */
186 Icw1.NeedIcw4 = TRUE;
187 Icw1.OperatingMode = Cascade;
188 Icw1.Interval = Interval8;
189 Icw1.InterruptMode = EdgeTriggered;
190 Icw1.Init = TRUE;
191 Icw1.InterruptVectorAddress = 0;
192 __outbyte(PIC1_CONTROL_PORT, Icw1.Bits);
193
194 /* ICW2 - interrupt vector offset */
195 Icw2.Bits = PRIMARY_VECTOR_BASE;
196 __outbyte(PIC1_DATA_PORT, Icw2.Bits);
197
198 /* Connect slave to IRQ 2 */
199 Icw3.Bits = 0;
200 Icw3.SlaveIrq2 = TRUE;
201 __outbyte(PIC1_DATA_PORT, Icw3.Bits);
202
203 /* Enable 8086 mode, non-automatic EOI, non-buffered mode, non special fully nested mode */
204 Icw4.SystemMode = New8086Mode;
205 Icw4.EoiMode = NormalEoi;
206 Icw4.BufferedMode = NonBuffered;
207 Icw4.SpecialFullyNestedMode = FALSE;
208 Icw4.Reserved = 0;
209 __outbyte(PIC1_DATA_PORT, Icw4.Bits);
210
211 /* Mask all interrupts */
212 __outbyte(PIC1_DATA_PORT, 0xFF);
213
214 /* Initialize ICW1 for slave, interval 8, edge-triggered mode with ICW4 */
215 Icw1.NeedIcw4 = TRUE;
216 Icw1.InterruptMode = EdgeTriggered;
217 Icw1.OperatingMode = Cascade;
218 Icw1.Interval = Interval8;
219 Icw1.Init = TRUE;
220 Icw1.InterruptVectorAddress = 0; /* This is only used in MCS80/85 mode */
221 __outbyte(PIC2_CONTROL_PORT, Icw1.Bits);
222
223 /* Set interrupt vector base */
224 Icw2.Bits = PRIMARY_VECTOR_BASE + 8;
225 __outbyte(PIC2_DATA_PORT, Icw2.Bits);
226
227 /* Slave ID */
228 Icw3.Bits = 0;
229 Icw3.SlaveId = 2;
230 __outbyte(PIC2_DATA_PORT, Icw3.Bits);
231
232 /* Enable 8086 mode, non-automatic EOI, non-buffered mode, non special fully nested mode */
233 Icw4.SystemMode = New8086Mode;
234 Icw4.EoiMode = NormalEoi;
235 Icw4.BufferedMode = NonBuffered;
236 Icw4.SpecialFullyNestedMode = FALSE;
237 Icw4.Reserved = 0;
238 __outbyte(PIC2_DATA_PORT, Icw4.Bits);
239
240 /* Mask all interrupts */
241 __outbyte(PIC2_DATA_PORT, 0xFF);
242 }
243
244 VOID
245 NTAPI
246 ApicInitializeLocalApic(ULONG Cpu)
247 {
248 APIC_BASE_ADRESS_REGISTER BaseRegister;
249 APIC_SPURIOUS_INERRUPT_REGISTER SpIntRegister;
250 LVT_REGISTER LvtEntry;
251
252 /* Enable the APIC if it wasn't yet */
253 BaseRegister.Long = __readmsr(MSR_APIC_BASE);
254 BaseRegister.Enable = 1;
255 BaseRegister.BootStrapCPUCore = (Cpu == 0);
256 __writemsr(MSR_APIC_BASE, BaseRegister.Long);
257
258 /* Set spurious vector and SoftwareEnable to 1 */
259 SpIntRegister.Long = ApicRead(APIC_SIVR);
260 SpIntRegister.Vector = APIC_SPURIOUS_VECTOR;
261 SpIntRegister.SoftwareEnable = 1;
262 SpIntRegister.FocusCPUCoreChecking = 0;
263 ApicWrite(APIC_SIVR, SpIntRegister.Long);
264
265 /* Read the version and save it globally */
266 if (Cpu == 0) ApicVersion = ApicRead(APIC_VER);
267
268 /* Set the mode to flat (max 8 CPUs supported!) */
269 ApicWrite(APIC_DFR, APIC_DF_Flat);
270
271 /* Set logical apic ID */
272 ApicWrite(APIC_LDR, ApicLogicalId(Cpu) << 24);
273
274 /* Set the spurious ISR */
275 KeRegisterInterruptHandler(APIC_SPURIOUS_VECTOR, ApicSpuriousService);
276
277 /* Create a template LVT */
278 LvtEntry.Long = 0;
279 LvtEntry.Vector = 0xFF;
280 LvtEntry.MessageType = APIC_MT_Fixed;
281 LvtEntry.DeliveryStatus = 0;
282 LvtEntry.RemoteIRR = 0;
283 LvtEntry.TriggerMode = APIC_TGM_Edge;
284 LvtEntry.Mask = 1;
285 LvtEntry.TimerMode = 0;
286
287 /* Initalize and mask LVTs */
288 ApicWrite(APIC_TMRLVTR, LvtEntry.Long);
289 ApicWrite(APIC_THRMLVTR, LvtEntry.Long);
290 ApicWrite(APIC_PCLVTR, LvtEntry.Long);
291 ApicWrite(APIC_EXT0LVTR, LvtEntry.Long);
292 ApicWrite(APIC_EXT1LVTR, LvtEntry.Long);
293 ApicWrite(APIC_EXT2LVTR, LvtEntry.Long);
294 ApicWrite(APIC_EXT3LVTR, LvtEntry.Long);
295
296 /* LINT0 */
297 LvtEntry.Vector = APIC_SPURIOUS_VECTOR;
298 LvtEntry.MessageType = APIC_MT_ExtInt;
299 ApicWrite(APIC_LINT0, LvtEntry.Long);
300
301 /* Enable LINT1 (NMI) */
302 LvtEntry.Mask = 0;
303 LvtEntry.Vector = APIC_NMI_VECTOR;
304 LvtEntry.MessageType = APIC_MT_NMI;
305 LvtEntry.TriggerMode = APIC_TGM_Level;
306 ApicWrite(APIC_LINT1, LvtEntry.Long);
307
308 /* Enable error LVTR */
309 LvtEntry.Vector = APIC_ERROR_VECTOR;
310 LvtEntry.MessageType = APIC_MT_Fixed;
311 ApicWrite(APIC_ERRLVTR, LvtEntry.Long);
312
313 /* Set the IRQL from the PCR */
314 ApicSetCurrentIrql(KeGetPcr()->Irql);
315 }
316
317
318 VOID
319 FORCEINLINE
320 ApicWriteIORedirectionEntry(
321 UCHAR Index,
322 IOAPIC_REDIRECTION_REGISTER ReDirReg)
323 {
324 IOApicWrite(IOAPIC_REDTBL + 2 * Index, ReDirReg.Long0);
325 IOApicWrite(IOAPIC_REDTBL + 2 * Index + 1, ReDirReg.Long1);
326 }
327
328 IOAPIC_REDIRECTION_REGISTER
329 FORCEINLINE
330 ApicReadIORedirectionEntry(
331 UCHAR Index)
332 {
333 IOAPIC_REDIRECTION_REGISTER ReDirReg;
334
335 ReDirReg.Long0 = IOApicRead(IOAPIC_REDTBL + 2 * Index);
336 ReDirReg.Long1 = IOApicRead(IOAPIC_REDTBL + 2 * Index + 1);
337
338 return ReDirReg;
339 }
340
341 UCHAR
342 NTAPI
343 HalpAllocateSystemInterrupt(
344 IN UCHAR Irq,
345 IN KIRQL Irql)
346 {
347 IOAPIC_REDIRECTION_REGISTER ReDirReg;
348 IN UCHAR Vector;
349
350 /* Start with low vector */
351 Vector = IrqlToTpr(Irql);
352
353 /* Find an empty vector */
354 while (HalpVectorToIndex[Vector] != 0xFF)
355 {
356 Vector++;
357
358 /* Check if we went over the edge */
359 if (TprToIrql(Vector) > Irql)
360 {
361 /* Nothing free, return failure */
362 return 0;
363 }
364 }
365
366 /* Save irq in the table */
367 HalpVectorToIndex[Vector] = Irq;
368
369 /* Setup a redirection entry */
370 ReDirReg.Vector = Vector;
371 ReDirReg.DeliveryMode = APIC_MT_LowestPriority;
372 ReDirReg.DestinationMode = APIC_DM_Logical;
373 ReDirReg.DeliveryStatus = 0;
374 ReDirReg.Polarity = 0;
375 ReDirReg.RemoteIRR = 0;
376 ReDirReg.TriggerMode = APIC_TGM_Edge;
377 ReDirReg.Mask = 1;
378 ReDirReg.Reserved = 0;
379 ReDirReg.Destination = 0;
380
381 /* Initialize entry */
382 IOApicWrite(IOAPIC_REDTBL + 2 * Irq, ReDirReg.Long0);
383 IOApicWrite(IOAPIC_REDTBL + 2 * Irq + 1, ReDirReg.Long1);
384
385 return Vector;
386 }
387
388 VOID
389 NTAPI
390 ApicInitializeIOApic(VOID)
391 {
392 PHARDWARE_PTE Pte;
393 IOAPIC_REDIRECTION_REGISTER ReDirReg;
394 UCHAR Index;
395 ULONG Vector;
396
397 /* Map the I/O Apic page */
398 Pte = HalAddressToPte(IOAPIC_BASE);
399 Pte->PageFrameNumber = IOAPIC_PHYS_BASE / PAGE_SIZE;
400 Pte->Valid = 1;
401 Pte->Write = 1;
402 Pte->Owner = 1;
403 Pte->CacheDisable = 1;
404 Pte->Global = 1;
405 _ReadWriteBarrier();
406
407 /* Setup a redirection entry */
408 ReDirReg.Vector = 0xFF;
409 ReDirReg.DeliveryMode = APIC_MT_Fixed;
410 ReDirReg.DestinationMode = APIC_DM_Physical;
411 ReDirReg.DeliveryStatus = 0;
412 ReDirReg.Polarity = 0;
413 ReDirReg.RemoteIRR = 0;
414 ReDirReg.TriggerMode = APIC_TGM_Edge;
415 ReDirReg.Mask = 1;
416 ReDirReg.Reserved = 0;
417 ReDirReg.Destination = 0;
418
419 /* Loop all table entries */
420 for (Index = 0; Index < 24; Index++)
421 {
422 /* Initialize entry */
423 IOApicWrite(IOAPIC_REDTBL + 2 * Index, ReDirReg.Long0);
424 IOApicWrite(IOAPIC_REDTBL + 2 * Index + 1, ReDirReg.Long1);
425 }
426
427 /* Init the vactor to index table */
428 for (Vector = 0; Vector <= 255; Vector++)
429 {
430 HalpVectorToIndex[Vector] = 0xFF;
431 }
432
433 // HACK: Allocate all IRQs, should rather do that on demand
434 for (Index = 0; Index <= 15; Index++)
435 {
436 /* Map the IRQs to IRQLs like with the PIC */
437 HalpAllocateSystemInterrupt(Index, 27 - Index);
438 }
439
440 /* Enable the timer interrupt */
441 ReDirReg.Vector = APIC_CLOCK_VECTOR;
442 ReDirReg.DeliveryMode = APIC_MT_Fixed;
443 ReDirReg.DestinationMode = APIC_DM_Physical;
444 ReDirReg.TriggerMode = APIC_TGM_Edge;
445 ReDirReg.Mask = 0;
446 ReDirReg.Destination = ApicRead(APIC_ID);
447 IOApicWrite(IOAPIC_REDTBL + 2 * APIC_CLOCK_INDEX, ReDirReg.Long0);
448
449 ApicSendEOI();
450 }
451
452 VOID
453 NTAPI
454 HalpInitializePICs(IN BOOLEAN EnableInterrupts)
455 {
456 ULONG_PTR EFlags;
457
458 /* Save EFlags and disable interrupts */
459 EFlags = __readeflags();
460 _disable();
461
462 /* Initialize and mask the PIC */
463 HalpInitializeLegacyPIC();
464
465 /* Initialize the I/O APIC */
466 ApicInitializeIOApic();
467
468 /* Manually reserve some vectors */
469 HalpVectorToIndex[APIC_CLOCK_VECTOR] = 8;
470 HalpVectorToIndex[APC_VECTOR] = 99;
471 HalpVectorToIndex[DISPATCH_VECTOR] = 99;
472
473 /* Set interrupt handlers in the IDT */
474 KeRegisterInterruptHandler(APIC_CLOCK_VECTOR, HalpClockInterrupt);
475 #ifndef _M_AMD64
476 KeRegisterInterruptHandler(APC_VECTOR, HalpApcInterrupt);
477 KeRegisterInterruptHandler(DISPATCH_VECTOR, HalpDispatchInterrupt);
478 #endif
479
480 /* Register the vectors for APC and dispatch interrupts */
481 HalpRegisterVector(IDT_INTERNAL, 0, APC_VECTOR, APC_LEVEL);
482 HalpRegisterVector(IDT_INTERNAL, 0, DISPATCH_VECTOR, DISPATCH_LEVEL);
483
484 /* Restore interrupt state */
485 if (EnableInterrupts) EFlags |= EFLAGS_INTERRUPT_MASK;
486 __writeeflags(EFlags);
487 }
488
489 VOID
490 DECLSPEC_NORETURN
491 FASTCALL
492 HalpApcInterruptHandler(IN PKTRAP_FRAME TrapFrame)
493 {
494 KPROCESSOR_MODE ProcessorMode;
495 KIRQL OldIrql;
496 ASSERT(ApicGetCurrentIrql() < APC_LEVEL);
497 ASSERT(ApicGetProcessorIrql() == APC_LEVEL);
498
499 /* Enter trap */
500 KiEnterInterruptTrap(TrapFrame);
501
502 /* Save the old IRQL */
503 OldIrql = ApicGetCurrentIrql();
504
505 /* Raise to APC_LEVEL */
506 ApicSetCurrentIrql(APC_LEVEL);
507
508 /* End the interrupt */
509 ApicSendEOI();
510
511 /* Kernel or user APC? */
512 if (KiUserTrap(TrapFrame)) ProcessorMode = UserMode;
513 else if (TrapFrame->EFlags & EFLAGS_V86_MASK) ProcessorMode = UserMode;
514 else ProcessorMode = KernelMode;
515
516 /* Enable interrupts and call the kernel's APC interrupt handler */
517 _enable();
518 KiDeliverApc(ProcessorMode, NULL, TrapFrame);
519
520 /* Disable interrupts */
521 _disable();
522
523 /* Restore the old IRQL */
524 ApicSetCurrentIrql(OldIrql);
525
526 /* Exit the interrupt */
527 KiEoiHelper(TrapFrame);
528 }
529
530 #ifndef _M_AMD64
531 VOID
532 DECLSPEC_NORETURN
533 FASTCALL
534 HalpDispatchInterruptHandler(IN PKTRAP_FRAME TrapFrame)
535 {
536 KIRQL OldIrql;
537 ASSERT(ApicGetCurrentIrql() < DISPATCH_LEVEL);
538 ASSERT(ApicGetProcessorIrql() == DISPATCH_LEVEL);
539
540 /* Enter trap */
541 KiEnterInterruptTrap(TrapFrame);
542
543 /* Save the old IRQL */
544 OldIrql = ApicGetCurrentIrql();
545
546 /* Raise to DISPATCH_LEVEL */
547 ApicSetCurrentIrql(DISPATCH_LEVEL);
548
549 /* End the interrupt */
550 ApicSendEOI();
551
552 /* Enable interrupts and call the kernel's DPC interrupt handler */
553 _enable();
554 KiDispatchInterrupt();
555 _disable();
556
557 /* Restore the old IRQL */
558 ApicSetCurrentIrql(OldIrql);
559
560 /* Exit the interrupt */
561 KiEoiHelper(TrapFrame);
562 }
563 #endif
564
565 VOID
566 NTAPI
567 HalpSendEOI(VOID)
568 {
569 ApicSendEOI();
570 }
571
572 /* PUBLIC FUNCTIONS ***********************************************************/
573
574 VOID
575 FASTCALL
576 HalRequestSoftwareInterrupt(IN KIRQL Irql)
577 {
578 APIC_COMMAND_REGISTER CommandRegister;
579
580 /* Setup the command register */
581 CommandRegister.Long0 = 0;
582 CommandRegister.Vector = IrqlToTpr(Irql);
583 CommandRegister.MessageType = APIC_MT_Fixed;
584 CommandRegister.TriggerMode = APIC_TGM_Edge;
585 CommandRegister.DestinationShortHand = APIC_DSH_Self;
586
587 /* Write the low dword to send the interrupt */
588 ApicWrite(APIC_ICR0, CommandRegister.Long0);
589 }
590
591 VOID
592 FASTCALL
593 HalClearSoftwareInterrupt(
594 IN KIRQL Irql)
595 {
596 /* Nothing to do */
597 }
598
599 BOOLEAN
600 NTAPI
601 HalEnableSystemInterrupt(
602 IN UCHAR Vector,
603 IN KIRQL Irql,
604 IN KINTERRUPT_MODE InterruptMode)
605 {
606 IOAPIC_REDIRECTION_REGISTER ReDirReg;
607 PKPRCB Prcb = KeGetCurrentPrcb();
608 UCHAR Index;
609 ASSERT(Irql <= HIGH_LEVEL);
610 ASSERT((IrqlToTpr(Irql) & 0xF0) == (Vector & 0xF0));
611
612 /* Get the irq for this vector */
613 Index = HalpVectorToIndex[Vector];
614
615 /* Check if its valid */
616 if (Index == 0xff)
617 {
618 /* Interrupt is not in use */
619 return FALSE;
620 }
621
622 /* Read the redirection entry */
623 ReDirReg = ApicReadIORedirectionEntry(Index);
624
625 /* Check if the interrupt was unused */
626 if (ReDirReg.Vector != Vector)
627 {
628 ReDirReg.Vector = Vector;
629 ReDirReg.DeliveryMode = APIC_MT_LowestPriority;
630 ReDirReg.DestinationMode = APIC_DM_Logical;
631 ReDirReg.Destination = 0;
632 ReDirReg.TriggerMode = 1 - InterruptMode;
633 }
634
635 /* Check if the destination is logical */
636 if (ReDirReg.DestinationMode = APIC_DM_Logical)
637 {
638 /* Set the bit for this cpu */
639 ReDirReg.Destination |= ApicLogicalId(Prcb->Number);
640 }
641
642 /* Now unmask it */
643 ReDirReg.Mask = FALSE;
644
645 /* Write back the entry */
646 ApicWriteIORedirectionEntry(Index, ReDirReg);
647
648 return TRUE;
649 }
650
651 VOID
652 NTAPI
653 HalDisableSystemInterrupt(
654 IN UCHAR Vector,
655 IN KIRQL Irql)
656 {
657 IOAPIC_REDIRECTION_REGISTER ReDirReg;
658 UCHAR Index;
659 ASSERT(Irql <= HIGH_LEVEL);
660
661 Index = HalpVectorToIndex[Vector];
662
663 /* Read lower dword of redirection entry */
664 ReDirReg.Long0 = IOApicRead(IOAPIC_REDTBL + 2 * Index);
665
666 /* Mask it */
667 ReDirReg.Mask = 1;
668
669 /* Write back lower dword */
670 IOApicWrite(IOAPIC_REDTBL + 2 * Irql, ReDirReg.Long0);
671 }
672
673 #ifndef _M_AMD64
674 BOOLEAN
675 NTAPI
676 HalBeginSystemInterrupt(
677 IN KIRQL Irql,
678 IN UCHAR Vector,
679 OUT PKIRQL OldIrql)
680 {
681 /* Get the current IRQL */
682 *OldIrql = ApicGetCurrentIrql();
683
684 /* Set the new IRQL */
685 ApicSetCurrentIrql(Irql);
686
687 /* Turn on interrupts */
688 _enable();
689
690 /* Success */
691 return TRUE;
692 }
693
694 VOID
695 NTAPI
696 HalEndSystemInterrupt(
697 IN KIRQL OldIrql,
698 IN PKTRAP_FRAME TrapFrame)
699 {
700 /* Send an EOI */
701 ApicSendEOI();
702
703 /* Restore the old IRQL */
704 ApicSetCurrentIrql(OldIrql);
705 }
706
707
708 KIRQL
709 NTAPI
710 KeGetCurrentIrql(VOID)
711 {
712 /* Read the current TPR and convert it to an IRQL */
713 return ApicGetCurrentIrql();
714 }
715
716 VOID
717 FASTCALL
718 KfLowerIrql(
719 IN KIRQL OldIrql)
720 {
721 #if DBG
722 /* Validate correct lower */
723 if (OldIrql > ApicGetCurrentIrql())
724 {
725 /* Crash system */
726 KeBugCheck(IRQL_NOT_LESS_OR_EQUAL);
727 }
728 #endif
729 /* Convert the new IRQL to a TPR value and write the register */
730 ApicSetCurrentIrql(OldIrql);
731 }
732
733 KIRQL
734 FASTCALL
735 KfRaiseIrql(
736 IN KIRQL NewIrql)
737 {
738 KIRQL OldIrql;
739
740 /* Read the current IRQL */
741 OldIrql = ApicGetCurrentIrql();
742 #if DBG
743 /* Validate correct raise */
744 if (OldIrql > NewIrql)
745 {
746 /* Crash system */
747 KeBugCheck(IRQL_NOT_GREATER_OR_EQUAL);
748 }
749 #endif
750 /* Convert the new IRQL to a TPR value and write the register */
751 ApicSetCurrentIrql(NewIrql);
752
753 /* Return old IRQL */
754 return OldIrql;
755 }
756
757 KIRQL
758 NTAPI
759 KeRaiseIrqlToDpcLevel(VOID)
760 {
761 return KfRaiseIrql(DISPATCH_LEVEL);
762 }
763
764 KIRQL
765 NTAPI
766 KeRaiseIrqlToSynchLevel(VOID)
767 {
768 return KfRaiseIrql(SYNCH_LEVEL);
769 }
770
771 #endif /* !_M_AMD64 */
772