diff --git a/sdk/xtdk/amd64/hltypes.h b/sdk/xtdk/amd64/hltypes.h index 71f0381..0c39d11 100644 --- a/sdk/xtdk/amd64/hltypes.h +++ b/sdk/xtdk/amd64/hltypes.h @@ -9,6 +9,7 @@ #ifndef __XTDK_AMD64_HLTYPES_H #define __XTDK_AMD64_HLTYPES_H +#include #include #include #include @@ -53,6 +54,27 @@ /* Maximum number of I/O APICs */ #define APIC_MAX_IOAPICS 64 +/* I/O APIC base address */ +#define IOAPIC_DEFAULT_BASE 0xFEC00000 + +/* I/O APIC definitions */ +#define IOAPIC_MAX_CONTROLLERS 128 +#define IOAPIC_MAX_OVERRIDES 16 +#define IOAPIC_RTE_MASKED 0x100FF +#define IOAPIC_RTE_SIZE 2 +#define IOAPIC_VECTOR_FREE 0xFF +#define IOAPIC_VECTOR_RESERVED 0xFE + +/* IOAPIC offsets */ +#define IOAPIC_IOREGSEL 0x00 +#define IOAPIC_IOWIN 0x10 + +/* IOAPIC registers */ +#define IOAPIC_ID 0x00 +#define IOAPIC_VER 0x01 +#define IOAPIC_ARB 0x02 +#define IOAPIC_REDTBL 0x10 + /* 8259/ISP PIC ports definitions */ #define PIC1_CONTROL_PORT 0x20 #define PIC1_DATA_PORT 0x21 @@ -77,6 +99,13 @@ /* C/C++ specific code */ #ifndef __XTOS_ASSEMBLER__ +/* APIC destination mode enumeration list */ +typedef enum _APIC_DEST_MODE +{ + APIC_DM_Physical, + APIC_DM_Logical +} APIC_DEST_MODE, *PAPIC_DEST_MODE; + /* APIC delivery mode enumeration list */ typedef enum _APIC_DM { @@ -274,6 +303,40 @@ typedef union _APIC_SPURIOUS_REGISTER }; } APIC_SPURIOUS_REGISTER, *PAPIC_SPURIOUS_REGISTER; +/* I/O APIC Controller information */ +typedef struct _IOAPIC_DATA +{ + ULONG GsiBase; + ULONG Identifier; + ULONG LineCount; + PHYSICAL_ADDRESS PhysicalAddress; + ULONG_PTR VirtualAddress; +} IOAPIC_DATA, *PIOAPIC_DATA; + +/* I/O APIC Redirection Register */ +typedef union _IOAPIC_REDIRECTION_REGISTER +{ + ULONGLONG LongLong; + struct + { + UINT Base; + UINT Extended; + }; + struct + { + ULONGLONG Vector:8; + ULONGLONG DeliveryMode:3; + ULONGLONG DestinationMode:1; + ULONGLONG DeliveryStatus:1; + ULONGLONG PinPolarity:1; + ULONGLONG RemoteIRR:1; + ULONGLONG TriggerMode:1; + ULONGLONG Mask:1; + ULONGLONG Reserved:39; + ULONGLONG Destination:8; + }; +} IOAPIC_REDIRECTION_REGISTER, *PIOAPIC_REDIRECTION_REGISTER; + /* I8259 PIC register structure */ typedef union _PIC_I8259_ICW1 { diff --git a/sdk/xtdk/amd64/xtstruct.h b/sdk/xtdk/amd64/xtstruct.h index 5d1ea52..7ac770b 100644 --- a/sdk/xtdk/amd64/xtstruct.h +++ b/sdk/xtdk/amd64/xtstruct.h @@ -16,6 +16,7 @@ #ifndef __XTOS_ASSEMBLER__ /* Architecture-specific enumeration lists forward references */ +typedef enum _APIC_DEST_MODE APIC_DEST_MODE, *PAPIC_DEST_MODE; typedef enum _APIC_DM APIC_DM, *PAPIC_DM; typedef enum _APIC_DSH APIC_DSH, *PAPIC_DSH; typedef enum _APIC_MODE APIC_MODE, *PAPIC_MODE; @@ -45,6 +46,7 @@ typedef struct _CPUID_REGISTERS CPUID_REGISTERS, *PCPUID_REGISTERS; typedef struct _CPUID_SIGNATURE CPUID_SIGNATURE, *PCPUID_SIGNATURE; typedef struct _FLOATING_SAVE_AREA FLOATING_SAVE_AREA, *PFLOATING_SAVE_AREA; typedef struct _HARDWARE_PTE HARDWARE_PTE, *PHARDWARE_PTE; +typedef struct _IOAPIC_DATA IOAPIC_DATA, *PIOAPIC_DATA; typedef struct _KDESCRIPTOR KDESCRIPTOR, *PKDESCRIPTOR; typedef struct _KEXCEPTION_FRAME KEXCEPTION_FRAME, *PKEXCEPTION_FRAME; typedef struct _KGDTENTRY KGDTENTRY, *PKGDTENTRY; @@ -76,6 +78,7 @@ typedef union _APIC_BASE_REGISTER APIC_BASE_REGISTER, *PAPIC_BASE_REGISTER; typedef union _APIC_COMMAND_REGISTER APIC_COMMAND_REGISTER, *PAPIC_COMMAND_REGISTER; typedef union _APIC_LVT_REGISTER APIC_LVT_REGISTER, *PAPIC_LVT_REGISTER; typedef union _APIC_SPURIOUS_REGISTER APIC_SPURIOUS_REGISTER, *PAPIC_SPURIOUS_REGISTER; +typedef union _IOAPIC_REDIRECTION_REGISTER IOAPIC_REDIRECTION_REGISTER, *PIOAPIC_REDIRECTION_REGISTER; typedef union _MMPTE MMP5E, *PMMP5E; typedef union _MMPTE MMPDE, *PMMPDE; typedef union _MMPTE MMPPE, *PMMPPE; diff --git a/sdk/xtdk/i686/hltypes.h b/sdk/xtdk/i686/hltypes.h index a6ee029..1b85f72 100644 --- a/sdk/xtdk/i686/hltypes.h +++ b/sdk/xtdk/i686/hltypes.h @@ -9,6 +9,7 @@ #ifndef __XTDK_I686_HLTYPES_H #define __XTDK_I686_HLTYPES_H +#include #include #include #include @@ -58,6 +59,27 @@ /* Maximum number of I/O APICs */ #define APIC_MAX_IOAPICS 64 +/* I/O APIC base address */ +#define IOAPIC_DEFAULT_BASE 0xFEC00000 + +/* I/O APIC definitions */ +#define IOAPIC_MAX_CONTROLLERS 64 +#define IOAPIC_MAX_OVERRIDES 16 +#define IOAPIC_RTE_MASKED 0x100FF +#define IOAPIC_RTE_SIZE 2 +#define IOAPIC_VECTOR_FREE 0xFF +#define IOAPIC_VECTOR_RESERVED 0xFE + +/* IOAPIC offsets */ +#define IOAPIC_IOREGSEL 0x00 +#define IOAPIC_IOWIN 0x10 + +/* IOAPIC registers */ +#define IOAPIC_ID 0x00 +#define IOAPIC_VER 0x01 +#define IOAPIC_ARB 0x02 +#define IOAPIC_REDTBL 0x10 + /* 8259/ISP PIC ports definitions */ #define PIC1_CONTROL_PORT 0x20 #define PIC1_DATA_PORT 0x21 @@ -84,6 +106,13 @@ /* C/C++ specific code */ #ifndef __XTOS_ASSEMBLER__ +/* APIC destination mode enumeration list */ +typedef enum _APIC_DEST_MODE +{ + APIC_DM_Physical, + APIC_DM_Logical +} APIC_DEST_MODE, *PAPIC_DEST_MODE; + /* APIC delivery mode enumeration list */ typedef enum _APIC_DM { @@ -281,6 +310,40 @@ typedef union _APIC_SPURIOUS_REGISTER }; } APIC_SPURIOUS_REGISTER, *PAPIC_SPURIOUS_REGISTER; +/* I/O APIC Controller information */ +typedef struct _IOAPIC_DATA +{ + ULONG GsiBase; + ULONG Identifier; + ULONG LineCount; + PHYSICAL_ADDRESS PhysicalAddress; + ULONG_PTR VirtualAddress; +} IOAPIC_DATA, *PIOAPIC_DATA; + +/* I/O APIC Redirection Register */ +typedef union _IOAPIC_REDIRECTION_REGISTER +{ + ULONGLONG LongLong; + struct + { + UINT Base; + UINT Extended; + }; + struct + { + ULONGLONG Vector:8; + ULONGLONG DeliveryMode:3; + ULONGLONG DestinationMode:1; + ULONGLONG DeliveryStatus:1; + ULONGLONG PinPolarity:1; + ULONGLONG RemoteIRR:1; + ULONGLONG TriggerMode:1; + ULONGLONG Mask:1; + ULONGLONG Reserved:39; + ULONGLONG Destination:8; + }; +} IOAPIC_REDIRECTION_REGISTER, *PIOAPIC_REDIRECTION_REGISTER; + /* I8259 PIC register structure */ typedef union _PIC_I8259_ICW1 { diff --git a/sdk/xtdk/i686/xtstruct.h b/sdk/xtdk/i686/xtstruct.h index 0e6310b..a265e9c 100644 --- a/sdk/xtdk/i686/xtstruct.h +++ b/sdk/xtdk/i686/xtstruct.h @@ -16,6 +16,7 @@ #ifndef __XTOS_ASSEMBLER__ /* Architecture-specific enumeration lists forward references */ +typedef enum _APIC_DEST_MODE APIC_DEST_MODE, *PAPIC_DEST_MODE; typedef enum _APIC_DM APIC_DM, *PAPIC_DM; typedef enum _APIC_DSH APIC_DSH, *PAPIC_DSH; typedef enum _APIC_MODE APIC_MODE, *PAPIC_MODE; @@ -48,6 +49,7 @@ typedef struct _FX_SAVE_AREA FX_SAVE_AREA, *PFX_SAVE_AREA; typedef struct _FX_SAVE_FORMAT FX_SAVE_FORMAT, *PFX_SAVE_FORMAT; typedef struct _HARDWARE_LEGACY_PTE HARDWARE_LEGACY_PTE, *PHARDWARE_LEGACY_PTE; typedef struct _HARDWARE_MODERN_PTE HARDWARE_MODERN_PTE, *PHARDWARE_MODERN_PTE; +typedef struct _IOAPIC_DATA IOAPIC_DATA, *PIOAPIC_DATA; typedef struct _KDESCRIPTOR KDESCRIPTOR, *PKDESCRIPTOR; typedef struct _KEXCEPTION_FRAME KEXCEPTION_FRAME, *PKEXCEPTION_FRAME; typedef struct _KGDTENTRY KGDTENTRY, *PKGDTENTRY; @@ -86,6 +88,7 @@ typedef union _APIC_COMMAND_REGISTER APIC_COMMAND_REGISTER, *PAPIC_COMMAND_REGIS typedef union _APIC_LVT_REGISTER APIC_LVT_REGISTER, *PAPIC_LVT_REGISTER; typedef union _APIC_SPURIOUS_REGISTER APIC_SPURIOUS_REGISTER, *PAPIC_SPURIOUS_REGISTER; typedef union _HARDWARE_PTE HARDWARE_PTE, *PHARDWARE_PTE; +typedef union _IOAPIC_REDIRECTION_REGISTER IOAPIC_REDIRECTION_REGISTER, *PIOAPIC_REDIRECTION_REGISTER; typedef union _MMPML2_PTE MMPML2_PTE, *PMMPML2_PTE; typedef union _MMPML3_PTE MMPML3_PTE, *PMMPML3_PTE; typedef union _MMPTE MMPDE, *PMMPDE; diff --git a/xtoskrnl/hl/data.cc b/xtoskrnl/hl/data.cc index 7d5aae5..970fcfc 100644 --- a/xtoskrnl/hl/data.cc +++ b/xtoskrnl/hl/data.cc @@ -39,6 +39,21 @@ HL_SCROLL_REGION_DATA HL::FrameBuffer::ScrollRegionData; /* APIC mode */ APIC_MODE HL::Pic::ApicMode; +/* Number of I/O APIC controllers */ +ULONG HL::Pic::ControllerCount; + +/* I/O APIC controllers information */ +IOAPIC_DATA HL::Pic::Controllers[IOAPIC_MAX_CONTROLLERS]; + +/* Number of I/O APIC overrides */ +ULONG HL::Pic::IrqOverrideCount; + +/* I/O APIC overrides information */ +ACPI_MADT_INTERRUPT_OVERRIDE HL::Pic::IrqOverrides[IOAPIC_MAX_OVERRIDES]; + +/* Mapped interrupt vectors */ +UCHAR HL::Pic::MappedVectors[256]; + /* Kernel profiling interval */ ULONG HL::Timer::ProfilingInterval; diff --git a/xtoskrnl/hl/x86/pic.cc b/xtoskrnl/hl/x86/pic.cc index 43dc1e3..f84f3ac 100644 --- a/xtoskrnl/hl/x86/pic.cc +++ b/xtoskrnl/hl/x86/pic.cc @@ -9,6 +9,62 @@ #include +/** + * Allocates, maps and commits a requested system interrupt level internally. + * + * @param RunLevel + * Supplies the actual system run level to allocate. + * + * @param Vector + * Supplies the interrupt handler vector assigned to process requests originating on the line. + * + * @return This routine returns the configured target vector. + * + * @since XT 1.0 + */ +XTAPI +VOID +HL::Pic::AllocateSystemInterrupt(IN UCHAR Irq, + IN UCHAR RunLevel, + IN UCHAR Vector) +{ + IOAPIC_REDIRECTION_REGISTER Register; + PIOAPIC_DATA Controller; + ULONG EntryNumber, Gsi; + XTSTATUS Status; + USHORT Flags; + + /* Determine the GSI and flags for the requested IRQ */ + ResolveInterruptOverride(Irq, &Gsi, &Flags); + + /* Find the APIC controller for the GSI */ + Status = GetIoApicController(Gsi, &Controller, &EntryNumber); + if(Status != STATUS_SUCCESS) + { + /* GSI maps to an invalid controller, return */ + DebugPrint(L"ERROR: Hardware IRQ / GSI maps to an invalid controller!\n"); + return; + } + + /* Model a logical connection */ + Register.DeliveryMode = APIC_DM_LOWPRIO; + Register.DeliveryStatus = 0; + Register.Destination = HL::Pic::ReadApicRegister(APIC_ID) >> 24; + Register.DestinationMode = APIC_DM_Physical; + Register.Mask = 1; + Register.PinPolarity = ((Flags & 0x03) == 0x03) ? 1 : 0; + Register.RemoteIRR = 0; + Register.Reserved = 0; + Register.TriggerMode = (((Flags >> 2) & 0x03) == 0x03) ? APIC_TGM_LEVEL : APIC_TGM_EDGE; + Register.Vector = Vector; + + /* Flash logical rules back into the hardware configuration index */ + WriteRedirectionEntry(Controller, EntryNumber, Register); + + /* Persist the allocated slot so standard routing algorithms don't overlap it */ + MappedVectors[Vector] = RunLevel; +} + /** * Checks whether the APIC is supported by the processor. * @@ -97,6 +153,105 @@ HL::Pic::ClearApicErrors(VOID) WriteApicRegister(APIC_ESR, 0); } +/** + * Searches the ACPI MADT tables for the I/O APIC controllers. + * + * @return This routine returns the status code. + * + * @since XT 1.0 + */ +XTAPI +XTSTATUS +HL::Pic::DetectIoApicControllers(VOID) +{ + PACPI_MADT_INTERRUPT_OVERRIDE OverrideDescriptor; + PACPI_MADT_IOAPIC IoApicDescriptor; + PACPI_SUBTABLE_HEADER SubTable; + ULONG_PTR MadtTable; + PACPI_MADT Madt; + XTSTATUS Status; + + /* Initialize number of I/O APIC Controllers */ + ControllerCount = 0; + + /* Get Multiple APIC Description Table (MADT) */ + Status = HL::Acpi::GetAcpiTable(ACPI_MADT_SIGNATURE, (PACPI_DESCRIPTION_HEADER*)&Madt); + if(Status == STATUS_SUCCESS && Madt != NULLPTR) + { + /* Set APIC table traverse pointer */ + MadtTable = (ULONG_PTR)Madt->ApicTables; + + /* Traverse all MADT tables to discover IOAPIC configurations */ + while(MadtTable < ((ULONG_PTR)Madt + Madt->Header.Length)) + { + /* Extract active header element */ + SubTable = (PACPI_SUBTABLE_HEADER)MadtTable; + + /* Prevent infinite traversal loops on corrupted firmware definitions */ + if(SubTable->Length == 0) + { + /* Invalid MADT table, break loop */ + break; + } + + /* Test specifically for I/O APIC component identity */ + if(SubTable->Type == ACPI_MADT_TYPE_IOAPIC && + SubTable->Length >= sizeof(ACPI_MADT_IOAPIC)) + { + /* Extract I/O APIC descriptor */ + IoApicDescriptor = (PACPI_MADT_IOAPIC)MadtTable; + + /* Set information about this I/O APIC Controller */ + Controllers[ControllerCount].GsiBase = IoApicDescriptor->GlobalIrqBase; + Controllers[ControllerCount].Identifier = IoApicDescriptor->IoApicId; + Controllers[ControllerCount].PhysicalAddress.QuadPart = IoApicDescriptor->IoApicAddress; + + /* Increment I/O APIC controller index */ + ControllerCount++; + } + else if(SubTable->Type == ACPI_MADT_TYPE_INT_OVERRIDE && + SubTable->Length >= sizeof(ACPI_MADT_INTERRUPT_OVERRIDE)) + { + /* Check if maximum number of interrupt overrides has not been reached */ + if(IrqOverrideCount < IOAPIC_MAX_OVERRIDES) + { + /* Extract interrupt override descriptor */ + OverrideDescriptor = (PACPI_MADT_INTERRUPT_OVERRIDE)MadtTable; + + /* Save information about this interrupt override */ + IrqOverrides[IrqOverrideCount].Bus = OverrideDescriptor->Bus; + IrqOverrides[IrqOverrideCount].Flags = OverrideDescriptor->Flags; + IrqOverrides[IrqOverrideCount].GlobalSystemInterrupt = OverrideDescriptor->GlobalSystemInterrupt; + IrqOverrides[IrqOverrideCount].SourceIrq = OverrideDescriptor->SourceIrq; + + /* Increment interrupt override index */ + IrqOverrideCount++; + } + } + + /* Ensure, maximum number of I/O APIC controllers has not been reached */ + if(ControllerCount >= IOAPIC_MAX_CONTROLLERS) + { + /* No more I/O APIC controllers supported, break loop */ + break; + } + + /* Go to the next subtable */ + MadtTable += SubTable->Length; + } + } + + /* Check if any I/O APIC controllers were found */ + if(ControllerCount == 0) + { + /* No I/O APIC controllers found, return failure */ + return STATUS_NOT_FOUND; + } + + /* Return success */ + return STATUS_SUCCESS; +} + /** * Gets the local APIC ID of the current processor. * @@ -117,6 +272,48 @@ HL::Pic::GetCpuApicId(VOID) return (ApicMode == APIC_MODE_COMPAT) ? ((ApicId & 0xFFFFFFFF) >> APIC_XAPIC_LDR_SHIFT) : ApicId; } +/** + * Gets the I/O APIC controller information for the specified GSI. + * + * @param Gsi + * Supplies the GSI to get the I/O APIC controller information for. + * + * @param Controller + * Supplies a pointer to the memory area where the I/O APIC controller information will be stored. + * + * @param EntryNumber + * Supplies a pointer to the memory area where the entry number will be stored. + * + * @return This routine returns the status code. + * + * @since XT 1.0 + */ +XTAPI +XTSTATUS +HL::Pic::GetIoApicController(IN ULONG Gsi, + OUT PIOAPIC_DATA *Controller, + OUT PULONG EntryNumber) +{ + ULONG ControllerIndex; + + /* Iterate over all available I/O APIC controllers */ + for(ControllerIndex = 0; ControllerIndex < ControllerCount; ControllerIndex++) + { + /* Check if the GSI belongs to this I/O APIC controller */ + if(Gsi >= Controllers[ControllerIndex].GsiBase && + Gsi < (Controllers[ControllerIndex].GsiBase + Controllers[ControllerIndex].LineCount)) + { + /* Return I/O APIC controller information */ + *Controller = &Controllers[ControllerIndex]; + *EntryNumber = (ULONG)(Gsi - Controllers[ControllerIndex].GsiBase); + return STATUS_SUCCESS; + } + } + + /* GSI does not belong to any I/O APIC controller, return failure */ + return STATUS_NOT_FOUND; +} + /** * Initializes the APIC interrupt controller. * @@ -137,7 +334,7 @@ HL::Pic::InitializeApic(VOID) if(!CheckApicSupport()) { /* APIC is not supported, raise kernel panic */ - DebugPrint(L"FATAL ERROR: Local APIC not present.\n"); + DebugPrint(L"ERROR: Local APIC not present.\n"); KE::Crash::Panic(0x5D, CPUID_GET_STANDARD1_FEATURES, 0x0, 0x0, CPUID_FEATURES_EDX_APIC); } @@ -233,6 +430,84 @@ HL::Pic::InitializeApic(VOID) WriteApicRegister(APIC_TPR, 0x00); } +/** + * Initializes the global I/O APIC controller setup over the entire redirection span. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +HL::Pic::InitializeIOApic(VOID) +{ + ULONG ControllerIndex, LineIndex, Vector, VersionRegister; + IOAPIC_REDIRECTION_REGISTER Register; + XTSTATUS Status; + + /* Detect I/O APIC controllers */ + Status = DetectIoApicControllers(); + if(Status != STATUS_SUCCESS) + { + DebugPrint(L"ERROR: I/O APIC Controller not present.\n"); + KE::Crash::Panic(0x5D, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF); + } + + /* Iterate over all I/O APIC controllers */ + ControllerIndex = 0; + while(ControllerIndex < ControllerCount) + { + /* Map the I/O APIC controller memory into hardware space */ + MM::HardwarePool::MapHardwareMemory(Controllers[ControllerIndex].PhysicalAddress, + 1, + FALSE, + (PVOID*)&Controllers[ControllerIndex].VirtualAddress); + + /* Perform a memory barrier */ + AR::CpuFunc::MemoryBarrier(); + AR::CpuFunc::ReadWriteBarrier(); + + /* Read the version register and calculate the maximum number of redirection entries */ + VersionRegister = ReadIOApicRegister(&Controllers[ControllerIndex], IOAPIC_VER); + Controllers[ControllerIndex].LineCount = ((VersionRegister >> 16) & 0xFF) + 1; + + /* Set up the default redirection entry for this controller */ + Register.DeliveryMode = APIC_DM_FIXED; + Register.DeliveryStatus = 0; + Register.Destination = ReadIOApicRegister(&Controllers[ControllerIndex], IOAPIC_ID) >> 24; + Register.DestinationMode = 0; + Register.Mask = 1; + Register.PinPolarity = 0; + Register.RemoteIRR = 0; + Register.Reserved = 0; + Register.TriggerMode = APIC_TGM_EDGE; + Register.Vector = IOAPIC_VECTOR_FREE; + + /* Propagate defaults across the array of potential handlers */ + for(LineIndex = 0; LineIndex < Controllers[ControllerIndex].LineCount; LineIndex++) + { + /* Write default values into the redirection table */ + WriteRedirectionEntry(&Controllers[ControllerIndex], LineIndex, Register); + } + + /* Print information about the I/O APIC controller */ + DebugPrint(L"Initialized I/O APIC Controller #%lu at 0x%llX (ID: %lu, GSI Base: %lu, Line Count: %lu)\n", + ControllerIndex, Controllers[ControllerIndex].VirtualAddress, + Controllers[ControllerIndex].Identifier, Controllers[ControllerIndex].GsiBase, + Controllers[ControllerIndex].LineCount); + + /* Go to the next I/O APIC controller */ + ControllerIndex++; + } + + /* Assign initial clean state for mapping translations */ + for(Vector = 0; Vector <= 255; Vector++) + { + /* Set vector to free */ + MappedVectors[Vector] = IOAPIC_VECTOR_FREE; + } +} + /** * Initializes the legacy PIC interrupt controller. * @@ -357,6 +632,104 @@ HL::Pic::ReadApicRegister(IN APIC_REGISTER Register) } } +/** + * Reads from the I/O APIC register. + * + * @param Controller + * Supplies the I/O APIC controller to read from. + * + * @param Register + * Supplies the I/O APIC register to read from. + * + * @return This routine returns the value read from the given IO APIC register. + * + * @since XT 1.0 + */ +XTFASTCALL +ULONG +HL::Pic::ReadIOApicRegister(IN PIOAPIC_DATA Controller, + IN UCHAR Register) +{ + /* Write the target address into the index register */ + HL::IoRegister::WriteRegister32((PULONG)(Controller->VirtualAddress + IOAPIC_IOREGSEL), Register); + + /* Fetch the resultant value from the data window */ + return HL::IoRegister::ReadRegister32((PULONG)(Controller->VirtualAddress + IOAPIC_IOWIN)); +} + +/** + * Reads a configuration entry from the I/O APIC redirection table. + * + * @param Controller + * Supplies the I/O APIC controller to read from. + * + * @param EntryNumber + * Supplies the redirection table entry number to read. + * + * @return This routine returns the populated redirection table entry. + * + * @since XT 1.0 + */ +XTFASTCALL +IOAPIC_REDIRECTION_REGISTER +HL::Pic::ReadRedirectionEntry(IN PIOAPIC_DATA Controller, + IN ULONG EntryNumber) +{ + IOAPIC_REDIRECTION_REGISTER Register; + ULONG Offset; + + /* Derive the offset corresponding to the index */ + Offset = IOAPIC_REDTBL + (EntryNumber * IOAPIC_RTE_SIZE); + + /* Read the low and high portions mapping to the 64-bit construct */ + Register.Base = ReadIOApicRegister(Controller, Offset); + Register.Extended = ReadIOApicRegister(Controller, Offset + 1); + + /* Return the redirection table entry */ + return Register; +} + +/** + * Resolves the GSI and flags for the specified IRQ. + * + * @param Irq + * Supplies the IRQ number to get the GSI and flags for. + * + * @param Gsi + * Supplies a pointer to the memory area where the GSI will be stored. + * + * @param Flags + * Supplies a pointer to the memory area where the flags will be stored. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTAPI +VOID +HL::Pic::ResolveInterruptOverride(IN UCHAR Irq, + OUT PULONG Gsi, + OUT PUSHORT Flags) +{ + ULONG Index; + + /* Iterate over all I/O APIC overrides */ + for(Index = 0; Index < IrqOverrideCount; Index++) + { + /* Check if this IRQ has been overridden */ + if(IrqOverrides[Index].SourceIrq == Irq) + { + /* Return overridden GSI and flags */ + *Flags = IrqOverrides[Index].Flags; + *Gsi = IrqOverrides[Index].GlobalSystemInterrupt; + } + } + + /* Return original IRQ number as GSI and no flags */ + *Flags = 0; + *Gsi = (ULONG)Irq; +} + /** * Signals to the APIC that handling an interrupt is complete. * @@ -387,8 +760,8 @@ HL::Pic::SendEoi(VOID) */ XTAPI VOID -HL::Pic::SendIpi(ULONG ApicId, - ULONG Vector) +HL::Pic::SendIpi(IN ULONG ApicId, + IN ULONG Vector) { /* Check current APIC mode */ if(ApicMode == APIC_MODE_X2APIC) @@ -416,7 +789,7 @@ HL::Pic::SendIpi(ULONG ApicId, */ XTAPI VOID -HL::Pic::SendSelfIpi(ULONG Vector) +HL::Pic::SendSelfIpi(IN ULONG Vector) { BOOLEAN Interrupts; @@ -460,6 +833,40 @@ HL::Pic::SendSelfIpi(ULONG Vector) } } +/** + * Translates a given Global System Interrupt (GSI) into an active system interrupt vector. + * + * @param Gsi + * Supplies the GSI to translate. + * + * @return This routine returns the underlying associated system vector mapping. + * + * @since XT 1.0 + */ +XTFASTCALL +UCHAR +HL::Pic::TranslateGsiToVector(IN ULONG Gsi) +{ + IOAPIC_REDIRECTION_REGISTER Register; + PIOAPIC_DATA Controller; + ULONG EntryNumber; + XTSTATUS Status; + + /* Find the APIC controller for the GSI */ + Status = GetIoApicController(Gsi, &Controller, &EntryNumber); + if(Status != STATUS_SUCCESS) + { + /* GSI maps to an invalid controller, return free */ + return IOAPIC_VECTOR_FREE; + } + + /* Read the redirection table entry */ + Register.Base = ReadIOApicRegister(Controller, IOAPIC_REDTBL + (EntryNumber * IOAPIC_RTE_SIZE)); + + /* Return the vector */ + return (UCHAR)Register.Vector; +} + /** * Writes to the APIC register. * @@ -489,3 +896,67 @@ HL::Pic::WriteApicRegister(IN APIC_REGISTER Register, HL::IoRegister::WriteRegister32((PULONG)(APIC_BASE + (Register << 4)), Value); } } + +/** + * Writes a value to the I/O APIC register. + * + * @param Controller + * Supplies the I/O APIC controller to write to. + * + * @param Register + * Supplies the I/O APIC register to write to. + * + * @param DataValue + * Supplies the value to write to the designated I/O APIC register. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTFASTCALL +VOID +HL::Pic::WriteIOApicRegister(IN PIOAPIC_DATA Controller, + IN UCHAR Register, + IN ULONG DataValue) +{ + /* Provide the index to the control port */ + HL::IoRegister::WriteRegister32((PULONG)(Controller->VirtualAddress + IOAPIC_IOREGSEL), Register); + + /* Commit the value via the data port */ + HL::IoRegister::WriteRegister32((PULONG)(Controller->VirtualAddress + IOAPIC_IOWIN), DataValue); +} + +/** + * Writes a configuration entry into the I/O APIC redirection table. + * + * @param Controller + * Supplies the I/O APIC controller to write to. + * + * @param EntryNumber + * Supplies the redirection table entry number to write. + * + * @param EntryData + * Supplies the redirection table entry data to write. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTFASTCALL +VOID +HL::Pic::WriteRedirectionEntry(IN PIOAPIC_DATA Controller, + IN ULONG EntryNumber, + IN IOAPIC_REDIRECTION_REGISTER EntryData) +{ + ULONG Offset; + + /* Calculate the offset of the redirection entry */ + Offset = IOAPIC_REDTBL + (EntryNumber * IOAPIC_RTE_SIZE); + + /* Mask the entry to prevent spurious interrupts */ + WriteIOApicRegister(Controller, Offset, IOAPIC_RTE_MASKED); + + /* Write the lower and upper chunks of the entry */ + WriteIOApicRegister(Controller, Offset + 1, EntryData.Extended); + WriteIOApicRegister(Controller, Offset, EntryData.Base); +} diff --git a/xtoskrnl/includes/hl/pic.hh b/xtoskrnl/includes/hl/pic.hh index 5077ea7..da6578a 100644 --- a/xtoskrnl/includes/hl/pic.hh +++ b/xtoskrnl/includes/hl/pic.hh @@ -19,24 +19,51 @@ namespace HL { private: STATIC APIC_MODE ApicMode; + STATIC ULONG ControllerCount; + STATIC IOAPIC_DATA Controllers[IOAPIC_MAX_CONTROLLERS]; + STATIC ULONG IrqOverrideCount; + STATIC ACPI_MADT_INTERRUPT_OVERRIDE IrqOverrides[IOAPIC_MAX_OVERRIDES]; + STATIC UCHAR MappedVectors[256]; public: STATIC XTAPI VOID ClearApicErrors(VOID); STATIC XTAPI ULONG GetCpuApicId(VOID); + STATIC XTAPI VOID InitializeIOApic(VOID); STATIC XTAPI VOID InitializePic(VOID); STATIC XTFASTCALL ULONGLONG ReadApicRegister(IN APIC_REGISTER Register); STATIC XTAPI VOID SendEoi(VOID); - STATIC XTAPI VOID SendIpi(ULONG ApicId, - ULONG Vector); - STATIC XTAPI VOID SendSelfIpi(ULONG Vector); + STATIC XTAPI VOID SendIpi(IN ULONG ApicId, + IN ULONG Vector); + STATIC XTAPI VOID SendSelfIpi(IN ULONG Vector); STATIC XTFASTCALL VOID WriteApicRegister(IN APIC_REGISTER Register, IN ULONGLONG Value); private: + STATIC XTAPI VOID AllocateSystemInterrupt(IN UCHAR Irq, + IN UCHAR RunLevel, + IN UCHAR Vector); STATIC XTAPI BOOLEAN CheckApicSupport(VOID); STATIC XTAPI BOOLEAN CheckX2ApicSupport(VOID); + STATIC XTAPI XTSTATUS DetectIoApicControllers(VOID); + STATIC XTAPI VOID ResolveInterruptOverride(IN UCHAR Irq, + OUT PULONG Gsi, + OUT PUSHORT Flags); + STATIC XTAPI XTSTATUS GetIoApicController(IN ULONG Gsi, + OUT PIOAPIC_DATA *Controller, + OUT PULONG EntryNumber); STATIC XTAPI VOID InitializeApic(VOID); STATIC XTAPI VOID InitializeLegacyPic(VOID); + STATIC XTFASTCALL ULONG ReadIOApicRegister(IN PIOAPIC_DATA Controller, + IN UCHAR Register); + STATIC XTFASTCALL IOAPIC_REDIRECTION_REGISTER ReadRedirectionEntry(IN PIOAPIC_DATA Controller, + IN ULONG EntryNumber); + STATIC XTFASTCALL UCHAR TranslateGsiToVector(IN ULONG Gsi); + STATIC XTFASTCALL VOID WriteIOApicRegister(IN PIOAPIC_DATA Controller, + IN UCHAR Register, + IN ULONG DataValue); + STATIC XTFASTCALL VOID WriteRedirectionEntry(IN PIOAPIC_DATA Controller, + IN ULONG EntryNumber, + IN IOAPIC_REDIRECTION_REGISTER EntryData); }; }