/* * PROJECT: ReactOS Kernel * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) * PURPOSE: Header file for APIC hal * COPYRIGHT: Copyright 2011 Timo Kreuzer * Copyright 2021 Justin Miller */ #pragma once #ifdef _M_AMD64 #define LOCAL_APIC_BASE 0xFFFFFFFFFFFE0000ULL #define IOAPIC_BASE 0xFFFFFFFFFFFE1000ULL /* Vectors */ #define APC_VECTOR 0x1F // IRQL 01 (APC_LEVEL) - KiApcInterrupt #define DISPATCH_VECTOR 0x2F // IRQL 02 (DISPATCH_LEVEL) - KiDpcInterrupt #define CMCI_VECTOR 0x35 // IRQL 05 (CMCI_LEVEL) - HalpInterruptCmciService #define APIC_CLOCK_VECTOR 0xD1 // IRQL 13 (CLOCK_LEVEL), IRQ 8 - HalpTimerClockInterrupt #define CLOCK_IPI_VECTOR 0xD2 // IRQL 13 (CLOCK_LEVEL) - HalpTimerClockIpiRoutine #define REBOOT_VECTOR 0xD7 // IRQL 15 (PROFILE_LEVEL) - HalpInterruptRebootService #define STUB_VECTOR 0xD8 // IRQL 15 (PROFILE_LEVEL) - HalpInterruptStubService #define APIC_SPURIOUS_VECTOR 0xDF // IRQL 13 (CLOCK_LEVEL) - HalpInterruptSpuriousService #define APIC_IPI_VECTOR 0xE1 // IRQL 14 (IPI_LEVEL) - KiIpiInterrupt #define APIC_ERROR_VECTOR 0xE2 // IRQL 14 (IPI_LEVEL) - HalpInterruptLocalErrorService #define POWERFAIL_VECTOR 0xE3 // IRQL 14 (POWER_LEVEL) : HalpInterruptDeferredRecoveryService #define APIC_PROFILE_VECTOR 0xFD // IRQL 15 (PROFILE_LEVEL) - HalpTimerProfileInterrupt #define APIC_PERF_VECTOR 0xFE // IRQL 15 (PROFILE_LEVEL) - HalpPerfInterrupt #define APIC_NMI_VECTOR 0xFF #define IrqlToTpr(Irql) (Irql << 4) #define IrqlToSoftVector(Irql) ((Irql << 4)|0xf) #define TprToIrql(Tpr) ((KIRQL)(Tpr >> 4)) #define CLOCK2_LEVEL CLOCK_LEVEL #else #define LOCAL_APIC_BASE 0xFFFE0000 #define IOAPIC_BASE 0xFFFE1000 /* Vectors */ #define APIC_SPURIOUS_VECTOR 0x1f #define APC_VECTOR 0x3D // IRQL 01 #define DISPATCH_VECTOR 0x41 // IRQL 02 #define APIC_GENERIC_VECTOR 0xC1 // IRQL 27 #define APIC_CLOCK_VECTOR 0xD1 // IRQL 28 #define APIC_SYNCH_VECTOR 0xD1 // IRQL 28 #define APIC_IPI_VECTOR 0xE1 // IRQL 29 #define APIC_ERROR_VECTOR 0xE3 #define POWERFAIL_VECTOR 0xEF // IRQL 30 #define APIC_PROFILE_VECTOR 0xFD // IRQL 31 #define APIC_PERF_VECTOR 0xFE #define APIC_NMI_VECTOR 0xFF #define IrqlToTpr(Irql) (HalpIRQLtoTPR[Irql]) #define IrqlToSoftVector(Irql) IrqlToTpr(Irql) #define TprToIrql(Tpr) (HalVectorToIRQL[Tpr >> 4]) #endif #define APIC_MAX_IRQ 24 #define APIC_FREE_VECTOR 0xFF #define APIC_RESERVED_VECTOR 0xFE /* The IMCR is supported by two read/writable or write-only I/O ports, 22h and 23h, which receive address and data respectively. To access the IMCR, write a value of 70h to I/O port 22h, which selects the IMCR. Then write the data to I/O port 23h. The power-on default value is zero, which connects the NMI and 8259 INTR lines directly to the BSP. Writing a value of 01h forces the NMI and 8259 INTR signals to pass through the APIC. */ #define IMCR_ADDRESS_PORT (PUCHAR)0x0022 #define IMCR_DATA_PORT (PUCHAR)0x0023 #define IMCR_SELECT 0x70 #define IMCR_PIC_DIRECT 0x00 #define IMCR_PIC_VIA_APIC 0x01 /* APIC Register Address Map */ typedef enum _APIC_REGISTER { APIC_ID = 0x0020, /* Local APIC ID Register (R/W) */ APIC_VER = 0x0030, /* Local APIC Version Register (R) */ APIC_TPR = 0x0080, /* Task Priority Register (R/W) */ APIC_APR = 0x0090, /* Arbitration Priority Register (R) */ APIC_PPR = 0x00A0, /* Processor Priority Register (R) */ APIC_EOI = 0x00B0, /* EOI Register (W) */ APIC_RRR = 0x00C0, /* Remote Read Register () */ APIC_LDR = 0x00D0, /* Logical Destination Register (R/W) */ APIC_DFR = 0x00E0, /* Destination Format Register (0-27 R, 28-31 R/W) */ APIC_SIVR = 0x00F0, /* Spurious Interrupt Vector Register (0-3 R, 4-9 R/W) */ APIC_ISR = 0x0100, /* Interrupt Service Register 0-255 (R) */ APIC_TMR = 0x0180, /* Trigger Mode Register 0-255 (R) */ APIC_IRR = 0x0200, /* Interrupt Request Register 0-255 (r) */ APIC_ESR = 0x0280, /* Error Status Register (R) */ APIC_ICR0 = 0x0300, /* Interrupt Command Register 0-31 (R/W) */ APIC_ICR1 = 0x0310, /* Interrupt Command Register 32-63 (R/W) */ APIC_TMRLVTR = 0x0320, /* Timer Local Vector Table (R/W) */ APIC_THRMLVTR = 0x0330, /* Thermal Local Vector Table */ APIC_PCLVTR = 0x0340, /* Performance Counter Local Vector Table (R/W) */ APIC_LINT0 = 0x0350, /* LINT0 Local Vector Table (R/W) */ APIC_LINT1 = 0x0360, /* LINT1 Local Vector Table (R/W) */ APIC_ERRLVTR = 0x0370, /* Error Local Vector Table (R/W) */ APIC_TICR = 0x0380, /* Initial Count Register for Timer (R/W) */ APIC_TCCR = 0x0390, /* Current Count Register for Timer (R) */ APIC_TDCR = 0x03E0, /* Timer Divide Configuration Register (R/W) */ APIC_EAFR = 0x0400, /* extended APIC Feature register (R/W) */ APIC_EACR = 0x0410, /* Extended APIC Control Register (R/W) */ APIC_SEOI = 0x0420, /* Specific End Of Interrupt Register (W) */ APIC_EXT0LVTR = 0x0500, /* Extended Interrupt 0 Local Vector Table */ APIC_EXT1LVTR = 0x0510, /* Extended Interrupt 1 Local Vector Table */ APIC_EXT2LVTR = 0x0520, /* Extended Interrupt 2 Local Vector Table */ APIC_EXT3LVTR = 0x0530 /* Extended Interrupt 3 Local Vector Table */ } APIC_REGISTER; #define MSR_APIC_BASE 0x0000001B #define IOAPIC_PHYS_BASE 0xFEC00000 #define APIC_CLOCK_INDEX 8 #define ApicLogicalId(Cpu) ((UCHAR)(1<< Cpu)) /* The following definitions are based on AMD documentation. They differ slightly in Intel documentation. */ /* Message Type (Intel: "Delivery Mode") */ typedef enum _APIC_MT { APIC_MT_Fixed = 0, APIC_MT_LowestPriority = 1, APIC_MT_SMI = 2, APIC_MT_RemoteRead = 3, APIC_MT_NMI = 4, APIC_MT_INIT = 5, APIC_MT_Startup = 6, APIC_MT_ExtInt = 7, } APIC_MT; /* Trigger Mode */ typedef enum _APIC_TGM { APIC_TGM_Edge, APIC_TGM_Level } APIC_TGM; /* Destination Mode */ typedef enum _APIC_DM { APIC_DM_Physical, APIC_DM_Logical } APIC_DM; /* Destination Short Hand */ typedef enum _APIC_DSH { APIC_DSH_Destination, APIC_DSH_Self, APIC_DSH_AllIncludingSelf, APIC_DSH_AllExclusingSelf } APIC_DSH; /* Write Constants */ typedef enum _APIC_DF { APIC_DF_Flat = 0xFFFFFFFF, APIC_DF_Cluster = 0x0FFFFFFF } APIC_DF; /* Remote Read Status */ typedef enum _APIC_RRS { APIC_RRS_Invalid = 0, APIC_RRS_Pending = 1, APIC_RRS_Done = 2 } APIC_RRS; /* Timer Constants */ enum _TIMER_DV { TIMER_DV_DivideBy2 = 0, TIMER_DV_DivideBy4 = 1, TIMER_DV_DivideBy8 = 2, TIMER_DV_DivideBy16 = 3, TIMER_DV_DivideBy32 = 8, TIMER_DV_DivideBy64 = 9, TIMER_DV_DivideBy128 = 10, TIMER_DV_DivideBy1 = 11, } TIMER_DV; #include typedef union _APIC_BASE_ADRESS_REGISTER { UINT64 LongLong; struct { UINT64 Reserved1:8; UINT64 BootStrapCPUCore:1; UINT64 Reserved2:2; UINT64 Enable:1; UINT64 BaseAddress:40; UINT64 ReservedMBZ:12; }; } APIC_BASE_ADRESS_REGISTER; typedef union _APIC_SPURIOUS_INERRUPT_REGISTER { UINT32 Long; struct { UINT32 Vector:8; UINT32 SoftwareEnable:1; UINT32 FocusCPUCoreChecking:1; UINT32 ReservedMBZ:22; }; } APIC_SPURIOUS_INERRUPT_REGISTER; typedef union _APIC_VERSION_REGISTER { UINT32 Long; struct { UINT32 Version:8; UINT32 ReservedMBZ:8; UINT32 MaxLVT:8; UINT32 ReservedMBZ1:7; UINT32 ExtRegSpacePresent:1; }; } APIC_VERSION_REGISTER; typedef union _APIC_EXTENDED_CONTROL_REGISTER { UINT32 Long; struct { UINT32 Version:1; UINT32 SEOIEnable:1; UINT32 ExtApicIdEnable:1; UINT32 ReservedMBZ:29; }; } APIC_EXTENDED_CONTROL_REGISTER; typedef union _APIC_INTERRUPT_COMMAND_REGISTER { UINT64 LongLong; struct { UINT32 Long0; UINT32 Long1; }; struct { UINT64 Vector:8; UINT64 MessageType:3; UINT64 DestinationMode:1; UINT64 DeliveryStatus:1; UINT64 ReservedMBZ:1; UINT64 Level:1; UINT64 TriggerMode:1; UINT64 RemoteReadStatus:2; /* Intel: Reserved */ UINT64 DestinationShortHand:2; UINT64 Reserved2MBZ:36; UINT64 Destination:8; }; } APIC_INTERRUPT_COMMAND_REGISTER; typedef union _LVT_REGISTER { UINT32 Long; struct { UINT32 Vector:8; UINT32 MessageType:3; UINT32 ReservedMBZ:1; UINT32 DeliveryStatus:1; UINT32 Reserved1MBZ:1; UINT32 RemoteIRR:1; UINT32 TriggerMode:1; UINT32 Mask:1; UINT32 TimerMode:1; UINT32 Reserved2MBZ:13; }; } LVT_REGISTER; /* IOAPIC offsets */ enum { IOAPIC_IOREGSEL = 0x00, IOAPIC_IOWIN = 0x10 }; /* IOAPIC Constants */ enum { IOAPIC_ID = 0x00, IOAPIC_VER = 0x01, IOAPIC_ARB = 0x02, IOAPIC_REDTBL = 0x10 }; typedef union _IOAPIC_REDIRECTION_REGISTER { UINT64 LongLong; struct { UINT32 Long0; UINT32 Long1; }; struct { UINT64 Vector:8; UINT64 DeliveryMode:3; UINT64 DestinationMode:1; UINT64 DeliveryStatus:1; UINT64 Polarity:1; UINT64 RemoteIRR:1; UINT64 TriggerMode:1; UINT64 Mask:1; UINT64 Reserved:39; UINT64 Destination:8; }; } IOAPIC_REDIRECTION_REGISTER; #include FORCEINLINE ULONG ApicRead(APIC_REGISTER Register) { return READ_REGISTER_ULONG((PULONG)(APIC_BASE + Register)); } FORCEINLINE VOID ApicWrite(APIC_REGISTER Register, ULONG Value) { WRITE_REGISTER_ULONG((PULONG)(APIC_BASE + Register), Value); } VOID NTAPI ApicInitializeTimer(ULONG Cpu); VOID NTAPI HalInitializeProfiling(VOID); VOID NTAPI HalpInitApicInfo(IN PLOADER_PARAMETER_BLOCK KeLoaderBlock); VOID __cdecl ApicSpuriousService(VOID);