From e5adc31af7033bc30000e51e13e4961f79df5714 Mon Sep 17 00:00:00 2001 From: Rafal Kupiec Date: Mon, 27 Nov 2023 22:38:15 +0100 Subject: [PATCH] Implement basic APIC support, including X2APIC --- sdk/xtdk/amd64/hltypes.h | 51 +++++++++- sdk/xtdk/hltypes.h | 11 ++- sdk/xtdk/i686/hltypes.h | 51 +++++++++- xtoskrnl/hl/globals.c | 3 + xtoskrnl/hl/pic.c | 180 +++++++++++++++++++++++++++++++++++- xtoskrnl/includes/globals.h | 3 + xtoskrnl/includes/hl.h | 16 ++++ 7 files changed, 307 insertions(+), 8 deletions(-) diff --git a/sdk/xtdk/amd64/hltypes.h b/sdk/xtdk/amd64/hltypes.h index 19d228d..ab06ce2 100644 --- a/sdk/xtdk/amd64/hltypes.h +++ b/sdk/xtdk/amd64/hltypes.h @@ -17,7 +17,8 @@ /* APIC base addresses */ #define APIC_BASE 0xFFFFFFFFFFFE0000 -#define APIC_MSR_BASE 0x0000001B +#define APIC_LAPIC_MSR_BASE 0x0000001B +#define APIC_X2APIC_MSR_BASE 0x00000800 /* APIC vector definitions */ #define APIC_VECTOR_ZERO 0x00 @@ -69,4 +70,52 @@ /* Serial port I/O addresses */ #define COMPORT_ADDRESSES {0x000, 0x3F8, 0x2F8, 0x3E8, 0x2E8, 0x5F8, 0x4F8, 0x5E8, 0x4E8} +/* APIC Base Register */ +typedef union _APIC_BASE_REGISTER +{ + ULONGLONG LongLong; + struct + { + ULONGLONG Reserved1:8; + ULONGLONG BootStrapProcessor:1; + ULONGLONG Reserved2:1; + ULONGLONG ExtendedMode:1; + ULONGLONG Enable:1; + ULONGLONG BaseAddress:40; + ULONGLONG Reserved3:12; + }; +} APIC_BASE_REGISTER, *PAPIC_BASE_REGISTER; + +/* APIC Local Vector Table (LVT) Register */ +typedef union _APIC_LVT_REGISTER +{ + ULONG Long; + struct + { + ULONG Vector:8; + ULONG MessageType:3; + ULONG Reserved1:1; + ULONG DeliveryStatus:1; + ULONG Reserved2:1; + ULONG RemoteIRR:1; + ULONG TriggerMode:1; + ULONG Mask:1; + ULONG TimerMode:1; + ULONG Reserved3:13; + }; +} APIC_LVT_REGISTER, *PAPIC_LVT_REGISTER; + +/* APIC Spurious Register */ +typedef union _APIC_SPURIOUS_REGISTER +{ + ULONG Long; + struct + { + ULONG Vector:8; + ULONG SoftwareEnable:1; + ULONG CoreChecking:1; + ULONG Reserved:22; + }; +} APIC_SPURIOUS_REGISTER, *PAPIC_SPURIOUS_REGISTER; + #endif /* __XTDK_AMD64_HLTYPES_H */ diff --git a/sdk/xtdk/hltypes.h b/sdk/xtdk/hltypes.h index 8eec8f2..bfcee77 100644 --- a/sdk/xtdk/hltypes.h +++ b/sdk/xtdk/hltypes.h @@ -101,14 +101,14 @@ typedef enum _APIC_REGISTER APIC_EOI = 0x0B, /* EOI Register */ APIC_RRR = 0x0C, /* Remote Read Register */ APIC_LDR = 0x0D, /* Logical Destination Register */ - APIC_DFR = 0x0E, /* Destination Format Register */ + APIC_DFR = 0x0E, /* Destination Format Register (not available in extended mode) */ APIC_SIVR = 0x0F, /* Spurious Interrupt Vector Register */ APIC_ISR = 0x10, /* Interrupt Service Register*/ APIC_TMR = 0x18, /* Trigger Mode Register */ APIC_IRR = 0x20, /* Interrupt Request Register */ APIC_ESR = 0x28, /* Error Status Register */ APIC_ICR0 = 0x30, /* Interrupt Command Register */ - APIC_ICR1 = 0x31, /* Interrupt Command Register */ + APIC_ICR1 = 0x31, /* Interrupt Command Register (not available in extended mode) */ APIC_TMRLVTR = 0x32, /* Timer Local Vector Table */ APIC_THRMLVTR = 0x33, /* Thermal Local Vector Table */ APIC_PCLVTR = 0x34, /* Performance Counter Local Vector Table */ @@ -127,6 +127,13 @@ typedef enum _APIC_REGISTER APIC_EXT3LVTR = 0x53 /* Extended Interrupt 3 Local Vector Table */ } APIC_REGISTER, *PAPIC_REGISTER; +/* APIC mode list */ +typedef enum _HAL_APIC_MODE +{ + APIC_MODE_COMPAT, + APIC_MODE_X2APIC +} HAL_APIC_MODE, *PHAL_APIC_MODE; + /* Serial (COM) port initial state */ typedef struct _CPPORT { diff --git a/sdk/xtdk/i686/hltypes.h b/sdk/xtdk/i686/hltypes.h index 47628bd..386175c 100644 --- a/sdk/xtdk/i686/hltypes.h +++ b/sdk/xtdk/i686/hltypes.h @@ -17,7 +17,8 @@ /* APIC base addresses */ #define APIC_BASE 0xFFFE0000 -#define APIC_MSR_BASE 0x0000001B +#define APIC_LAPIC_MSR_BASE 0x0000001B +#define APIC_X2APIC_MSR_BASE 0x00000800 /* APIC vector definitions */ #define APIC_VECTOR_ZERO 0x00 @@ -74,4 +75,52 @@ /* Serial port I/O addresses */ #define COMPORT_ADDRESSES {0x000, 0x3F8, 0x2F8, 0x3E8, 0x2E8, 0x5F8, 0x4F8, 0x5E8, 0x4E8} +/* APIC Base Register */ +typedef union _APIC_BASE_REGISTER +{ + ULONGLONG LongLong; + struct + { + ULONGLONG Reserved1:8; + ULONGLONG BootStrapProcessor:1; + ULONGLONG Reserved2:1; + ULONGLONG ExtendedMode:1; + ULONGLONG Enable:1; + ULONGLONG BaseAddress:40; + ULONGLONG Reserved3:12; + }; +} APIC_BASE_REGISTER, *PAPIC_BASE_REGISTER; + +/* APIC Local Vector Table (LVT) Register */ +typedef union _APIC_LVT_REGISTER +{ + ULONG Long; + struct + { + ULONG Vector:8; + ULONG MessageType:3; + ULONG Reserved1:1; + ULONG DeliveryStatus:1; + ULONG Reserved2:1; + ULONG RemoteIRR:1; + ULONG TriggerMode:1; + ULONG Mask:1; + ULONG TimerMode:1; + ULONG Reserved3:13; + }; +} APIC_LVT_REGISTER, *PAPIC_LVT_REGISTER; + +/* APIC Spurious Register */ +typedef union _APIC_SPURIOUS_REGISTER +{ + ULONG Long; + struct + { + ULONG Vector:8; + ULONG SoftwareEnable:1; + ULONG CoreChecking:1; + ULONG Reserved:22; + }; +} APIC_SPURIOUS_REGISTER, *PAPIC_SPURIOUS_REGISTER; + #endif /* __XTDK_I686_HLTYPES_H */ diff --git a/xtoskrnl/hl/globals.c b/xtoskrnl/hl/globals.c index 15c38f9..8bf7ecb 100644 --- a/xtoskrnl/hl/globals.c +++ b/xtoskrnl/hl/globals.c @@ -9,5 +9,8 @@ #include +/* APIC mode */ +HAL_APIC_MODE HlpApicMode; + /* FrameBuffer information */ HAL_FRAMEBUFFER_DATA HlpFrameBufferData; diff --git a/xtoskrnl/hl/pic.c b/xtoskrnl/hl/pic.c index b2fc1cc..85b932f 100644 --- a/xtoskrnl/hl/pic.c +++ b/xtoskrnl/hl/pic.c @@ -10,7 +10,7 @@ /** - * Reads from the local APIC register. + * Reads from the APIC register. * * @param Register * Supplies the APIC register to read from. @@ -23,11 +23,20 @@ XTFASTCALL ULONG HlReadApicRegister(IN APIC_REGISTER Register) { - return RtlReadRegisterLong((PULONG)(APIC_BASE + (Register << 4))); + if(HlpApicMode == APIC_MODE_X2APIC) + { + /* Read from x2APIC MSR */ + return ArReadModelSpecificRegister((ULONG)(APIC_X2APIC_MSR_BASE + Register)); + } + else + { + /* Read from xAPIC */ + return RtlReadRegisterLong((PULONG)(APIC_BASE + (Register << 4))); + } } /** - * Writes to the local APIC register. + * Writes to the APIC register. * * @param Register * Supplies the APIC register to write to. @@ -44,5 +53,168 @@ VOID HlWriteApicRegister(IN APIC_REGISTER Register, IN ULONG Value) { - RtlWriteRegisterLong((PULONG)(APIC_BASE + (Register << 4)), Value); + if(HlpApicMode == APIC_MODE_X2APIC) + { + /* Write to x2APIC MSR */ + ArWriteModelSpecificRegister((ULONG)(APIC_X2APIC_MSR_BASE + Register), Value); + } + else + { + /* Write to xAPIC */ + RtlWriteRegisterLong((PULONG)(APIC_BASE + (Register << 4)), Value); + } +} + +/** + * Checks whether the x2APIC extension is supported by the processor. + * + * @return This routine returns TRUE if x2APIC is supported, or FALSE otherwise. + * + * @since XT 1.0 + * + * @todo Check if bits 0 and 1 of DMAR ACPI table flags are set after implementing ACPI support. + * Intel VT-d spec says x2apic should not be enabled if they are. + */ +XTAPI +BOOLEAN +HlpCheckX2ApicSupport(VOID) +{ + CPUID_REGISTERS CpuRegisters; + + /* Prepare CPUID registers */ + CpuRegisters.Leaf = CPUID_GET_CPU_FEATURES; + CpuRegisters.SubLeaf = 0; + CpuRegisters.Eax = 0; + CpuRegisters.Ebx = 0; + CpuRegisters.Ecx = 0; + CpuRegisters.Edx = 0; + + /* Get CPUID */ + ArCpuId(&CpuRegisters); + + /* Check x2APIC status from the CPUID results */ + if(!(CpuRegisters.Ecx & CPUID_FEATURES_ECX_X2APIC)) + { + /* x2APIC is not supported */ + return FALSE; + } + + /* x2APIC is supported */ + return TRUE; +} + +/** + * Allows an APIC spurious interrupts to end up. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTCDECL +VOID +HlpHandleApicSpuriousService() +{ +} + +/** + * Allows a PIC spurious interrupts to end up. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTCDECL +VOID +HlpHandlePicSpuriousService() +{ +} + +/** + * Initializes the APIC interrupt controller. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + * + * @todo Register interrupt handlers for spurious vectors. + */ +XTAPI +VOID +HlpInitializeApic() +{ + APIC_BASE_REGISTER BaseRegister; + APIC_LVT_REGISTER LvtRegister; + APIC_SPURIOUS_REGISTER SpuriousRegister; + ULONG CpuNumber = 0; + + /* Check if this is an x2APIC compatible machine */ + if(HlpCheckX2ApicSupport()) + { + /* Enable x2APIC */ + HlpApicMode = APIC_MODE_X2APIC; + } + else + { + /* Use xAPIC compatibility mode */ + HlpApicMode = APIC_MODE_COMPAT; + } + + /* Enable the APIC */ + BaseRegister.LongLong = ArReadModelSpecificRegister(APIC_LAPIC_MSR_BASE); + BaseRegister.Enable = 1; + BaseRegister.ExtendedMode = (HlpApicMode == APIC_MODE_X2APIC); + BaseRegister.BootStrapProcessor = 1; + ArWriteModelSpecificRegister(APIC_LAPIC_MSR_BASE, BaseRegister.LongLong); + + /* xAPIC compatibility mode specific initialization */ + if(HlpApicMode == APIC_MODE_COMPAT) + { + /* Initialize Destination Format Register with flat model */ + HlWriteApicRegister(APIC_DFR, APIC_DF_FLAT); + + /* Set the logical APIC ID */ + HlWriteApicRegister(APIC_LDR, (1UL << CpuNumber) << 24); + } + + /* Set the spurious interrupt vector and register interrupt handlers */ + SpuriousRegister.Long = HlReadApicRegister(APIC_SIVR); + SpuriousRegister.Vector = APIC_VECTOR_SPURIOUS; + SpuriousRegister.SoftwareEnable = 1; + SpuriousRegister.CoreChecking = 0; + HlWriteApicRegister(APIC_SIVR, SpuriousRegister.Long); + + /* Initialize Logical Vector Table */ + LvtRegister.Long = 0; + LvtRegister.Vector = APIC_VECTOR_NMI; + LvtRegister.MessageType = APIC_DM_FIXED; + LvtRegister.DeliveryStatus = 0; + LvtRegister.RemoteIRR = 0; + LvtRegister.TriggerMode = APIC_TGM_EDGE; + LvtRegister.Mask = 0; + LvtRegister.TimerMode = 0; + + /* Mask LVT tables */ + HlWriteApicRegister(APIC_TMRLVTR, LvtRegister.Long); + HlWriteApicRegister(APIC_THRMLVTR, LvtRegister.Long); + HlWriteApicRegister(APIC_PCLVTR, LvtRegister.Long); + + /* Mask LINT0 */ + LvtRegister.Vector = APIC_VECTOR_SPURIOUS; + LvtRegister.MessageType = APIC_DM_EXTINT; + HlWriteApicRegister(APIC_LINT0, LvtRegister.Long); + + /* Mask LINT1 */ + LvtRegister.Mask = 0; + LvtRegister.Vector = APIC_VECTOR_NMI; + LvtRegister.MessageType = APIC_DM_NMI; + LvtRegister.TriggerMode = APIC_TGM_LEVEL; + HlWriteApicRegister(APIC_LINT1, LvtRegister.Long); + + /* Mask LVTR_ERROR */ + LvtRegister.Vector = APIC_VECTOR_ERROR; + LvtRegister.MessageType = APIC_DM_FIXED; + HlWriteApicRegister(APIC_ERRLVTR, LvtRegister.Long); + + /* Clear errors after enabling vectors */ + HlWriteApicRegister(APIC_ESR, 0); } diff --git a/xtoskrnl/includes/globals.h b/xtoskrnl/includes/globals.h index 98a3671..70b111a 100644 --- a/xtoskrnl/includes/globals.h +++ b/xtoskrnl/includes/globals.h @@ -12,6 +12,9 @@ #include +/* APIC mode */ +EXTERN HAL_APIC_MODE HlpApicMode; + /* FrameBuffer information */ EXTERN HAL_FRAMEBUFFER_DATA HlpFrameBufferData; diff --git a/xtoskrnl/includes/hl.h b/xtoskrnl/includes/hl.h index 6ff39d1..215d208 100644 --- a/xtoskrnl/includes/hl.h +++ b/xtoskrnl/includes/hl.h @@ -69,6 +69,22 @@ VOID HlWriteApicRegister(IN APIC_REGISTER Register, IN ULONG Value); +XTAPI +BOOLEAN +HlpCheckX2ApicSupport(VOID); + +XTCDECL +VOID +HlpHandleApicSpuriousService(); + +XTCDECL +VOID +HlpHandlePicSpuriousService(); + +XTAPI +VOID +HlpInitializeApic(); + XTFASTCALL KRUNLEVEL HlpTransformApicTprToRunLevel(IN UCHAR Tpr);