909 lines
24 KiB
C
909 lines
24 KiB
C
/*++
|
||
|
||
Copyright (c) 1997 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
pmsapic.c
|
||
|
||
Abstract:
|
||
|
||
Implements various SAPIC-ACPI functions.
|
||
|
||
Author:
|
||
|
||
Todd Kjos (Hewlett-Packard) 20-Apr-1998
|
||
|
||
Based on I386 version of pmapic.c:
|
||
Jake Oshins (jakeo) 19-May-1997
|
||
|
||
Environment:
|
||
|
||
Kernel mode only.
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "halp.h"
|
||
#include "acpitabl.h"
|
||
#include "iosapic.h"
|
||
#include "xxacpi.h"
|
||
#include "ixsleep.h"
|
||
|
||
PMAPIC HalpApicTable;
|
||
|
||
struct _IOAPIC_DEBUG_TABLE
|
||
{
|
||
PIO_INTR_CONTROL IoIntrControl;
|
||
PIO_SAPIC_REGS IoSapicRegs;
|
||
|
||
} *HalpApicDebugAddresses;
|
||
|
||
ULONG
|
||
DetectAcpiMP(
|
||
OUT PBOOLEAN IsConfiguredMp,
|
||
IN PLOADER_PARAMETER_BLOCK LoaderBlock
|
||
);
|
||
|
||
VOID
|
||
HalpInitMPInfo(
|
||
IN PLOADER_PARAMETER_BLOCK LoaderBlock,
|
||
IN PMAPIC ApicTable
|
||
);
|
||
|
||
BOOLEAN
|
||
HalpVerifyIoSapic(
|
||
IN PUCHAR BaseAddress
|
||
);
|
||
VOID
|
||
HalpSaveInterruptControllerState(
|
||
VOID
|
||
);
|
||
|
||
VOID
|
||
HalpRestoreInterruptControllerState(
|
||
VOID
|
||
);
|
||
|
||
VOID
|
||
HalpSetInterruptControllerWakeupState(
|
||
ULONG Context
|
||
);
|
||
|
||
VOID
|
||
HalpSetCPEVectorState(
|
||
IN ULONG GlobalInterrupt,
|
||
IN UCHAR SapicVector,
|
||
IN USHORT DestinationCPU,
|
||
IN ULONG Flags
|
||
);
|
||
|
||
VOID
|
||
HalpProcessLocalSapic(
|
||
IN PLOADER_PARAMETER_BLOCK LoaderBlock,
|
||
IN PPROCLOCALSAPIC ProcLocalSapic
|
||
);
|
||
|
||
VOID
|
||
HalpProcessIoSapic(
|
||
IN PLOADER_PARAMETER_BLOCK LoaderBlock,
|
||
IN PIOSAPIC IoSapic
|
||
);
|
||
|
||
VOID
|
||
HalpProcessIsaVector(
|
||
IN PLOADER_PARAMETER_BLOCK LoaderBlock,
|
||
IN PISA_VECTOR IsaVector
|
||
);
|
||
|
||
VOID
|
||
HalpProcessPlatformInt(
|
||
IN PLOADER_PARAMETER_BLOCK LoaderBlock,
|
||
IN PPLATFORM_INTERRUPT PlatformInt
|
||
);
|
||
|
||
extern UCHAR rgzNoApicTable[];
|
||
extern UCHAR rgzNoApic[];
|
||
extern UCHAR rgzApicNotVerified[];
|
||
extern ULONG HalpPicVectorRedirect[];
|
||
|
||
struct _MPINFO HalpMpInfo;
|
||
extern ULONG HalpPicVectorFlags[];
|
||
extern ULONG HalpIpiClock;
|
||
extern BOOLEAN HalpHiberInProgress;
|
||
|
||
// from pmdata.c: CPE related.
|
||
extern ULONG HalpCPEIntIn[];
|
||
extern USHORT HalpCPEDestination[];
|
||
extern ULONG HalpCPEVectorFlags[];
|
||
extern UCHAR HalpCPEIoSapicVector[];
|
||
extern ULONG HalpMaxCPEImplemented;
|
||
|
||
BOOLEAN HalpPicStateIntact = TRUE;
|
||
|
||
PIO_INTR_CONTROL HalpIoSapicList = NULL;
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(INIT, DetectAcpiMP)
|
||
#pragma alloc_text(INIT, HalpInitMPInfo)
|
||
#pragma alloc_text(INIT, HalpProcessLocalSapic)
|
||
#pragma alloc_text(INIT, HalpProcessIoSapic)
|
||
#pragma alloc_text(INIT, HalpProcessIsaVector)
|
||
#pragma alloc_text(INIT, HalpProcessPlatformInt)
|
||
#pragma alloc_text(PAGELK, HalpVerifyIoSapic)
|
||
#pragma alloc_text(PAGELK, HalpSaveInterruptControllerState)
|
||
#pragma alloc_text(PAGELK, HalpRestoreInterruptControllerState)
|
||
#pragma alloc_text(PAGELK, HalpSetInterruptControllerWakeupState)
|
||
#pragma alloc_text(PAGELK, HalpAcpiPicStateIntact)
|
||
#endif
|
||
|
||
|
||
ULONG
|
||
DetectAcpiMP(
|
||
OUT PBOOLEAN IsConfiguredMp,
|
||
IN PLOADER_PARAMETER_BLOCK LoaderBlock
|
||
)
|
||
{
|
||
UCHAR ApicVersion, index, processorNumber;
|
||
PUCHAR LocalApic;
|
||
NTSTATUS status;
|
||
|
||
//
|
||
// Make sure there is an SAPIC Table
|
||
//
|
||
|
||
HalpApicTable = HalpGetAcpiTablePhase0(LoaderBlock, APIC_SIGNATURE);
|
||
|
||
if (HalpApicTable == NULL) {
|
||
HalDisplayString(rgzNoApicTable);
|
||
KeBugCheckEx(ACPI_BIOS_ERROR, 0x11, 10, 0, 0);
|
||
return(FALSE);
|
||
}
|
||
|
||
HalDebugPrint(( HAL_INFO, "HAL: Found a MADT table at %p\n", HalpApicTable ));
|
||
|
||
HalDebugPrint(( HAL_INFO, "HAL: Signature: %x Length: %x\n",
|
||
HalpApicTable->Header.Signature,
|
||
HalpApicTable->Header.Length ));
|
||
|
||
HalDebugPrint(( HAL_INFO, "HAL: OEMID: %s\n", HalpApicTable->Header.OEMID ));
|
||
|
||
// We have a SAPIC table. Initialize the interrupt info structure
|
||
|
||
HalpInitMPInfo(LoaderBlock, HalpApicTable);
|
||
|
||
if (HalpMpInfo.IoSapicCount == 0) {
|
||
//
|
||
// There are no IO Sapics.
|
||
//
|
||
// Should we allow this case on the theory that
|
||
// that all the interrupts are connected to LINTx pins on the CPU?
|
||
//
|
||
HalDebugPrint(( HAL_ERROR, rgzNoApic ));
|
||
return (FALSE);
|
||
}
|
||
|
||
if (HalpMpInfo.ProcessorCount == 0) {
|
||
|
||
KeBugCheckEx(ACPI_BIOS_ERROR, 0x11, 11, 0, 0);
|
||
}
|
||
|
||
//
|
||
// Initialize NtProcessorNumber in the order that we are going to process
|
||
// them in HalStartNextProcessor. The BSP is 0 and the rest are numbered
|
||
// in the order the Local SAPICs appear in the MADT starting at 1.
|
||
//
|
||
|
||
processorNumber = 1;
|
||
for (index = 0; index < HalpMpInfo.ProcessorCount; index++) {
|
||
|
||
if (HalpProcessorInfo[index].LocalApicID == (USHORT)PCR->HalReserved[PROCESSOR_ID_INDEX]) {
|
||
|
||
HalpProcessorInfo[index].NtProcessorNumber = 0;
|
||
|
||
} else {
|
||
|
||
HalpProcessorInfo[index].NtProcessorNumber = processorNumber++;
|
||
}
|
||
}
|
||
|
||
*IsConfiguredMp = (HalpMpInfo.ProcessorCount > 1 ? TRUE : FALSE);
|
||
return TRUE;
|
||
}
|
||
|
||
#define IO_SAPIC_REGS_SIZE 4096
|
||
|
||
|
||
VOID
|
||
HalpInitMPInfo(
|
||
IN PLOADER_PARAMETER_BLOCK LoaderBlock,
|
||
IN PMAPIC ApicTable
|
||
)
|
||
/*++
|
||
Routine Description:
|
||
This routine initializes a HAL specific data structure that is
|
||
used by the HAL to simplify access to MP information.
|
||
|
||
Arguments:
|
||
SapicTable Pointer to the SAPIC table.
|
||
|
||
Return Value:
|
||
None
|
||
|
||
*/
|
||
{
|
||
PAPICTABLE TablePtr;
|
||
ULONG i;
|
||
|
||
HalpMpInfo.ProcessorCount = 0;
|
||
HalpMpInfo.IoSapicCount = 0;
|
||
|
||
// Walk the Multiple Apic table...
|
||
|
||
TablePtr = (PAPICTABLE) ApicTable->APICTables;
|
||
|
||
// Loop ends when TraversePtr is off the end of the table...
|
||
while ((UINT_PTR)TablePtr <
|
||
((UINT_PTR)ApicTable + ApicTable->Header.Length)) {
|
||
|
||
if (TablePtr->Type == LOCAL_SAPIC) {
|
||
|
||
HalpProcessLocalSapic(LoaderBlock, (PPROCLOCALSAPIC)TablePtr);
|
||
|
||
} else if (TablePtr->Type == IO_SAPIC) {
|
||
|
||
HalpProcessIoSapic(LoaderBlock, (PIOSAPIC)TablePtr);
|
||
|
||
} else if (TablePtr->Type == ISA_VECTOR_OVERRIDE) {
|
||
|
||
HalpProcessIsaVector(LoaderBlock, (PISA_VECTOR)TablePtr);
|
||
|
||
} else if (TablePtr->Type == PLATFORM_INTERRUPT_SOURCE) {
|
||
|
||
HalpProcessPlatformInt(LoaderBlock, (PPLATFORM_INTERRUPT)TablePtr);
|
||
|
||
} else {
|
||
|
||
HalDebugPrint(( HAL_ERROR, "HAL: Processing MADT - Skip Table %p: Type = %d, Length = %d\n", TablePtr, TablePtr->Type, TablePtr->Length ));
|
||
}
|
||
|
||
(UINT_PTR)TablePtr += TablePtr->Length;
|
||
}
|
||
//
|
||
// Check if there is Interrupt Source Override entry. If there is, force the
|
||
// new flags into the SAPIC state. This is done now because of the possibility
|
||
// the firmware can place the ISO Vector Override entry ahead of IOSAPIC entry.
|
||
//
|
||
for (i = 0; i < PIC_VECTORS; i++) {
|
||
if (HalpPicVectorFlags[i]) {
|
||
HaliSetVectorState( HalpPicVectorRedirect[i],
|
||
HalpPicVectorFlags[i]
|
||
);
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
VOID
|
||
HalpProcessLocalSapic(
|
||
IN PLOADER_PARAMETER_BLOCK LoaderBlock,
|
||
IN PPROCLOCALSAPIC ProcLocalSapic
|
||
)
|
||
{
|
||
USHORT LID;
|
||
ULONG ProcessorNum;
|
||
|
||
if (ProcLocalSapic->Length != PROCESSOR_LOCAL_SAPIC_LENGTH) {
|
||
HalDebugPrint(( HAL_ERROR,
|
||
"HAL: HalpProcessLocalSapic - Invalid Length %p: Expected %d, Found %d\n",
|
||
ProcLocalSapic,
|
||
PROCESSOR_LOCAL_SAPIC_LENGTH,
|
||
ProcLocalSapic->Length ));
|
||
return;
|
||
}
|
||
|
||
// Make sure processor is enabled...
|
||
if (!(ProcLocalSapic->Flags & PLAF_ENABLED)) {
|
||
|
||
return;
|
||
}
|
||
|
||
// It is. Bump the count and store the LID value for IPIs
|
||
|
||
LID = (ProcLocalSapic->APICID << 8) | ProcLocalSapic->APICEID;
|
||
|
||
HalpProcessorInfo[HalpMpInfo.ProcessorCount].AcpiProcessorID = ProcLocalSapic->ACPIProcessorID;
|
||
HalpProcessorInfo[HalpMpInfo.ProcessorCount].LocalApicID = LID;
|
||
|
||
HalpMpInfo.ProcessorCount++;
|
||
|
||
HalDebugPrint(( HAL_INFO,
|
||
"HAL: Found a processor-local SAPIC: %p LID=%x\n",
|
||
ProcLocalSapic,
|
||
LID ));
|
||
}
|
||
|
||
VOID
|
||
HalpProcessIoSapic(
|
||
IN PLOADER_PARAMETER_BLOCK LoaderBlock,
|
||
IN PIOSAPIC IoSapic
|
||
)
|
||
{
|
||
ULONG IntiBase,RedirEntries;
|
||
PHYSICAL_ADDRESS IoSapicPhys;
|
||
PVOID IoSapicBase;
|
||
UINT_PTR IoSapicPhysBase;
|
||
PIO_SAPIC_REGS SapicRegs;
|
||
PIO_INTR_CONTROL IoIntrControl;
|
||
ULONG i;
|
||
|
||
union {
|
||
ULONG raw;
|
||
SAPIC_VERSION version;
|
||
} versionUnion;
|
||
|
||
if (IoSapic->Length != IO_SAPIC_LENGTH) {
|
||
|
||
HalDebugPrint(( HAL_ERROR,
|
||
"HAL: HalpProcessIoSapic - Invalid Length %p: Expected %d, Found %d\n",
|
||
IoSapic,
|
||
IO_SAPIC_LENGTH,
|
||
IoSapic->Length ));
|
||
|
||
return;
|
||
}
|
||
|
||
HalDebugPrint(( HAL_INFO, "HAL: Found an IO SAPIC: %p\n", IoSapic ));
|
||
|
||
// Map IO Sapic Registers...
|
||
IntiBase = IoSapic->SystemVectorBase;
|
||
IoSapicPhysBase = IoSapic->IOSAPICAddress;
|
||
IoSapicPhys.QuadPart = (UINT_PTR)IoSapicPhysBase;
|
||
IoSapicBase = HalpMapPhysicalMemory( IoSapicPhys,
|
||
ADDRESS_AND_SIZE_TO_SPAN_PAGES(IoSapicPhys.LowPart, IO_SAPIC_REGS_SIZE),
|
||
MmNonCached);
|
||
ASSERT(IoSapicBase);
|
||
|
||
SapicRegs = (PIO_SAPIC_REGS)IoSapicBase;
|
||
|
||
if (!SapicRegs) {
|
||
HalDebugPrint(( HAL_ERROR, "HAL: Couldn't map the I/O Sapic\n" ));
|
||
return;
|
||
}
|
||
|
||
// Read the IO Sapic version and extract the number of redirection table entries
|
||
SapicRegs->RegisterSelect = IO_VERS_REGISTER;
|
||
SapicRegs->RegisterWindow = 0;
|
||
versionUnion.raw = SapicRegs->RegisterWindow;
|
||
|
||
//
|
||
// CPQMOD_JL001 - Incorrect count - hw provide max rte index not
|
||
// count.
|
||
//
|
||
//RedirEntries = versionUnion.version.MaxRedirEntries;
|
||
RedirEntries = versionUnion.version.MaxRedirEntries + 1;
|
||
|
||
if (HalpVerifyIoSapic((PUCHAR)SapicRegs)) {
|
||
|
||
// Allocate and fill out a IO Sapic structure
|
||
PHYSICAL_ADDRESS physicalAddress;
|
||
|
||
physicalAddress.QuadPart = (LONGLONG)HalpAllocPhysicalMemory(
|
||
LoaderBlock,
|
||
~0,
|
||
BYTES_TO_PAGES(sizeof(IO_INTR_CONTROL) + (RedirEntries*sizeof(IOSAPICINTI))),
|
||
FALSE );
|
||
|
||
if (physicalAddress.QuadPart == 0) {
|
||
HalDebugPrint(( HAL_ERROR, "HAL: Couldn't allocate memory for the IO Sapic structures\n" ));
|
||
return;
|
||
}
|
||
|
||
IoIntrControl = (PIO_INTR_CONTROL)HalpMapPhysicalMemory(
|
||
physicalAddress,
|
||
ADDRESS_AND_SIZE_TO_SPAN_PAGES(physicalAddress.LowPart, sizeof(IO_INTR_CONTROL) + (RedirEntries*sizeof(IOSAPICINTI))),
|
||
MmCached );
|
||
|
||
ASSERT(IoIntrControl);
|
||
|
||
IoIntrControl->IntiBase = IntiBase;
|
||
IoIntrControl->IntiMax = IntiBase + RedirEntries - 1;
|
||
IoIntrControl->RegBaseVirtual = IoSapicBase;
|
||
IoIntrControl->RegBasePhysical = IoSapicPhys;
|
||
IoIntrControl->IntrMethods = &HalpIoSapicMethods;
|
||
IoIntrControl->InterruptAffinity = 0xffffffff;
|
||
IoIntrControl->NextCpu = 0;
|
||
IoIntrControl->flink = NULL;
|
||
|
||
for (i = 0; i < RedirEntries; i++) {
|
||
IoIntrControl->Inti[i].Vector =
|
||
DELIVER_FIXED | ACTIVE_LOW | LEVEL_TRIGGERED;
|
||
IoIntrControl->Inti[i].Destination = 0;
|
||
IoIntrControl->Inti[i].GlobalVector = 0;
|
||
|
||
//
|
||
// CPQMOD_JL002 - Fix for using the rte and not the
|
||
// SystemVector.
|
||
//
|
||
//IoIntrControl->IntrMethods->MaskEntry(IoIntrControl,IntiBase+i);
|
||
IoIntrControl->IntrMethods->MaskEntry(IoIntrControl,i);
|
||
}
|
||
|
||
// Insert structure into list. Since we are running on P0 at
|
||
// Phase0 initialization, we can assume that no one else is
|
||
// modifying this list therefore no synchronization is needed.
|
||
if (HalpIoSapicList == NULL) {
|
||
HalpIoSapicList = IoIntrControl;
|
||
} else {
|
||
PIO_INTR_CONTROL *LastLink;
|
||
PIO_INTR_CONTROL IoSapicListEntry;
|
||
LastLink = &HalpIoSapicList;
|
||
IoSapicListEntry = HalpIoSapicList;
|
||
while (IoSapicListEntry != NULL) {
|
||
|
||
if (IoSapicListEntry->IntiBase > IoIntrControl->IntiMax) {
|
||
// Insert new entry before current entry
|
||
IoIntrControl->flink = *LastLink;
|
||
*LastLink = IoIntrControl;
|
||
break;
|
||
} else {
|
||
LastLink = &IoSapicListEntry->flink;
|
||
IoSapicListEntry = IoSapicListEntry->flink;
|
||
}
|
||
}
|
||
if (IoSapicListEntry == NULL) {
|
||
// We got to the end of the list. The new entry goes
|
||
// after the last entry...
|
||
*LastLink = IoIntrControl;
|
||
}
|
||
}
|
||
|
||
HalpMpInfo.IoSapicCount++;
|
||
|
||
} else {
|
||
// The Io Sapic is not there, ignore this entry in the table
|
||
HalDebugPrint(( HAL_ERROR, rgzApicNotVerified ));
|
||
HalpUnmapVirtualAddress(IoSapicBase, ADDRESS_AND_SIZE_TO_SPAN_PAGES(IoSapicBase, IO_SAPIC_REGS_SIZE));
|
||
}
|
||
}
|
||
|
||
VOID
|
||
HalpProcessIsaVector(
|
||
IN PLOADER_PARAMETER_BLOCK LoaderBlock,
|
||
IN PISA_VECTOR IsaVector
|
||
)
|
||
{
|
||
if (IsaVector->Length != ISA_VECTOR_OVERRIDE_LENGTH) {
|
||
|
||
HalDebugPrint(( HAL_ERROR,
|
||
"HAL: HalpProcessIsaVector - Invalid Length %p: Expected %d, Found %d\n",
|
||
IsaVector,
|
||
ISA_VECTOR_OVERRIDE_LENGTH,
|
||
IsaVector->Length ));
|
||
|
||
return;
|
||
}
|
||
|
||
//
|
||
// Found an ISA vector redirection entry.
|
||
//
|
||
|
||
HalpPicVectorRedirect[IsaVector->Source] =
|
||
IsaVector->GlobalSystemInterruptVector;
|
||
|
||
HalpPicVectorFlags[IsaVector->Source] = IsaVector->Flags;
|
||
|
||
HalDebugPrint(( HAL_INFO, "HAL: Found an ISA VECTOR: %p, %x -> %x, flags: %x\n",
|
||
IsaVector,
|
||
IsaVector->Source,
|
||
IsaVector->GlobalSystemInterruptVector,
|
||
IsaVector->Flags ));
|
||
}
|
||
|
||
VOID
|
||
HalpProcessPlatformInt(
|
||
IN PLOADER_PARAMETER_BLOCK LoaderBlock,
|
||
IN PPLATFORM_INTERRUPT PlatformInt
|
||
)
|
||
{
|
||
static ULONG currentCPECount = 0;
|
||
|
||
if (PlatformInt->Length != PLATFORM_INTERRUPT_SOURCE_LENGTH) {
|
||
|
||
HalDebugPrint(( HAL_ERROR,
|
||
"HAL: HalpProcessPlatformInt - Invalid Length %p: Expected %d, Found %d\n",
|
||
PlatformInt,
|
||
PLATFORM_INTERRUPT_SOURCE_LENGTH,
|
||
PlatformInt->Length ));
|
||
|
||
return;
|
||
}
|
||
|
||
//
|
||
// Process a Corrected Platform Error Interrupt Source structure.
|
||
//
|
||
|
||
if (PlatformInt->InterruptType == PLATFORM_INT_CPE) {
|
||
|
||
|
||
//
|
||
// Does this platform has more (than what we expected) number of CPE sources?
|
||
//
|
||
|
||
if ( currentCPECount >= HALP_CPE_MAX_INTERRUPT_SOURCES ) {
|
||
|
||
HalDebugPrint(( HAL_ERROR,
|
||
"HAL: Platform Interrupt Source %p skipped due to overflow: %ld >= HALP_CPE_MAX_INTERRUPT_SOURCES\n", PlatformInt, currentCPECount ));
|
||
|
||
return;
|
||
}
|
||
|
||
//
|
||
// Save the input pin number of SAPIC for this CPE source
|
||
//
|
||
|
||
HalpCPEIntIn[currentCPECount] = (ULONG)PlatformInt->GlobalVector;
|
||
|
||
//
|
||
// Save the Flags for this CPE source
|
||
//
|
||
|
||
HalpCPEVectorFlags[currentCPECount] = (ULONG)PlatformInt->Flags;
|
||
|
||
//
|
||
// Save the IO Sapic Vector (that BIOS expects OS to use) for this platform CMC source
|
||
//
|
||
|
||
HalpCPEIoSapicVector[currentCPECount] = (UCHAR)PlatformInt->IOSAPICVector;
|
||
|
||
// Thierry - WARNING - 09/19/2000
|
||
// NT HAL ignores the IO SAPIC vector field for the platform interrupt sources.
|
||
// NT imposes the CPEI_VECTOR value for Corrected Machine Errors interrupt vector, for all
|
||
// the destination processors. Actually, the current default is to attach all the processors
|
||
// IDT[CPEI_VECTOR] with the HAL default ISR - HalpCPEIHandler for the CPE interrupt model.
|
||
// We will connect the ISR only for the destination processors after testing if judged valid.
|
||
// The rationales are:
|
||
// - IOSAPICVector was mostly added in the specs by Intel for IA64 PMI interrupt sources.
|
||
// These PMI interrupts are not visible by NT.
|
||
// - NT has no infrastructure at this time to support vector registration for FW/chipset
|
||
// generated external interrupts visible to NT.
|
||
// - Having the FW specifying the vector requires the HAL to control the specified
|
||
// value with its current IDT[] related resources usage and defines actions in case
|
||
// of conficts.
|
||
//
|
||
|
||
HalDebugPrint(( HAL_INFO, "HAL: CPE source VECTOR: %x. HAL imposes VECTOR: %x\n",
|
||
HalpCPEIoSapicVector[currentCPECount],
|
||
CPEI_VECTOR ));
|
||
HalpCPEIoSapicVector[currentCPECount] = (UCHAR)(CPEI_VECTOR);
|
||
|
||
//
|
||
// Save the Destination Processor (that BIOS expects OS to use) for this CPE source)
|
||
//
|
||
|
||
HalpCPEDestination[currentCPECount] = (USHORT)(
|
||
(PlatformInt->APICID << 8) | PlatformInt->ACPIEID);
|
||
|
||
//
|
||
// Force the flags into the SAPIC state
|
||
//
|
||
|
||
HalpSetCPEVectorState( HalpCPEIntIn[currentCPECount],
|
||
HalpCPEIoSapicVector[currentCPECount],
|
||
HalpCPEDestination[currentCPECount],
|
||
HalpCPEVectorFlags[currentCPECount]
|
||
);
|
||
|
||
|
||
HalDebugPrint(( HAL_INFO, "HAL: Found an Platform Interrupt VECTOR: %p, %x -> %x, flags: %x\n",
|
||
PlatformInt,
|
||
PlatformInt->IOSAPICVector,
|
||
PlatformInt->GlobalVector,
|
||
PlatformInt->Flags ));
|
||
|
||
//
|
||
// Keep track of how many CPE sources are implemented in the platform.
|
||
//
|
||
|
||
HalpMaxCPEImplemented = ++currentCPECount;
|
||
|
||
}
|
||
else if ( ( PlatformInt->InterruptType == PLATFORM_INT_PMI ) ||
|
||
( PlatformInt->InterruptType == PLATFORM_INT_INIT ) ) {
|
||
|
||
HalpWriteRedirEntry( PlatformInt->GlobalVector,
|
||
PlatformInt->IOSAPICVector,
|
||
(USHORT)((PlatformInt->APICID <<8) | PlatformInt->ACPIEID),
|
||
PlatformInt->Flags,
|
||
PlatformInt->InterruptType
|
||
);
|
||
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
BOOLEAN
|
||
HalpVerifyIoSapic(
|
||
IN PUCHAR BaseAddress
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Verify that an IO Sapic Unit exists at the specified address
|
||
|
||
Arguments:
|
||
|
||
BaseAddress - Virtual address of the IO Unit to test.
|
||
|
||
Return Value:
|
||
BOOLEAN - TRUE if a IO Unit was found at the passed address
|
||
- FALSE otherwise
|
||
|
||
--*/
|
||
|
||
{
|
||
union SapicUnion {
|
||
ULONG Raw;
|
||
struct SapicVersion Ver;
|
||
} Temp1, Temp2;
|
||
|
||
PIO_SAPIC_REGS IoUnitPtr = (PIO_SAPIC_REGS) BaseAddress;
|
||
|
||
//
|
||
// The documented detection mechanism is to write all zeros to
|
||
// the Version register. Then read it back. The IO Unit exists if the
|
||
// same result is read both times and the Version is valid.
|
||
//
|
||
|
||
IoUnitPtr->RegisterSelect = IO_VERS_REGISTER;
|
||
IoUnitPtr->RegisterWindow = 0;
|
||
|
||
IoUnitPtr->RegisterSelect = IO_VERS_REGISTER;
|
||
Temp1.Raw = IoUnitPtr->RegisterWindow;
|
||
|
||
IoUnitPtr->RegisterSelect = IO_VERS_REGISTER;
|
||
IoUnitPtr->RegisterWindow = 0;
|
||
|
||
IoUnitPtr->RegisterSelect = IO_VERS_REGISTER;
|
||
Temp2.Raw = IoUnitPtr->RegisterWindow;
|
||
|
||
if ( Temp1.Raw == 0 ||
|
||
(Temp1.Ver.Version != Temp2.Ver.Version) ||
|
||
(Temp1.Ver.MaxRedirEntries != Temp2.Ver.MaxRedirEntries)) {
|
||
//
|
||
// No IO Unit There
|
||
//
|
||
HalDebugPrint(( HAL_ERROR, "HAL: No IoSapic at %I64x\n", BaseAddress ));
|
||
return (FALSE);
|
||
}
|
||
|
||
HalDebugPrint(( HAL_INFO, "HAL: IoSapic found at %I64x, Max Entries = %d\n", BaseAddress, Temp1.Ver.MaxRedirEntries ));
|
||
|
||
return (TRUE);
|
||
}
|
||
|
||
VOID
|
||
HalpInitApicDebugMappings(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called at the very beginning of phase 1 initialization.
|
||
It creates mappings for the APICs using MmMapIoSpace. This will allow
|
||
us to access their registers from the debugger.
|
||
|
||
A much better solution would be to allow us to describe our memory usage to
|
||
MM but ....
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
--*/
|
||
{
|
||
PHYSICAL_ADDRESS physicalAddress;
|
||
PIO_INTR_CONTROL IoIntrControl;
|
||
ULONG index;
|
||
|
||
if (HalpMpInfo.IoSapicCount == 0) {
|
||
|
||
//
|
||
// I doubt this machine is going to get very far without IOAPICs
|
||
// but there is certainly nothing for this routine to do.
|
||
|
||
return;
|
||
}
|
||
|
||
ASSERT(HalpApicDebugAddresses == NULL);
|
||
|
||
HalpApicDebugAddresses = ExAllocatePool(NonPagedPool,
|
||
HalpMpInfo.IoSapicCount * sizeof(*HalpApicDebugAddresses));
|
||
|
||
if (HalpApicDebugAddresses == NULL) {
|
||
|
||
return;
|
||
}
|
||
|
||
IoIntrControl = HalpIoSapicList;
|
||
|
||
for (index = 0; index < HalpMpInfo.IoSapicCount; index++) {
|
||
|
||
if (IoIntrControl != NULL) {
|
||
|
||
if (HalpVirtualToPhysical((ULONG_PTR)IoIntrControl, &physicalAddress)) {
|
||
|
||
HalpApicDebugAddresses[index].IoIntrControl =
|
||
MmMapIoSpace(physicalAddress,
|
||
sizeof(IO_INTR_CONTROL) +
|
||
(IoIntrControl->IntiMax - IoIntrControl->IntiBase + 1) * sizeof(IOSAPICINTI),
|
||
MmCached
|
||
);
|
||
}
|
||
|
||
HalpApicDebugAddresses[index].IoSapicRegs =
|
||
MmMapIoSpace(IoIntrControl->RegBasePhysical,
|
||
IO_SAPIC_REGS_SIZE,
|
||
MmNonCached
|
||
);
|
||
|
||
IoIntrControl = IoIntrControl->flink;
|
||
|
||
} else {
|
||
|
||
HalpApicDebugAddresses[index].IoIntrControl = NULL;
|
||
HalpApicDebugAddresses[index].IoSapicRegs = NULL;
|
||
}
|
||
}
|
||
}
|
||
|
||
VOID
|
||
HalpSaveInterruptControllerState(
|
||
VOID
|
||
)
|
||
{
|
||
HalDebugPrint(( HAL_ERROR, "HAL: HalpSaveInterruptControllerState - not yet implemented\n"));
|
||
|
||
HalpHiberInProgress = TRUE;
|
||
}
|
||
|
||
VOID
|
||
HalpRestoreInterruptControllerState(
|
||
VOID
|
||
)
|
||
{
|
||
//
|
||
// Restore the IO APIC state
|
||
//
|
||
HalDebugPrint(( HAL_ERROR, "HAL: HalpRestoreInterruptControllerState - not yet implemented\n"));
|
||
|
||
HalpPicStateIntact = TRUE;
|
||
}
|
||
|
||
VOID
|
||
HalpSetInterruptControllerWakeupState(
|
||
ULONG Context
|
||
)
|
||
{
|
||
HalDebugPrint(( HAL_FATAL_ERROR, "HAL: HalpSetInterruptControllerWakeupState - not yet implemented\n"));
|
||
|
||
KeBugCheckEx(HAL_INITIALIZATION_FAILED, 0, 0, 0 , 0);
|
||
}
|
||
|
||
BOOLEAN
|
||
HalpAcpiPicStateIntact(
|
||
VOID
|
||
)
|
||
{
|
||
return HalpPicStateIntact;
|
||
}
|
||
|
||
|
||
ULONG
|
||
HalpAcpiNumProcessors(
|
||
VOID
|
||
)
|
||
{
|
||
return HalpMpInfo.ProcessorCount;
|
||
}
|
||
|
||
|
||
VOID
|
||
HalpMaskAcpiInterrupt(
|
||
VOID
|
||
)
|
||
{
|
||
ULONG inti;
|
||
KAFFINITY affinity;
|
||
ULONG sciVector = HalpFixedAcpiDescTable.sci_int_vector;
|
||
|
||
if (sciVector < PIC_VECTORS) {
|
||
sciVector = HalpPicVectorRedirect[sciVector];
|
||
}
|
||
|
||
HalpGetSapicInterruptDesc(
|
||
Internal,
|
||
0,
|
||
sciVector,
|
||
&inti,
|
||
&affinity
|
||
);
|
||
|
||
HalpDisableRedirEntry(inti);
|
||
|
||
}
|
||
|
||
VOID
|
||
HalpUnmaskAcpiInterrupt(
|
||
VOID
|
||
)
|
||
{
|
||
ULONG inti;
|
||
KAFFINITY affinity;
|
||
|
||
ULONG sciVector = HalpFixedAcpiDescTable.sci_int_vector;
|
||
|
||
if (sciVector < PIC_VECTORS) {
|
||
sciVector = HalpPicVectorRedirect[sciVector];
|
||
}
|
||
|
||
HalpGetSapicInterruptDesc(
|
||
Internal,
|
||
0,
|
||
sciVector,
|
||
&inti,
|
||
&affinity
|
||
);
|
||
|
||
HalpEnableRedirEntry(inti);
|
||
}
|
||
|
||
NTSTATUS
|
||
HalpGetApicIdByProcessorNumber(
|
||
IN UCHAR Processor,
|
||
IN OUT USHORT *ApicId
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function returns an APIC ID for a given processor.
|
||
|
||
Arguments:
|
||
|
||
Processor - The logical processor number that is
|
||
associated with this APIC ID.
|
||
|
||
ApicId - pointer to a value to fill in with the APIC ID.
|
||
|
||
Return Value:
|
||
|
||
Status.
|
||
|
||
--*/
|
||
{
|
||
ULONG index;
|
||
|
||
for (index = 0; index < HalpMpInfo.ProcessorCount; index++) {
|
||
|
||
if (HalpProcessorInfo[index].NtProcessorNumber == Processor) {
|
||
|
||
//
|
||
// Return the APIC ID, Extended APIC ID for this
|
||
// processor.
|
||
//
|
||
|
||
*ApicId = HalpProcessorInfo[index].LocalApicID;
|
||
|
||
return STATUS_SUCCESS;
|
||
}
|
||
}
|
||
|
||
return STATUS_NOT_FOUND;
|
||
}
|