ReactOS 0.4.17-dev-1190-g4c812f4
apic.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS HAL
3 * LICENSE: GNU GPL - See COPYING in the top level directory
4 * FILE: hal/halx86/apic/apic.c
5 * PURPOSE: HAL APIC Management and Control Code
6 * PROGRAMMERS: Timo Kreuzer (timo.kreuzer@reactos.org)
7 * REFERENCES: https://web.archive.org/web/20190407074221/http://www.joseflores.com/docs/ExploringIrql.html
8 * https://www.codeproject.com/KB/system/soviet_kernel_hack.aspx
9 * http://bbs.unixmap.net/thread-2022-1-1.html (DEAD_LINK)
10 * https://codemachine.com/articles/interrupt_dispatching.html
11 * https://www.osronline.com/article.cfm%5Earticle=211.htm
12 */
13
14/* INCLUDES *******************************************************************/
15
16#include <hal.h>
17#include "apicp.h"
18#include <smp.h>
19#define NDEBUG
20#include <debug.h>
21
22#ifndef _M_AMD64
23#define APIC_LAZY_IRQL
24#endif
25
26/* GLOBALS ********************************************************************/
27
29
30/* Always updated together. */
33
35
36typedef struct _HALP_IOAPIC_UNIT
37{
42
43/* I/O APICs in use, the first one is mapped at IOAPIC_BASE */
46
47/* One past the highest input served by an I/O APIC */
49
50/*
51 * Last value written to each redirection entry
52 * This is done for a few reasons but the biggest benefit
53 * is preperation for ACPI Sleep. Which we need to cache the last
54 * known state to restore. IOAPIC data lost during ACPI Sleep!
55 */
57
58#ifndef _M_AMD64
59const UCHAR
61{
62 0x00, /* 0 PASSIVE_LEVEL */
63 0x3d, /* 1 APC_LEVEL */
64 0x41, /* 2 DISPATCH_LEVEL */
65 0x41, /* 3 \ */
66 0x51, /* 4 \ */
67 0x61, /* 5 | */
68 0x71, /* 6 | */
69 0x81, /* 7 | */
70 0x91, /* 8 | */
71 0xa1, /* 9 | */
72 0xb1, /* 10 | */
73 0xb1, /* 11 | */
74 0xb1, /* 12 | */
75 0xb1, /* 13 | */
76 0xb1, /* 14 | */
77 0xb1, /* 15 DEVICE IRQL */
78 0xb1, /* 16 | */
79 0xb1, /* 17 | */
80 0xb1, /* 18 | */
81 0xb1, /* 19 | */
82 0xb1, /* 20 | */
83 0xb1, /* 21 | */
84 0xb1, /* 22 | */
85 0xb1, /* 23 | */
86 0xb1, /* 24 | */
87 0xb1, /* 25 / */
88 0xb1, /* 26 / */
89 0xc1, /* 27 PROFILE_LEVEL */
90 0xd1, /* 28 CLOCK2_LEVEL */
91 0xe1, /* 29 IPI_LEVEL */
92 0xef, /* 30 POWER_LEVEL */
93 0xff, /* 31 HIGH_LEVEL */
94};
95
96const KIRQL
98{
99 0, /* 00 PASSIVE_LEVEL */
100 0xff, /* 10 */
101 0xff, /* 20 */
102 1, /* 3D APC_LEVEL */
103 2, /* 41 DISPATCH_LEVEL */
104 4, /* 50 \ */
105 5, /* 60 \ */
106 6, /* 70 | */
107 7, /* 80 DEVICE IRQL */
108 8, /* 90 | */
109 9, /* A0 / */
110 10, /* B0 / */
111 27, /* C1 PROFILE_LEVEL */
112 28, /* D1 CLOCK2_LEVEL */
113 29, /* E1 IPI_LEVEL / EF POWER_LEVEL */
114 31, /* FF HIGH_LEVEL */
115};
116#endif
117
118/* PRIVATE FUNCTIONS **********************************************************/
119
121ULONG
125{
126 /* Select the register, then do the read */
129}
130
132VOID
137{
138 /* Select the register, then do the write */
141}
142
161{
162 ULONG Index;
163
164 for (Index = 0; Index < HalpIoApicCount; Index++)
165 {
166 if ((Input >= HalpIoApics[Index].InputBase) &&
167 (Input - HalpIoApics[Index].InputBase < HalpIoApics[Index].InputCount))
168 {
170 return TRUE;
171 }
172 }
173
174 return FALSE;
175}
176
186VOID
190{
193
195 {
196 ASSERT(FALSE);
197 return;
198 }
199
200 HalpIoApicShadow[Input] = ReDirReg;
201
202 /* The destination has to be in place before the low half unmasks the
203 entry, so that an asserted input cannot reach a stale processor */
204 Register = (UCHAR)(IOAPIC_REDTBL + 2 * (Input - Unit->InputBase));
205 IOApicWrite(Unit->Base, Register + 1, ReDirReg.Long1);
206 IOApicWrite(Unit->Base, Register, ReDirReg.Long0);
207}
208
218{
220 return HalpIoApicShadow[Input];
221}
222
224VOID
226{
227 ULONG Flags;
230
231 /*
232 * The IRR registers are spaced 16 bytes apart and hold 32 status bits each.
233 * Pre-compute the register and bit that match our vector.
234 */
235 ULONG VectorHigh = Vector / 32;
236 ULONG VectorLow = Vector % 32;
237 ULONG Irr = APIC_IRR + 0x10 * VectorHigh;
238 ULONG IrrBit = 1UL << VectorLow;
239
240 /* Setup the command register */
241 Icr.LongLong = 0;
242 Icr.Vector = Vector;
244 Icr.TriggerMode = TriggerMode;
246
247 /* Disable interrupts so that we can change IRR without being interrupted */
249 _disable();
250
251 /* Wait for the APIC to be idle */
252 do
253 {
254 IcrStatus.Long0 = ApicRead(APIC_ICR0);
255 } while (IcrStatus.DeliveryStatus);
256
257 /* Write high dword first, then low dword to send the interrupt */
260
261 /* Wait until we see the interrupt request.
262 * It will stay in requested state until we re-enable interrupts.
263 */
264 while (!(ApicRead(Irr) & IrrBit))
265 {
267 }
268
269 /* Finally, restore the original interrupt state */
271 {
272 _enable();
273 }
274}
275
277VOID
279{
281}
282
284KIRQL
286{
287 /* Read the TPR and convert it to an IRQL */
288 return TprToIrql(ApicRead(APIC_PPR));
289}
290
292KIRQL
294{
295#ifdef _M_AMD64
296 return (KIRQL)__readcr8();
297#elif defined(APIC_LAZY_IRQL)
298 /* Return the field in the PCR */
300#else
301 /* Read the TPR and convert it to an IRQL */
302 return TprToIrql(ApicRead(APIC_TPR));
303#endif
304}
305
307VOID
309{
310#ifdef _M_AMD64
311 __writecr8(Irql);
312#elif defined(APIC_LAZY_IRQL)
314#else
315 /* Convert IRQL and write the TPR */
317#endif
318}
319#define ApicRaiseIrql ApicSetIrql
320
321#ifdef APIC_LAZY_IRQL
323VOID
325{
327
328 /* Is the new Irql lower than set in the TPR? */
329 if (Irql < KeGetPcr()->IRR)
330 {
331 /* Save the new hard IRQL in the IRR field */
332 KeGetPcr()->IRR = Irql;
333
334 /* Need to lower it back */
336 }
337}
338#else
339#define ApicLowerIrql ApicSetIrql
340#endif
341
342UCHAR
345 _In_ UCHAR Irq)
346{
347 /* Firmware can leave a vector in an entry, so use the allocation table */
348 return HalpGsivToVector[Irq];
349}
350
351KIRQL
354{
355 return TprToIrql(Vector);
356}
357
358UCHAR
361{
363}
364
365VOID
366NTAPI
368{
369 ApicSendEOI();
370}
371
372VOID
373NTAPI
375 _In_ ULONG Cpu)
376{
377 APIC_BASE_ADDRESS_REGISTER BaseRegister;
379 APIC_VERSION_REGISTER VersionRegister;
380 APIC_EXTENDED_FEATURE_REGISTER FeatureRegister;
381 LVT_REGISTER LvtEntry;
382 ULONG Index;
383
384 /* Enable the APIC if it wasn't yet */
385 BaseRegister.LongLong = __readmsr(MSR_APIC_BASE);
386 BaseRegister.Enable = 1;
387 BaseRegister.BootStrapCPUCore = (Cpu == 0);
388 __writemsr(MSR_APIC_BASE, BaseRegister.LongLong);
389
390 /* Set spurious vector and SoftwareEnable to 1 */
391 SpIntRegister.Long = ApicRead(APIC_SIVR);
392 SpIntRegister.Vector = APIC_SPURIOUS_VECTOR;
393 SpIntRegister.SoftwareEnable = 1;
394 SpIntRegister.FocusCPUCoreChecking = 0;
395 ApicWrite(APIC_SIVR, SpIntRegister.Long);
396
397 /* Read the version and save it globally */
398 if (Cpu == 0) ApicVersion = ApicRead(APIC_VER);
399
400 /* Set the mode to flat (max 8 CPUs supported!) */
402
403 /* Set logical apic ID */
404 ApicWrite(APIC_LDR, ApicLogicalId(Cpu) << 24);
405
406 /* Set the spurious ISR */
408
409 /* Create a template LVT */
410 LvtEntry.Long = 0;
411 LvtEntry.Vector = APIC_FREE_VECTOR;
412 LvtEntry.MessageType = APIC_MT_Fixed;
413 LvtEntry.DeliveryStatus = 0;
414 LvtEntry.RemoteIRR = 0;
415 LvtEntry.TriggerMode = APIC_TGM_Edge;
416 LvtEntry.Mask = 1;
417 LvtEntry.TimerMode = 0;
418
419 /* Initialize and mask LVTs. Accessing one this APIC lacks is an illegal register error */
420 VersionRegister.Long = ApicRead(APIC_VER);
421 ApicWrite(APIC_TMRLVTR, LvtEntry.Long);
422
423 /* The performance counter LVT came with 5 LVT entries, the thermal LVT with 6 */
424 if (VersionRegister.MaxLVT >= 4)
425 {
426 ApicWrite(APIC_PCLVTR, LvtEntry.Long);
427 }
428 if (VersionRegister.MaxLVT >= 5)
429 {
430 ApicWrite(APIC_THRMLVTR, LvtEntry.Long);
431 }
432
433 /* AMD extended LVTs reset unmasked */
434 if (VersionRegister.ExtRegSpacePresent)
435 {
436 FeatureRegister.Long = ApicRead(APIC_EAFR);
437 for (Index = 0; Index < min(FeatureRegister.ExtLvtCount, 4); Index++)
438 {
439 ApicWrite((APIC_REGISTER)(APIC_EXT0LVTR + Index * 0x10), LvtEntry.Long);
440 }
441 }
442
443 /* LINT0 */
444 LvtEntry.Vector = APIC_SPURIOUS_VECTOR;
445 LvtEntry.MessageType = APIC_MT_ExtInt;
446 ApicWrite(APIC_LINT0, LvtEntry.Long);
447
448 /* Enable LINT1 (NMI) */
449 LvtEntry.Mask = 0;
450 LvtEntry.Vector = APIC_NMI_VECTOR;
451 LvtEntry.MessageType = APIC_MT_NMI;
452 LvtEntry.TriggerMode = APIC_TGM_Level;
453 ApicWrite(APIC_LINT1, LvtEntry.Long);
454
455 /* Clear any error from the writes above */
457
458 /* Enable error LVTR */
460 LvtEntry.Vector = APIC_ERROR_VECTOR;
461 LvtEntry.MessageType = APIC_MT_Fixed;
462 ApicWrite(APIC_ERRLVTR, LvtEntry.Long);
463
464 /* Set the IRQL from the PCR */
466#ifdef APIC_LAZY_IRQL
467 /* Save the new hard IRQL in the IRR field */
468 KeGetPcr()->IRR = KeGetPcr()->Irql;
469#endif
470}
471
472UCHAR
473NTAPI
475 _In_ UCHAR Irq,
477{
479
480 ASSERT(Irq < HalpMaxGsi);
482
483 /* Setup a redirection entry */
484 ReDirReg.Vector = Vector;
487 ReDirReg.DeliveryStatus = 0;
488 ReDirReg.Polarity = 0;
489 ReDirReg.RemoteIRR = 0;
490 ReDirReg.TriggerMode = APIC_TGM_Edge;
491 ReDirReg.Mask = 1;
492 ReDirReg.Reserved = 0;
493 ReDirReg.Destination = ApicRead(APIC_ID) >> 24;
494
495 /* Initialize entry */
496 ApicWriteIORedirectionEntry(Irq, ReDirReg);
497
498 /* Record the allocation in both tables */
501
502 return Vector;
503}
504
505ULONG
506NTAPI
510 _Out_ PKIRQL OutIrql,
511 _Out_ PKAFFINITY OutAffinity)
512{
515 KIRQL Irql;
516
517 /* Resources that already hold a system vector are translated here too, so stay quiet */
519 {
520 DPRINT("No I/O APIC serves input %lu\n", BusInterruptLevel);
521 *OutAffinity = 0;
522 *OutIrql = 0;
523 return 0;
524 }
525
526 /* Get the vector currently registered */
528
529 /* Check if it's used */
531 {
532 /* Calculate IRQL */
534 *OutIrql = HalpVectorToIrql(Vector);
535 }
536 else
537 {
539
540 /* Outer loop to find alternative slots, when all IRQLs are in use */
541 for (Offset = 0; Offset < 15; Offset++)
542 {
543 /* Loop allowed IRQL range */
544 for (Irql = CLOCK_LEVEL - 1; Irql >= CMCI_LEVEL; Irql--)
545 {
546 /* Calculate the vactor */
548
549 /* Check if the vector is free */
551 {
552 /* Found one, allocate the interrupt */
554 *OutIrql = Irql;
555 goto Exit;
556 }
557 }
558 }
559
560 DPRINT1("Failed to get an interrupt vector for IRQ %lu\n", BusInterruptLevel);
561 *OutAffinity = 0;
562 *OutIrql = 0;
563 return 0;
564 }
565
566Exit:
567
568 *OutAffinity = HalpDefaultInterruptAffinity;
570
571 return Vector;
572}
573
584static
585VOID
586NTAPI
588 _In_ ULONG PhysicalBase,
589 _In_ ULONG InputBase)
590{
592 PHARDWARE_PTE Pte;
594
595 if ((HalpIoApicCount == HALP_MAX_IOAPICS) || (InputBase >= HALP_MAX_INPUTS))
596 {
597 DPRINT1("I/O APIC at 0x%lx with input base %lu ignored\n", PhysicalBase, InputBase);
598 return;
599 }
600
601 /* Each I/O APIC takes the next page from IOAPIC_BASE */
604 Pte = HalAddressToPte(Unit->Base);
605 Pte->PageFrameNumber = PhysicalBase / PAGE_SIZE;
606 Pte->Valid = 1;
607 Pte->Write = 1;
608 Pte->Owner = 1;
609 Pte->CacheDisable = 1;
610 Pte->Global = 1;
612 Unit->Base += BYTE_OFFSET(PhysicalBase);
613
614 /* Nothing decodes the address when all bits read back set */
616 if (Version == 0xFFFFFFFF)
617 {
618 DPRINT1("No I/O APIC responds at 0x%lx\n", PhysicalBase);
619 return;
620 }
621
622 /* Bits 23:16 hold the index of the last redirection entry, the register index caps the count */
623 Unit->InputBase = InputBase;
624 Unit->InputCount = min(((Version >> 16) & 0xFF) + 1, HALP_IOAPIC_MAX_ENTRIES);
625 Unit->InputCount = min(Unit->InputCount, HALP_MAX_INPUTS - InputBase);
626 HalpMaxGsi = max(HalpMaxGsi, InputBase + Unit->InputCount);
628}
629
630VOID
631NTAPI
633{
635 IOAPIC_REDIRECTION_REGISTER ReDirReg, Current;
638
639 /* Use the I/O APICs from the MADT, or the default one without it */
641 {
643 {
646 }
647 }
648 if (HalpIoApicCount == 0)
649 {
651 }
652
653 /* Setup a redirection entry */
654 ReDirReg.LongLong = 0;
655 ReDirReg.Vector = APIC_FREE_VECTOR;
656 ReDirReg.MessageType = APIC_MT_Fixed;
658 ReDirReg.TriggerMode = APIC_TGM_Edge;
659 ReDirReg.Mask = 1;
660 ReDirReg.Destination = ApicRead(APIC_ID) >> 24;
661
662 /* Initialize all entries of all I/O APICs */
664 {
665 for (Input = Unit->InputBase; Input < Unit->InputBase + Unit->InputCount; Input++)
666 {
667 /* Entries the firmware routes to SMI stay as they are */
668 Register = (UCHAR)(IOAPIC_REDTBL + 2 * (Input - Unit->InputBase));
669 Current.Long0 = IOApicRead(Unit->Base, Register);
670 if (Current.MessageType == APIC_MT_SMI)
671 {
672 Current.Long1 = IOApicRead(Unit->Base, Register + 1);
673 HalpIoApicShadow[Input] = Current;
674 continue;
675 }
676
678 }
679 }
680
681 /* Init the vector and input tables */
682 for (Vector = 0; Vector <= 255; Vector++)
683 {
686 }
687
688 /* Enable the timer interrupt (but keep it masked) */
689 ReDirReg.Vector = APIC_CLOCK_VECTOR;
690 ReDirReg.MessageType = APIC_MT_Fixed;
692 ReDirReg.TriggerMode = APIC_TGM_Level;
693 ReDirReg.Mask = 1;
694 ReDirReg.Destination = ApicRead(APIC_ID) >> 24;
696}
697
698VOID
699NTAPI
702{
703 ULONG_PTR EFlags;
704
705 /* Save EFlags and disable interrupts */
706 EFlags = __readeflags();
707 _disable();
708
709 /* Initialize and mask the PIC */
711
712 /* Initialize the I/O APIC */
714
715 /* Manually reserve some vectors */
722
723 /* Local APIC sources, all above the device vector range */
728
729 /* Set interrupt handlers in the IDT */
732#ifndef _M_AMD64
735#endif
736
737 /* Register the vectors for APC and dispatch interrupts */
740
741 /* Restore interrupt state */
743 __writeeflags(EFlags);
744}
745
746
747/* SOFTWARE INTERRUPT TRAPS ***************************************************/
748
749#ifndef _M_AMD64
750VOID
754{
755 KPROCESSOR_MODE ProcessorMode;
758
759 /* Enter trap */
760 KiEnterInterruptTrap(TrapFrame);
761
762#ifdef APIC_LAZY_IRQL
764 {
765 /* "Spurious" interrupt, exit the interrupt */
766 KiEoiHelper(TrapFrame);
767 }
768#else
769 /* Save the old IRQL */
772#endif
773
774 /* Raise to APC_LEVEL */
776
777 /* End the interrupt */
778 ApicSendEOI();
779
780 /* Kernel or user APC? */
781 if (KiUserTrap(TrapFrame)) ProcessorMode = UserMode;
782 else if (TrapFrame->EFlags & EFLAGS_V86_MASK) ProcessorMode = UserMode;
783 else ProcessorMode = KernelMode;
784
785 /* Enable interrupts and call the kernel's APC interrupt handler */
786 _enable();
787 KiDeliverApc(ProcessorMode, NULL, TrapFrame);
788
789 /* Disable interrupts */
790 _disable();
791
792 /* Restore the old IRQL */
794
795 /* Exit the interrupt */
796 KiEoiHelper(TrapFrame);
797}
798
799VOID
803{
806
807 /* Enter trap */
808 KiEnterInterruptTrap(TrapFrame);
809
810#ifdef APIC_LAZY_IRQL
812 {
813 /* "Spurious" interrupt, exit the interrupt */
814 KiEoiHelper(TrapFrame);
815 }
816#else
817 /* Get the current IRQL */
820#endif
821
822 /* Raise to DISPATCH_LEVEL */
824
825 /* End the interrupt */
826 ApicSendEOI();
827
828 /* Enable interrupts and call the kernel's DPC interrupt handler */
829 _enable();
831 _disable();
832
833 /* Restore the old IRQL */
835
836 /* Exit the interrupt */
837 KiEoiHelper(TrapFrame);
838}
839#endif
840
841
842/* SOFTWARE INTERRUPTS ********************************************************/
843
844
845VOID
848{
849 /* Convert irql to vector and request an interrupt */
851}
852
853VOID
856 IN KIRQL Irql)
857{
858 /* Nothing to do */
859}
860
861
862/* SYSTEM INTERRUPTS **********************************************************/
863
881static
883NTAPI
888{
891
892 *Input = 0;
893 *Polarity = InterruptPolarityUnknown;
894
896 return STATUS_NOT_FOUND;
897
900 {
901 DPRINT1("No I/O APIC serves input %lu of vector 0x%lx\n", *Input, Vector);
902 return STATUS_NOT_FOUND;
903 }
904
905 return Status;
906}
907
925static
927NTAPI
931 _In_ KINTERRUPT_POLARITY Reported)
932{
933 ULONG Irq;
934
935 if (Reported != InterruptPolarityUnknown)
936 return Reported;
937
938 for (Irq = 0; Irq < HALP_ISA_IRQ_COUNT; Irq++)
939 {
942 {
944 }
945 }
946
947 /* PCI lines are level and active low, ISA lines are edge and active high */
949}
950
952NTAPI
957{
959 KINTERRUPT_POLARITY Polarity;
961 ULONG Input;
962 UCHAR Index;
964 ASSERT((IrqlToTpr(Irql) & 0xF0) == (Vector & 0xF0));
965
966 /* Get the irq for this vector */
968
969 /* Message-signaled interrupts have no input to unmask */
970 if (Index == APIC_MSI_VECTOR)
971 {
972 return TRUE;
973 }
974
975 /* The ACPI driver allocates vectors itself when it arbitrates interrupts */
976 Polarity = InterruptPolarityUnknown;
977 if (Index == APIC_FREE_VECTOR)
978 {
979 Status = HalpQueryVectorInput(Vector, &Input, &Polarity);
981 {
983 return TRUE;
984 }
985
986 /* Don't take over an input that belongs to another vector */
988 {
989 DPRINT1("No free input for vector 0x%lx, status 0x%lx\n", Vector, Status);
990 return FALSE;
991 }
992
994 Index = (UCHAR)Input;
995 }
996
997 /* Check if its valid */
998 if (Index >= HalpMaxGsi)
999 {
1000 /* Interrupt is not in use */
1001 return FALSE;
1002 }
1003
1004 /* Read the redirection entry */
1006
1007 /* Check if the interrupt is already enabled */
1008 if (ReDirReg.Mask == FALSE)
1009 {
1010 /* If the vector matches, there is nothing more to do,
1011 otherwise something is wrong. */
1012 return (ReDirReg.Vector == Vector);
1013 }
1014
1015 /* Set up the redirection entry */
1016 ReDirReg.Vector = Vector;
1017 ReDirReg.MessageType = APIC_MT_Fixed;
1019 ReDirReg.Destination = ApicRead(APIC_ID) >> 24;
1020 ReDirReg.TriggerMode = (InterruptMode == LevelSensitive) ?
1022 ReDirReg.Polarity =
1024 ReDirReg.Mask = FALSE;
1025
1026 /* Write back the entry */
1028
1029 return TRUE;
1030}
1031
1032VOID
1033NTAPI
1036 _In_ KIRQL Irql)
1037{
1039 UCHAR Index;
1042
1044
1045 /* Message-signaled and reserved vectors have no entry to mask */
1046 if (Index >= HalpMaxGsi)
1047 return;
1048
1049 /* Mask the redirection entry */
1051 ReDirReg.Mask = 1;
1053}
1054
1055BOOLEAN
1056NTAPI
1058 _In_ KIRQL Irql,
1061{
1062 KIRQL CurrentIrql;
1063
1064 /* Get the current IRQL */
1065 CurrentIrql = ApicGetCurrentIrql();
1066
1067#ifdef APIC_LAZY_IRQL
1068 /* Check if this interrupt is allowed */
1069 if (CurrentIrql >= Irql)
1070 {
1072 UCHAR Index;
1073
1074 /* It is not, set the real Irql in the TPR! */
1075 ApicWrite(APIC_TPR, IrqlToTpr(CurrentIrql));
1076
1077 /* Save the new hard IRQL in the IRR field */
1078 KeGetPcr()->IRR = CurrentIrql;
1079
1080 /* End this interrupt */
1081 ApicSendEOI();
1082
1083 /* Get the irq for this vector */
1085
1086 /* Check if it's valid */
1087 if (Index < HalpMaxGsi)
1088 {
1089 /* Read the I/O redirection entry */
1091
1092 /* Re-request the interrupt to be handled later */
1094 }
1095 else
1096 {
1097 /* This should be a reserved or message-signaled vector! */
1099
1100 /* Re-request the interrupt to be handled later */
1102 }
1103
1104 /* Pretend it was a spurious interrupt */
1105 return FALSE;
1106 }
1107#endif
1108 /* Save the current IRQL */
1109 *OldIrql = CurrentIrql;
1110
1111 /* Set the new IRQL */
1113
1114 /* Turn on interrupts */
1115 _enable();
1116
1117 /* Success */
1118 return TRUE;
1119}
1120
1121VOID
1122NTAPI
1125 IN PKTRAP_FRAME TrapFrame)
1126{
1127 /* Send an EOI */
1128 ApicSendEOI();
1129
1130 /* Restore the old IRQL */
1132}
1133
1134
1135/* IRQL MANAGEMENT ************************************************************/
1136
1137#ifndef _M_AMD64
1138KIRQL
1139NTAPI
1141{
1142 /* Read the current TPR and convert it to an IRQL */
1143 return ApicGetCurrentIrql();
1144}
1145
1146VOID
1150{
1151#if DBG
1152 /* Validate correct lower */
1154 {
1155 /* Crash system */
1156 KeBugCheck(IRQL_NOT_LESS_OR_EQUAL);
1157 }
1158#endif
1159 /* Set the new IRQL */
1161}
1162
1163KIRQL
1167{
1168 KIRQL OldIrql;
1169
1170 /* Read the current IRQL */
1172#if DBG
1173 /* Validate correct raise */
1174 if (OldIrql > NewIrql)
1175 {
1176 /* Crash system */
1177 KeBugCheck(IRQL_NOT_GREATER_OR_EQUAL);
1178 }
1179#endif
1180 /* Convert the new IRQL to a TPR value and write the register */
1182
1183 /* Return old IRQL */
1184 return OldIrql;
1185}
1186
1187KIRQL
1188NTAPI
1190{
1192}
1193
1194KIRQL
1195NTAPI
1197{
1198 return KfRaiseIrql(SYNCH_LEVEL);
1199}
1200
1201#endif /* !_M_AMD64 */
1202
#define EFLAGS_INTERRUPT_MASK
#define RTL_NUMBER_OF(x)
Definition: RtlRegistry.c:12
unsigned char BOOLEAN
Definition: actypes.h:127
static VOID NTAPI HalpMapIoApic(_In_ ULONG PhysicalBase, _In_ ULONG InputBase)
Maps an I/O APIC and adds it to the units in use.
Definition: apic.c:587
VOID NTAPI ApicInitializeLocalApic(_In_ ULONG Cpu)
Definition: apic.c:374
static NTSTATUS NTAPI HalpQueryVectorInput(_In_ ULONG Vector, _Out_ PULONG Input, _Out_ PKINTERRUPT_POLARITY Polarity)
Asks the ACPI driver for the input of a vector it allocated.
Definition: apic.c:884
VOID DECLSPEC_NORETURN FASTCALL HalpApcInterruptHandler(IN PKTRAP_FRAME TrapFrame)
Definition: apic.c:753
ULONG HalpMaxGsi
Definition: apic.c:48
const KIRQL HalVectorToIRQL[16]
Definition: apic.c:97
VOID NTAPI HalDisableSystemInterrupt(_In_ ULONG Vector, _In_ KIRQL Irql)
Definition: apic.c:1034
VOID FASTCALL KfLowerIrql(IN KIRQL OldIrql)
Definition: apic.c:1148
BOOLEAN NTAPI HalEnableSystemInterrupt(_In_ ULONG Vector, _In_ KIRQL Irql, _In_ KINTERRUPT_MODE InterruptMode)
Definition: apic.c:953
ULONG ApicVersion
Definition: apic.c:28
VOID NTAPI HalEndSystemInterrupt(IN KIRQL OldIrql, IN PKTRAP_FRAME TrapFrame)
Definition: apic.c:1123
#define ApicRaiseIrql
Definition: apic.c:319
FORCEINLINE VOID IOApicWrite(_In_ ULONG_PTR Base, _In_ UCHAR Register, _In_ ULONG Value)
Definition: apic.c:133
UCHAR HalpVectorToIndex[256]
Definition: apic.c:31
FORCEINLINE VOID ApicSetIrql(KIRQL Irql)
Definition: apic.c:308
UCHAR FASTCALL HalpIrqToVector(_In_ UCHAR Irq)
Definition: apic.c:344
KIRQL FASTCALL HalpVectorToIrql(UCHAR Vector)
Definition: apic.c:353
VOID NTAPI ApicInitializeIOApic(VOID)
Definition: apic.c:632
FORCEINLINE VOID ApicWriteIORedirectionEntry(_In_ ULONG Input, _In_ IOAPIC_REDIRECTION_REGISTER ReDirReg)
Programs a redirection entry and records it in the shadow table.
Definition: apic.c:187
UCHAR NTAPI HalpAllocateSystemInterrupt(_In_ UCHAR Irq, _In_ UCHAR Vector)
Definition: apic.c:474
ULONG HalpIoApicCount
Definition: apic.c:45
struct _HALP_IOAPIC_UNIT HALP_IOAPIC_UNIT
BOOLEAN NTAPI HalBeginSystemInterrupt(_In_ KIRQL Irql, _In_ ULONG Vector, _Out_ PKIRQL OldIrql)
Definition: apic.c:1057
FORCEINLINE VOID ApicLowerIrql(KIRQL Irql)
Definition: apic.c:324
FORCEINLINE VOID ApicRequestSelfInterrupt(IN UCHAR Vector, UCHAR TriggerMode)
Definition: apic.c:225
VOID DECLSPEC_NORETURN FASTCALL HalpDispatchInterruptHandler(IN PKTRAP_FRAME TrapFrame)
Definition: apic.c:802
UCHAR FASTCALL HalpVectorToIrq(UCHAR Vector)
Definition: apic.c:360
HALP_APIC_INFO_TABLE HalpApicInfoTable
Definition: misc.c:19
FORCEINLINE VOID ApicSendEOI(void)
Definition: apic.c:278
static KINTERRUPT_POLARITY NTAPI HalpGetInputPolarity(_In_ ULONG Input, _In_ KINTERRUPT_MODE Mode, _In_ KINTERRUPT_POLARITY Reported)
Picks the polarity to program for an input.
Definition: apic.c:928
FORCEINLINE KIRQL ApicGetProcessorIrql(VOID)
Definition: apic.c:285
ULONG NTAPI HalpGetRootInterruptVector(_In_ ULONG BusInterruptLevel, _In_ ULONG BusInterruptVector, _Out_ PKIRQL OutIrql, _Out_ PKAFFINITY OutAffinity)
Definition: apic.c:507
IOAPIC_REDIRECTION_REGISTER HalpIoApicShadow[HALP_MAX_INPUTS]
Definition: apic.c:56
UCHAR HalpGsivToVector[256]
Definition: apic.c:32
HALP_IOAPIC_UNIT HalpIoApics[HALP_MAX_IOAPICS]
Definition: apic.c:44
VOID FASTCALL HalRequestSoftwareInterrupt(IN KIRQL Irql)
Definition: apic.c:847
VOID NTAPI HalpInitializePICs(_In_ BOOLEAN EnableInterrupts)
Definition: apic.c:700
FORCEINLINE IOAPIC_REDIRECTION_REGISTER ApicReadIORedirectionEntry(_In_ ULONG Input)
Returns a redirection entry from the shadow table, without accessing the I/O APIC.
Definition: apic.c:216
VOID NTAPI HalpSendEOI(VOID)
Definition: apic.c:367
struct _HALP_IOAPIC_UNIT * PHALP_IOAPIC_UNIT
const UCHAR HalpIRQLtoTPR[32]
Definition: apic.c:60
FORCEINLINE ULONG IOApicRead(_In_ ULONG_PTR Base, _In_ UCHAR Register)
Definition: apic.c:122
KIRQL FASTCALL KfRaiseIrql(IN KIRQL NewIrql)
Definition: apic.c:1165
VOID FASTCALL HalClearSoftwareInterrupt(IN KIRQL Irql)
Definition: apic.c:855
FORCEINLINE KIRQL ApicGetCurrentIrql(VOID)
Definition: apic.c:293
FORCEINLINE BOOLEAN HalpFindIoApicInput(_In_ ULONG Input, _Out_ PHALP_IOAPIC_UNIT *Unit)
Finds the I/O APIC that serves an input.
Definition: apic.c:158
KIRQL NTAPI KeRaiseIrqlToSynchLevel(VOID)
Definition: apic.c:1196
#define MSR_APIC_BASE
Definition: apicp.h:121
#define CLOCK_IPI_VECTOR
Definition: apicp.h:47
@ APIC_DF_Flat
Definition: apicp.h:168
#define APIC_NMI_VECTOR
Definition: apicp.h:53
@ APIC_DM_Logical
Definition: apicp.h:153
@ APIC_DM_Physical
Definition: apicp.h:152
#define HALP_MAX_IOAPICS
Definition: apicp.h:67
#define APC_VECTOR
Definition: apicp.h:42
@ APIC_DSH_Self
Definition: apicp.h:160
#define IOAPIC_BASE
Definition: apicp.h:38
#define APIC_CLOCK_VECTOR
Definition: apicp.h:45
#define IOAPIC_VER
Definition: apicp.h:307
#define HALP_MAX_INPUTS
Definition: apicp.h:66
#define APIC_FREE_VECTOR
Definition: apicp.h:61
@ APIC_MT_LowestPriority
Definition: apicp.h:133
@ APIC_MT_Fixed
Definition: apicp.h:132
@ APIC_MT_NMI
Definition: apicp.h:136
@ APIC_MT_ExtInt
Definition: apicp.h:139
@ APIC_MT_SMI
Definition: apicp.h:134
#define APIC_IPI_VECTOR
Definition: apicp.h:48
#define APIC_SPURIOUS_VECTOR
Definition: apicp.h:41
#define APIC_ERROR_VECTOR
Definition: apicp.h:49
#define APIC_PROFILE_VECTOR
Definition: apicp.h:51
#define HALP_IOAPIC_MAX_ENTRIES
Definition: apicp.h:68
enum _APIC_REGISTER APIC_REGISTER
#define IOAPIC_REDTBL
Definition: apicp.h:309
#define ApicLogicalId(Cpu)
Definition: apicp.h:124
VOID __cdecl ApicSpuriousService(VOID)
#define DISPATCH_VECTOR
Definition: apicp.h:43
#define APIC_MSI_VECTOR
Definition: apicp.h:63
FORCEINLINE ULONG ApicRead(APIC_REGISTER Register)
Definition: apicp.h:337
#define APIC_CLOCK_INDEX
Definition: apicp.h:123
#define IrqlToTpr(Irql)
Definition: apicp.h:55
#define APIC_RESERVED_VECTOR
Definition: apicp.h:62
VOID __cdecl ApicErrorService(VOID)
FORCEINLINE VOID ApicWrite(APIC_REGISTER Register, ULONG Value)
Definition: apicp.h:344
#define IOAPIC_IOWIN
Definition: apicp.h:303
#define TprToIrql(Tpr)
Definition: apicp.h:57
@ APIC_LINT1
Definition: apicp.h:107
@ APIC_PPR
Definition: apicp.h:91
@ APIC_ICR0
Definition: apicp.h:101
@ APIC_TPR
Definition: apicp.h:89
@ APIC_VER
Definition: apicp.h:88
@ APIC_LDR
Definition: apicp.h:94
@ APIC_ESR
Definition: apicp.h:100
@ APIC_ERRLVTR
Definition: apicp.h:108
@ APIC_IRR
Definition: apicp.h:99
@ APIC_PCLVTR
Definition: apicp.h:105
@ APIC_ICR1
Definition: apicp.h:102
@ APIC_EAFR
Definition: apicp.h:112
@ APIC_THRMLVTR
Definition: apicp.h:104
@ APIC_TMRLVTR
Definition: apicp.h:103
@ APIC_EOI
Definition: apicp.h:92
@ APIC_ID
Definition: apicp.h:87
@ APIC_DFR
Definition: apicp.h:95
@ APIC_LINT0
Definition: apicp.h:106
@ APIC_SIVR
Definition: apicp.h:96
@ APIC_EXT0LVTR
Definition: apicp.h:115
#define IOAPIC_IOREGSEL
Definition: apicp.h:302
#define IrqlToSoftVector(Irql)
Definition: apicp.h:56
@ APIC_TGM_Level
Definition: apicp.h:146
@ APIC_TGM_Edge
Definition: apicp.h:145
#define IOAPIC_PHYS_BASE
Definition: apicp.h:122
VOID NTAPI KiDispatchInterrupt(VOID)
Definition: thrdini.c:305
#define WRITE_REGISTER_ULONG(r, v)
Definition: arm.h:11
#define READ_REGISTER_ULONG(r)
Definition: arm.h:10
LONG NTSTATUS
Definition: precomp.h:26
#define DPRINT1
Definition: precomp.h:8
KAFFINITY * PKAFFINITY
Definition: basetsd.h:189
DECLSPEC_NORETURN VOID NTAPI KeBugCheck(ULONG BugCheckCode)
Definition: bug.c:1434
_Out_ PKIRQL Irql
Definition: csq.h:179
_In_ D3DDDI_VIDEO_PRESENT_TARGET_ID _In_ ULONG _In_ ULONG Flags
Definition: dispmprt.h:245
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:33
#define DECLSPEC_NORETURN
Definition: corecrt.h:131
static NTSTATUS EnableInterrupts(IN PPORT_DEVICE_EXTENSION DeviceExtension, IN UCHAR FlagsToDisable, IN UCHAR FlagsToEnable)
Definition: pnp.c:380
#define ULONG_PTR
Definition: config.h:101
#define SYNCH_LEVEL
Definition: env_spec_w32.h:704
UCHAR KIRQL
Definition: env_spec_w32.h:591
#define HIGH_LEVEL
Definition: env_spec_w32.h:703
#define APC_LEVEL
Definition: env_spec_w32.h:695
#define PAGE_SIZE
Definition: env_spec_w32.h:49
#define KeGetCurrentIrql()
Definition: env_spec_w32.h:706
KIRQL * PKIRQL
Definition: env_spec_w32.h:592
#define DISPATCH_LEVEL
Definition: env_spec_w32.h:696
IN OUT PLONG IN OUT PLONG Addend IN OUT PLONG IN LONG IN OUT PLONG IN LONG Increment KeRaiseIrqlToDpcLevel
Definition: CrNtStubs.h:68
Unit
Definition: gdiplusenums.h:26
Status
Definition: gdiplustypes.h:24
KAFFINITY HalpDefaultInterruptAffinity
Definition: processor.c:18
VOID HalpClockInterrupt(VOID)
Definition: timer.c:30
VOID NTAPI HalpRegisterVector(IN UCHAR Flags, IN ULONG BusVector, IN ULONG SystemVector, IN KIRQL Irql)
Definition: usage.c:34
VOID NTAPI HalpInitializeLegacyPICs(VOID)
Definition: pic.c:18
#define IDT_INTERNAL
Definition: halp.h:21
VOID __cdecl HalpDispatchInterrupt(VOID)
#define HalAddressToPte(x)
Definition: halp.h:187
VOID __cdecl HalpApcInterrupt(VOID)
VOID __cdecl HalpClockIpi(VOID)
_In_ ULONG Mode
Definition: hubbusif.h:303
#define _ReadWriteBarrier()
Definition: intrin_arm.h:36
PPC_QUAL unsigned char __readfsbyte(const unsigned long Offset)
Definition: intrin_ppc.h:360
PPC_QUAL void __writemsr(const unsigned long Value)
Definition: intrin_ppc.h:748
PPC_QUAL unsigned long long __readmsr()
Definition: intrin_ppc.h:741
PPC_QUAL void __writefsbyte(const unsigned long Offset, const unsigned char Data)
Definition: intrin_ppc.h:342
__INTRIN_INLINE void __writeeflags(uintptr_t Value)
Definition: intrin_x86.h:1701
__INTRIN_INLINE uintptr_t __readeflags(void)
Definition: intrin_x86.h:1706
#define ASSERT(a)
Definition: mode.c:44
#define min(a, b)
Definition: monoChain.cc:55
#define EFLAGS_V86_MASK
Definition: ketypes.h:207
#define CMCI_LEVEL
Definition: ketypes.h:15
#define CLOCK_LEVEL
Definition: ketypes.h:16
#define HalGetVectorInputOverride
Definition: halfuncs.h:62
#define KernelMode
Definition: asm.h:38
#define UserMode
Definition: asm.h:39
#define KeGetPcr()
Definition: ketypes.h:81
_In_opt_ ULONG Base
Definition: rtlfuncs.h:2486
#define _Out_
Definition: no_sal2.h:160
#define _In_
Definition: no_sal2.h:158
#define FASTCALL
Definition: nt_native.h:50
_In_ ULONG _In_ ULONG Offset
Definition: ntddpcm.h:101
FORCEINLINE BOOLEAN KiUserTrap(IN PKTRAP_FRAME TrapFrame)
Definition: ke.h:377
FORCEINLINE VOID KeRegisterInterruptHandler(IN ULONG Vector, IN PVOID Handler)
Definition: ke.h:311
DECLSPEC_NORETURN VOID FASTCALL KiEoiHelper(IN PKTRAP_FRAME TrapFrame)
Definition: traphdlr.c:126
VOID NTAPI KiDeliverApc(IN KPROCESSOR_MODE DeliveryMode, IN PKEXCEPTION_FRAME ExceptionFrame, IN PKTRAP_FRAME TrapFrame)
Definition: apc.c:302
@ LevelSensitive
Definition: miniport.h:80
enum _KINTERRUPT_MODE KINTERRUPT_MODE
@ Input
Definition: arc.h:93
void __cdecl _disable(void)
Definition: intrin_arm.h:365
void __cdecl _enable(void)
Definition: intrin_arm.h:373
#define YieldProcessor
Definition: ke.h:48
_Requires_lock_held_ SpinLock _Releases_lock_ SpinLock _In_ _IRQL_restores_ KIRQL NewIrql
Definition: ke.h:114
#define STATUS_NOT_FOUND
Definition: shellext.h:72
#define HALP_ISA_IRQ_COUNT
Definition: smp.h:24
#define HALP_APIC_INFO_TABLE_IOAPIC_NUMBER
Definition: smp.h:23
#define DPRINT
Definition: sndvol32.h:73
static void Exit(void)
Definition: sock.c:1330
ULONG IsaIrqGsi[HALP_ISA_IRQ_COUNT]
Definition: smp.h:34
ULONG IoApicPA[HALP_APIC_INFO_TABLE_IOAPIC_NUMBER]
Definition: smp.h:32
ULONG IoApicIrqBase[HALP_APIC_INFO_TABLE_IOAPIC_NUMBER]
Definition: smp.h:33
KINTERRUPT_POLARITY IsaIrqPolarity[HALP_ISA_IRQ_COUNT]
Definition: smp.h:35
ULONG InputCount
Definition: apic.c:40
ULONG_PTR Base
Definition: apic.c:38
ULONG InputBase
Definition: apic.c:39
ULONG64 Owner
Definition: mmtypes.h:68
ULONG64 PageFrameNumber
Definition: mmtypes.h:78
ULONG64 Write
Definition: mmtypes.h:67
ULONG64 Valid
Definition: mmtypes.h:66
ULONG64 CacheDisable
Definition: mmtypes.h:70
ULONG64 Global
Definition: mmtypes.h:74
Definition: ke.h:294
#define max(a, b)
Definition: svc.c:63
FORCEINLINE VOID KiEnterInterruptTrap(IN PKTRAP_FRAME TrapFrame)
Definition: trap_x.h:368
uint32_t * PULONG
Definition: typedefs.h:59
unsigned char UCHAR
Definition: typedefs.h:53
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:255
#define NTAPI
Definition: typedefs.h:36
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define IN
Definition: typedefs.h:39
uint32_t ULONG
Definition: typedefs.h:59
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
UINT32 ExtRegSpacePresent
Definition: apicp.h:229
UINT32 RemoteIRR
Definition: apicp.h:293
UINT32 MessageType
Definition: apicp.h:289
UINT32 TimerMode
Definition: apicp.h:296
UINT32 Long
Definition: apicp.h:285
UINT32 Vector
Definition: apicp.h:288
UINT32 Mask
Definition: apicp.h:295
UINT32 TriggerMode
Definition: apicp.h:294
UINT32 DeliveryStatus
Definition: apicp.h:291
_In_ WDFCOLLECTION _In_ ULONG Index
_Must_inspect_result_ _In_ WDFDEVICE _In_ LPCGUID _Out_ PINTERFACE _In_ USHORT _In_ USHORT Version
Definition: wdffdo.h:469
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING _Out_opt_ PUSHORT _Inout_opt_ PUNICODE_STRING Value
Definition: wdfregistry.h:413
#define FORCEINLINE
Definition: wdftypes.h:67
_In_ ULONG _In_ ULONG BusInterruptLevel
Definition: halfuncs.h:171
_In_ ULONG _In_ ULONG _In_ ULONG BusInterruptVector
Definition: halfuncs.h:172
_In_ PKSERVICE_ROUTINE _In_opt_ PVOID _In_opt_ PKSPIN_LOCK _In_ ULONG _In_ KIRQL _In_ KIRQL _In_ KINTERRUPT_MODE InterruptMode
Definition: iofuncs.h:806
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:778
CCHAR KPROCESSOR_MODE
Definition: ketypes.h:7
@ InterruptActiveLow
Definition: ketypes.h:435
@ InterruptPolarityUnknown
Definition: ketypes.h:433
@ InterruptActiveHigh
Definition: ketypes.h:434
enum _KINTERRUPT_POLARITY KINTERRUPT_POLARITY
enum _KINTERRUPT_POLARITY * PKINTERRUPT_POLARITY
#define BYTE_OFFSET(Va)
#define NT_ASSERT
Definition: rtlfuncs.h:3334