Add support for I/O APIC controllers and interrupt override handling
This commit is contained in:
@@ -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
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user