Add support for I/O APIC controllers and interrupt override handling
All checks were successful
Builds / ExectOS (amd64, release) (push) Successful in 33s
Builds / ExectOS (amd64, debug) (push) Successful in 35s
Builds / ExectOS (i686, debug) (push) Successful in 31s
Builds / ExectOS (i686, release) (push) Successful in 29s

This commit is contained in:
2026-04-18 00:04:12 +02:00
parent 715419abe7
commit cd4e905054
7 changed files with 652 additions and 7 deletions

View File

@@ -9,6 +9,7 @@
#ifndef __XTDK_AMD64_HLTYPES_H
#define __XTDK_AMD64_HLTYPES_H
#include <xtbase.h>
#include <xtdefs.h>
#include <xtstruct.h>
#include <xttypes.h>
@@ -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
{

View File

@@ -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;

View File

@@ -9,6 +9,7 @@
#ifndef __XTDK_I686_HLTYPES_H
#define __XTDK_I686_HLTYPES_H
#include <xtbase.h>
#include <xtdefs.h>
#include <xtstruct.h>
#include <xttypes.h>
@@ -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
{

View File

@@ -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;

View File

@@ -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;

View File

@@ -9,6 +9,62 @@
#include <xtos.hh>
/**
* 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);
}

View File

@@ -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);
};
}