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