You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
866 lines
22 KiB
866 lines
22 KiB
/*++
|
|
|
|
Copyright (c) 1997 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
pmapic.c
|
|
|
|
Abstract:
|
|
|
|
Implements various APIC-ACPI functions.
|
|
|
|
Author:
|
|
|
|
Jake Oshins (jakeo) 19-May-1997
|
|
|
|
Environment:
|
|
|
|
Kernel mode only.
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "halp.h"
|
|
#include "acpitabl.h"
|
|
#include "apic.inc"
|
|
#include "xxacpi.h"
|
|
#include "ixsleep.h"
|
|
|
|
#ifdef DEBUGGING
|
|
#include "string.h"
|
|
#include "stdlib.h"
|
|
#include "stdio.h"
|
|
#endif
|
|
|
|
ULONG
|
|
DetectAcpiMP (
|
|
OUT PBOOLEAN IsConfiguredMp,
|
|
IN PLOADER_PARAMETER_BLOCK LoaderBlock
|
|
);
|
|
|
|
VOID
|
|
HalpInitMpInfo (
|
|
IN PMAPIC ApicTable,
|
|
IN ULONG Phase
|
|
);
|
|
|
|
BOOLEAN
|
|
HalpVerifyIOUnit(
|
|
IN PUCHAR BaseAddress
|
|
);
|
|
|
|
VOID
|
|
HalpMaskAcpiInterrupt(
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
HalpUnmaskAcpiInterrupt(
|
|
VOID
|
|
);
|
|
|
|
extern UCHAR rgzNoApicTable[];
|
|
extern UCHAR rgzNoApic[];
|
|
extern UCHAR rgzBadApicVersion[];
|
|
extern UCHAR rgzApicNotVerified[];
|
|
|
|
extern UCHAR HalpIRQLtoTPR[];
|
|
extern UCHAR HalpVectorToIRQL[];
|
|
extern ULONG HalpPicVectorRedirect[];
|
|
extern ULONG HalpPicVectorFlags[];
|
|
extern USHORT HalpMaxApicInti[];
|
|
extern UCHAR HalpIoApicId[];
|
|
extern ULONG HalpIpiClock;
|
|
extern PVOID *HalpLocalNmiSources;
|
|
|
|
ULONG HalpIOApicVersion[MAX_IOAPICS];
|
|
|
|
extern BOOLEAN HalpHiberInProgress;
|
|
|
|
BOOLEAN HalpPicStateIntact = TRUE;
|
|
UCHAR HalpMaxProcs = 0;
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(INIT, DetectAcpiMP)
|
|
#pragma alloc_text(PAGELK, HalpInitMpInfo)
|
|
#pragma alloc_text(PAGELK, HalpVerifyIOUnit)
|
|
#pragma alloc_text(PAGELK, HalpSaveInterruptControllerState)
|
|
#pragma alloc_text(PAGELK, HalpRestoreInterruptControllerState)
|
|
#pragma alloc_text(PAGELK, HalpSetInterruptControllerWakeupState)
|
|
#pragma alloc_text(PAGELK, HalpAcpiPicStateIntact)
|
|
#pragma alloc_text(PAGELK, HalpGetApicVersion)
|
|
#pragma alloc_text(PAGELK, HalpMaskAcpiInterrupt)
|
|
#pragma alloc_text(PAGELK, HalpUnmaskAcpiInterrupt)
|
|
#endif
|
|
|
|
|
|
ULONG
|
|
DetectAcpiMP(
|
|
OUT PBOOLEAN IsConfiguredMp,
|
|
IN PLOADER_PARAMETER_BLOCK LoaderBlock
|
|
)
|
|
{
|
|
UCHAR ApicVersion, i;
|
|
PUCHAR LocalApic;
|
|
#ifdef DEBUGGING
|
|
CHAR string[100];
|
|
#endif
|
|
PHYSICAL_ADDRESS physicalAddress;
|
|
|
|
//
|
|
// The addres of the IRQL translation tables must be returned
|
|
// to the kernel
|
|
//
|
|
|
|
#if defined(_X86_)
|
|
LoaderBlock->Extension->HalpIRQLToTPR = HalpIRQLtoTPR;
|
|
LoaderBlock->Extension->HalpVectorToIRQL = HalpVectorToIRQL;
|
|
#endif
|
|
|
|
//
|
|
// Initialize MpInfo table
|
|
//
|
|
|
|
RtlZeroMemory (&HalpMpInfoTable, sizeof(MP_INFO));
|
|
|
|
//
|
|
// Set the return Values to the default
|
|
//
|
|
|
|
*IsConfiguredMp = FALSE;
|
|
|
|
//
|
|
// See if there is an APIC Table
|
|
//
|
|
|
|
if ((HalpApicTable = HalpGetAcpiTablePhase0(LoaderBlock, APIC_SIGNATURE)) == NULL) {
|
|
HalDisplayString(rgzNoApicTable);
|
|
return(FALSE);
|
|
}
|
|
|
|
// We have an APIC table. Initialize a HAL specific MP information
|
|
// structure that gets information from the MAPIC table.
|
|
|
|
#ifdef DEBUGGING
|
|
sprintf(string, "Signature: %x Length: %x\n",
|
|
HalpApicTable->Header.Signature,
|
|
HalpApicTable->Header.Length);
|
|
HalDisplayString(string);
|
|
sprintf(string, "OEMID: %s\n", HalpApicTable->Header.OEMID);
|
|
HalDisplayString(string);
|
|
sprintf(string, "Local Apic Address: %x\n", HalpApicTable->LocalAPICAddress);
|
|
HalDisplayString(string);
|
|
sprintf(string, "Flags: %x\n", HalpApicTable->Flags);
|
|
HalDisplayString(string);
|
|
#endif
|
|
|
|
HalpInitMpInfo(HalpApicTable, 0);
|
|
|
|
// Verify the information in the MAPIC table as best as we can.
|
|
|
|
if (HalpMpInfoTable.IOApicCount == 0) {
|
|
//
|
|
// Someone Has a MP Table and no IO Units -- Weird
|
|
// We have to assume the BIOS knew what it was doing
|
|
// when it built the table. so ..
|
|
//
|
|
HalDisplayString (rgzNoApic);
|
|
|
|
return (FALSE);
|
|
}
|
|
|
|
//
|
|
// It's an APIC System. It could be a UP System though.
|
|
//
|
|
|
|
if (HalpMpInfoTable.ProcessorCount > 1) {
|
|
*IsConfiguredMp = TRUE;
|
|
}
|
|
|
|
HalpMpInfoTable.LocalApicBase = (ULONG) HalpApicTable->LocalAPICAddress;
|
|
physicalAddress =
|
|
HalpPtrToPhysicalAddress( UlongToPtr(HalpMpInfoTable.LocalApicBase) );
|
|
|
|
LocalApic = (PUCHAR) HalpMapPhysicalMemoryWriteThrough( physicalAddress,
|
|
1 );
|
|
HalpRemapVirtualAddress (
|
|
(PVOID) LOCALAPIC,
|
|
physicalAddress,
|
|
TRUE
|
|
);
|
|
|
|
ApicVersion = (UCHAR) *(LocalApic + LU_VERS_REGISTER);
|
|
|
|
if (ApicVersion > 0x1f) {
|
|
//
|
|
// Only known Apics are 82489dx with version 0.x and
|
|
// Embedded Apics with version 1.x (where x is don't care)
|
|
//
|
|
// Return of 0xFF? Can't have an MPS system without a Local Unit.
|
|
//
|
|
|
|
#ifdef DEBUGGING
|
|
sprintf(string, "HALMPS: apic version %x, read from %x\n",
|
|
ApicVersion, LocalApic + LU_VERS_REGISTER);
|
|
|
|
HalDisplayString(string);
|
|
#endif
|
|
|
|
HalDisplayString (rgzBadApicVersion);
|
|
|
|
return (FALSE);
|
|
}
|
|
|
|
for(i=0; i < HalpMpInfoTable.IOApicCount; i++)
|
|
{
|
|
//
|
|
// Verify the existance of the IO Unit
|
|
//
|
|
|
|
|
|
if (!(HalpVerifyIOUnit((PUCHAR)HalpMpInfoTable.IoApicBase[i]))) {
|
|
HalDisplayString (rgzApicNotVerified);
|
|
|
|
return (FALSE);
|
|
}
|
|
}
|
|
|
|
HalDisplayString("HAL: DetectAPIC: APIC system found - Returning TRUE\n");
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
VOID
|
|
HalpInitMpInfo (
|
|
IN PMAPIC ApicTable,
|
|
IN ULONG Phase
|
|
)
|
|
|
|
/*++
|
|
Routine Description:
|
|
This routine initializes a HAL specific data structure that is
|
|
used by the HAL to simplify access to MP information.
|
|
|
|
Arguments:
|
|
|
|
ApicTable - Pointer to the APIC table.
|
|
|
|
Phase - indicates which pass we are are doing through the table.
|
|
|
|
Return Value:
|
|
Pointer to the HAL MP information table.
|
|
|
|
*/
|
|
{
|
|
PUCHAR TraversePtr;
|
|
UCHAR CheckSum;
|
|
UCHAR apicNo = 0;
|
|
ULONG nmiSources = 0;
|
|
#ifdef DEBUGGING
|
|
CHAR string[100];
|
|
#endif
|
|
PIO_APIC_UNIT apic;
|
|
PHYSICAL_ADDRESS physicalAddress;
|
|
PIOAPIC ioApic;
|
|
UCHAR totalProcs = 0;
|
|
|
|
union {
|
|
ULONG raw;
|
|
APIC_VERSION version;
|
|
} versionUnion;
|
|
|
|
// Walk the MAPIC table.
|
|
|
|
TraversePtr = (PUCHAR) ApicTable->APICTables;
|
|
|
|
//
|
|
// ACPI machines have embedded APICs.
|
|
//
|
|
HalpMpInfoTable.ApicVersion = 0x10;
|
|
|
|
#ifdef DUMP_MAPIC_TABLE
|
|
|
|
while ((ULONG)TraversePtr <
|
|
((ULONG)ApicTable + ApicTable->Header.Length)) {
|
|
|
|
sprintf(string, "%08x %08x %08x %08x\n",
|
|
*(PULONG)TraversePtr,
|
|
*(PULONG)(TraversePtr + 4),
|
|
*(PULONG)(TraversePtr + 8),
|
|
*(PULONG)(TraversePtr + 12)
|
|
);
|
|
HalDisplayString(string);
|
|
TraversePtr += 16;
|
|
}
|
|
|
|
TraversePtr = (PUCHAR) ApicTable->APICTables;
|
|
#endif
|
|
|
|
if (!(ApicTable->Flags & PCAT_COMPAT)) {
|
|
|
|
//
|
|
// This HAL can't actually handle a machine without 8259's,
|
|
// even though it doesn't use them.
|
|
//
|
|
|
|
KeBugCheckEx(MISMATCHED_HAL,
|
|
6, 0, 0, 0);
|
|
|
|
}
|
|
|
|
while ((ULONG_PTR)TraversePtr <
|
|
((ULONG_PTR)ApicTable + ApicTable->Header.Length)) {
|
|
|
|
if ((((PPROCLOCALAPIC)(TraversePtr))->Type == PROCESSOR_LOCAL_APIC)
|
|
&& (((PPROCLOCALAPIC)(TraversePtr))->Length == PROCESSOR_LOCAL_APIC_LENGTH)) {
|
|
|
|
#ifdef DEBUGGING
|
|
sprintf(string, "Found a processor-local APIC: %x\n", TraversePtr);
|
|
HalDisplayString(string);
|
|
#endif
|
|
|
|
if (Phase == 0) {
|
|
|
|
if(((PPROCLOCALAPIC)(TraversePtr))->Flags & PLAF_ENABLED) {
|
|
|
|
//
|
|
// This processor is enabled, so keep track of useful stuff.
|
|
//
|
|
|
|
HalpProcLocalApicTable[HalpMpInfoTable.ProcessorCount].NamespaceProcID =
|
|
((PPROCLOCALAPIC)(TraversePtr))->ACPIProcessorID;
|
|
|
|
HalpProcLocalApicTable[HalpMpInfoTable.ProcessorCount].ApicID =
|
|
((PPROCLOCALAPIC)(TraversePtr))->APICID;
|
|
|
|
HalpMpInfoTable.ProcessorCount += 1;
|
|
}
|
|
}
|
|
|
|
totalProcs++;
|
|
|
|
HalpMaxProcs = (totalProcs > HalpMaxProcs) ? totalProcs : HalpMaxProcs;
|
|
|
|
TraversePtr += ((PPROCLOCALAPIC)(TraversePtr))->Length;
|
|
|
|
} else if ((((PIOAPIC)(TraversePtr))->Type == IO_APIC) &&
|
|
(((PIOAPIC)(TraversePtr))->Length == IO_APIC_LENGTH)) {
|
|
|
|
|
|
#ifdef DEBUGGING
|
|
sprintf(string, "Found an IO APIC: [%x] %x\n",
|
|
HalpMpInfoTable.IOApicCount,
|
|
TraversePtr);
|
|
HalDisplayString(string);
|
|
#endif
|
|
|
|
ioApic = (PIOAPIC)TraversePtr;
|
|
|
|
if (Phase == 0) {
|
|
//
|
|
// Found an IO APIC entry. Record the info from
|
|
// the table.
|
|
//
|
|
|
|
apicNo = (UCHAR)HalpMpInfoTable.IOApicCount;
|
|
|
|
HalpIoApicId[apicNo] = ioApic->IOAPICID;
|
|
|
|
HalpMpInfoTable.IoApicIntiBase[apicNo] =
|
|
ioApic->SystemVectorBase;
|
|
|
|
HalpMpInfoTable.IoApicPhys[apicNo] =
|
|
ioApic->IOAPICAddress;
|
|
|
|
//
|
|
// Get a virtual address for it.
|
|
//
|
|
|
|
physicalAddress = HalpPtrToPhysicalAddress(
|
|
UlongToPtr(ioApic->IOAPICAddress) );
|
|
|
|
HalpMpInfoTable.IoApicBase[apicNo] =
|
|
HalpMapPhysicalMemoryWriteThrough( physicalAddress, 1 );
|
|
|
|
apic = (PIO_APIC_UNIT)HalpMpInfoTable.IoApicBase[apicNo];
|
|
|
|
if (!apic) {
|
|
#ifdef DEBUGGING
|
|
sprintf(string, "Couldn't map the I/O apic\n");
|
|
HalDisplayString(string);
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Dig the number of Intis out of the hardware.
|
|
//
|
|
|
|
apic->RegisterSelect = IO_VERS_REGISTER;
|
|
apic->RegisterWindow = 0;
|
|
versionUnion.raw = apic->RegisterWindow;
|
|
|
|
HalpMaxApicInti[apicNo] = versionUnion.version.MaxRedirEntries + 1;
|
|
|
|
//
|
|
// Also store the version so that it can be retrieved by the ACPI driver
|
|
//
|
|
|
|
HalpIOApicVersion[apicNo] = versionUnion.raw;
|
|
|
|
#ifdef DEBUGGING
|
|
sprintf(string, "GSIV base: %x PhysAddr: %x VirtAddr: %x Intis: %x\n",
|
|
HalpMpInfoTable.IoApicVectorBase[apicNo],
|
|
HalpMpInfoTable.IoApicPhys[apicNo],
|
|
HalpMpInfoTable.IoApicBase[apicNo],
|
|
HalpMaxApicInti[apicNo]);
|
|
|
|
HalDisplayString(string);
|
|
#endif
|
|
|
|
HalpMpInfoTable.IOApicCount += 1;
|
|
}
|
|
|
|
TraversePtr += ioApic->Length;
|
|
|
|
} else if ((((PISA_VECTOR)TraversePtr)->Type == ISA_VECTOR_OVERRIDE) &&
|
|
(((PISA_VECTOR)TraversePtr)->Length == ISA_VECTOR_OVERRIDE_LENGTH)) {
|
|
|
|
#ifdef DEBUGGING
|
|
sprintf(string, "Found an ISA VECTOR: %x, %x -> %x, flags: %x\n",
|
|
TraversePtr,
|
|
((PISA_VECTOR)TraversePtr)->Source,
|
|
((PISA_VECTOR)TraversePtr)->GlobalSystemInterruptVector,
|
|
((PISA_VECTOR)TraversePtr)->Flags
|
|
);
|
|
HalDisplayString(string);
|
|
#endif
|
|
|
|
if (Phase == 0) {
|
|
|
|
//
|
|
// Found an ISA vector redirection entry.
|
|
//
|
|
|
|
HalpPicVectorRedirect[((PISA_VECTOR)TraversePtr)->Source] =
|
|
((PISA_VECTOR)TraversePtr)->GlobalSystemInterruptVector;
|
|
|
|
HalpPicVectorFlags[((PISA_VECTOR)TraversePtr)->Source] =
|
|
((PISA_VECTOR)TraversePtr)->Flags;
|
|
|
|
}
|
|
|
|
TraversePtr += ISA_VECTOR_OVERRIDE_LENGTH;
|
|
|
|
} else if ((((PIO_NMISOURCE)TraversePtr)->Type == IO_NMI_SOURCE) &&
|
|
(((PIO_NMISOURCE)TraversePtr)->Length == IO_NMI_SOURCE_LENGTH)) {
|
|
|
|
if (Phase == 1) {
|
|
|
|
BOOLEAN found;
|
|
USHORT inti;
|
|
|
|
found = HalpGetApicInterruptDesc(0,
|
|
0,
|
|
((PIO_NMISOURCE)TraversePtr)->GlobalSystemInterruptVector,
|
|
&inti);
|
|
|
|
if (found) {
|
|
|
|
HalpIntiInfo[inti].Type = INT_TYPE_NMI;
|
|
HalpIntiInfo[inti].Level =
|
|
(((((((PIO_NMISOURCE)TraversePtr)->Flags & EL_BITS) == EL_EDGE_TRIGGERED) ||
|
|
((PIO_NMISOURCE)TraversePtr)->Flags & EL_BITS) == EL_CONFORMS_WITH_BUS)
|
|
? CFG_EDGE : CFG_LEVEL);
|
|
HalpIntiInfo[inti].Polarity =
|
|
((PIO_NMISOURCE)TraversePtr)->Flags & PO_BITS;
|
|
}
|
|
}
|
|
|
|
TraversePtr += IO_NMI_SOURCE_LENGTH;
|
|
|
|
} else if ((((PLOCAL_NMISOURCE)TraversePtr)->Type == LOCAL_NMI_SOURCE) &&
|
|
(((PLOCAL_NMISOURCE)TraversePtr)->Length == LOCAL_NMI_SOURCE_LENGTH)) {
|
|
|
|
if (Phase == 1) {
|
|
|
|
//
|
|
// While running through phase 1, we should catalog local NMI sources.
|
|
//
|
|
|
|
if (!HalpLocalNmiSources) {
|
|
|
|
//
|
|
// Allocate enough pool to point to all the possible local NMI structures.
|
|
// Since there are two NMI pins on each processor, this is the number of processors
|
|
// times two times the size of a pointer.
|
|
//
|
|
|
|
HalpLocalNmiSources = ExAllocatePoolWithTag(NonPagedPool,
|
|
sizeof(PVOID) * HalpMaxProcs * 2,
|
|
HAL_POOL_TAG);
|
|
|
|
RtlZeroMemory(HalpLocalNmiSources,
|
|
sizeof(PVOID) * HalpMaxProcs * 2);
|
|
}
|
|
|
|
HalpLocalNmiSources[nmiSources++] = (PVOID)TraversePtr;
|
|
|
|
}
|
|
|
|
TraversePtr += LOCAL_NMI_SOURCE_LENGTH;
|
|
|
|
} else {
|
|
#ifdef DEBUGGING
|
|
sprintf(string, "%x: %x \n", TraversePtr, *TraversePtr);
|
|
HalDisplayString(string);
|
|
#endif
|
|
//
|
|
// Found random bits in the table. Try the next byte and
|
|
// see if we can make sense of it.
|
|
//
|
|
|
|
TraversePtr += 1;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
BOOLEAN
|
|
HalpVerifyIOUnit(
|
|
IN PUCHAR BaseAddress
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Verify that an IO 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 ApicUnion {
|
|
ULONG Raw;
|
|
struct ApicVersion Ver;
|
|
} Temp1, Temp2;
|
|
|
|
struct ApicIoUnit *IoUnitPtr = (struct ApicIoUnit *) 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.Ver.Version != Temp2.Ver.Version) ||
|
|
(Temp1.Ver.MaxRedirEntries != Temp2.Ver.MaxRedirEntries)) {
|
|
//
|
|
// No IO Unit There
|
|
//
|
|
return (FALSE);
|
|
}
|
|
|
|
return (TRUE);
|
|
}
|
|
|
|
#ifdef DEBUGGING
|
|
struct PcMpTable *PcMpTablePtr, *PcMpDefaultTablePtrs[];
|
|
|
|
void
|
|
ComputeCheckSum(UCHAR This, UCHAR That)
|
|
{
|
|
}
|
|
#endif
|
|
|
|
|
|
VOID
|
|
HalpSaveInterruptControllerState(
|
|
VOID
|
|
)
|
|
{
|
|
|
|
HalpHiberInProgress = TRUE;
|
|
}
|
|
|
|
VOID
|
|
HalpRestoreInterruptControllerState(
|
|
VOID
|
|
)
|
|
{
|
|
//
|
|
// Restore the IO APIC state
|
|
//
|
|
|
|
HalpRestoreIoApicRedirTable();
|
|
|
|
HalpPicStateIntact = TRUE;
|
|
}
|
|
|
|
VOID
|
|
HalpSetInterruptControllerWakeupState(
|
|
ULONG Context
|
|
)
|
|
{
|
|
LOADER_PARAMETER_BLOCK LoaderBlock;
|
|
SLEEP_STATE_CONTEXT sleepContext;
|
|
BOOLEAN IsMpSystem;
|
|
ULONG flags;
|
|
KIRQL OldIrql;
|
|
KPRCB Prcb;
|
|
ULONG ii;
|
|
USHORT inti;
|
|
ULONG localApicId;
|
|
ULONG oldProcNumber, oldProcsStarted;
|
|
ULONG localApicBase;
|
|
|
|
sleepContext.AsULONG = Context;
|
|
|
|
flags = HalpDisableInterrupts();
|
|
|
|
if (sleepContext.bits.Flags & SLEEP_STATE_RESTART_OTHER_PROCESSORS) {
|
|
|
|
//
|
|
// If you are remapping local apic, io apic and ACPI MAPIC table
|
|
// resources, you first have to unmap the current resources!!!
|
|
// The BIOS may have created the MAPIC table at a different place or may
|
|
// have changed values like processor local APIC IDs. Reparse it.
|
|
//
|
|
|
|
ASSERT(HalpApicTable);
|
|
oldProcNumber = HalpMpInfoTable.ProcessorCount;
|
|
oldProcsStarted = HalpMpInfoTable.NtProcessors;
|
|
localApicBase = HalpMpInfoTable.LocalApicBase;
|
|
|
|
HalpUnMapIOApics();
|
|
|
|
RtlZeroMemory (&HalpMpInfoTable, sizeof(MP_INFO));
|
|
RtlZeroMemory(HalpProcLocalApicTable,
|
|
sizeof(PROC_LOCAL_APIC) * MAX_PROCESSORS);
|
|
|
|
HalpInitMpInfo(HalpApicTable, 0);
|
|
|
|
if (HalpMpInfoTable.ProcessorCount != oldProcNumber) {
|
|
|
|
KeBugCheckEx(HAL_INITIALIZATION_FAILED,
|
|
0x2000,
|
|
oldProcNumber,
|
|
HalpMpInfoTable.ProcessorCount,
|
|
0);
|
|
}
|
|
|
|
HalpMpInfoTable.NtProcessors = oldProcsStarted;
|
|
HalpMpInfoTable.LocalApicBase = localApicBase;
|
|
|
|
RtlZeroMemory(&LoaderBlock, sizeof(LoaderBlock));
|
|
RtlZeroMemory(&Prcb, sizeof(Prcb));
|
|
LoaderBlock.Prcb = (ULONG_PTR) &Prcb;
|
|
}
|
|
|
|
//
|
|
// Initialize minimum global hardware state needed.
|
|
//
|
|
|
|
HalpIpiClock = 0;
|
|
HalpInitializeIOUnits();
|
|
HalpInitializePICs(FALSE);
|
|
HalpSet8259Mask(HalpGlobal8259Mask);
|
|
|
|
//
|
|
// Initialize boot processor's local APIC so it can wake other processors
|
|
//
|
|
|
|
HalpInitializeLocalUnit ();
|
|
KeRaiseIrql(HIGH_LEVEL, &OldIrql);
|
|
|
|
//
|
|
// Wake up the other processors
|
|
//
|
|
|
|
if (sleepContext.bits.Flags & SLEEP_STATE_RESTART_OTHER_PROCESSORS) {
|
|
|
|
//
|
|
// Fill in this processor's Apic ID.
|
|
//
|
|
|
|
localApicId = *(PVULONG)(LOCALAPIC + LU_ID_REGISTER);
|
|
|
|
localApicId &= APIC_ID_MASK;
|
|
localApicId >>= APIC_ID_SHIFT;
|
|
|
|
((PHALPRCB)KeGetCurrentPrcb()->HalReserved)->PCMPApicID = (UCHAR)localApicId;
|
|
|
|
//
|
|
// Mark this processor as started.
|
|
//
|
|
|
|
for (ii = 0; ii < HalpMpInfoTable.NtProcessors; ii++) {
|
|
|
|
if (HalpProcLocalApicTable[ii].ApicID ==
|
|
((PHALPRCB)KeGetCurrentPrcb()->HalReserved)->PCMPApicID) {
|
|
|
|
HalpProcLocalApicTable[ii].Started = TRUE;
|
|
HalpProcLocalApicTable[ii].Enumerated = TRUE;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
ASSERT(ii != HalpMpInfoTable.ProcessorCount);
|
|
|
|
for(ii = 1; ii < HalpMpInfoTable.NtProcessors; ++ii) {
|
|
|
|
// Set processor number in dummy loader parameter block
|
|
|
|
Prcb.Number = (UCHAR) ii;
|
|
CurTiledCr3LowPart = HalpTiledCr3Addresses[ii].LowPart;
|
|
if (!HalStartNextProcessor(&LoaderBlock, &HalpHiberProcState[ii])) {
|
|
|
|
//
|
|
// We could not start a processor. This is a fatal error.
|
|
//
|
|
|
|
KeBugCheckEx(HAL_INITIALIZATION_FAILED,
|
|
0x2001,
|
|
oldProcNumber,
|
|
HalpMpInfoTable.NtProcessors,
|
|
0);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Enable the clock interrupt.
|
|
//
|
|
|
|
HalpGetApicInterruptDesc(
|
|
DEFAULT_PC_BUS,
|
|
0,
|
|
HalpPicVectorRedirect[RTC_IRQ],
|
|
&inti
|
|
);
|
|
|
|
HalpSetRedirEntry((UCHAR)inti,
|
|
HalpIntiInfo[inti].Entry,
|
|
HalpIntiInfo[inti].Destinations << DESTINATION_SHIFT);
|
|
|
|
HalpPicStateIntact = FALSE;
|
|
|
|
HalpRestoreInterrupts(flags);
|
|
}
|
|
|
|
BOOLEAN
|
|
HalpAcpiPicStateIntact(
|
|
VOID
|
|
)
|
|
{
|
|
return HalpPicStateIntact;
|
|
}
|
|
|
|
|
|
ULONG HalpGetApicVersion(ULONG ApicNo)
|
|
{
|
|
/*++
|
|
Routine Description:
|
|
|
|
Obtains the contents of the version register
|
|
for a particular system IO APIC unit. These contents
|
|
are saved by the HAL in HalpInitMpInfo.
|
|
|
|
Arguments:
|
|
|
|
ApicNo - the number of the IO APIC Unit whose version we want.
|
|
|
|
|
|
Return Value:
|
|
|
|
The contents of the version register for the given IO APIC unit.
|
|
|
|
A 0 is returned if no version can be obtained because the given
|
|
APIC number is not valid.
|
|
*/
|
|
|
|
// If this APIC has been found by the HAL ...
|
|
|
|
if (ApicNo < HalpMpInfoTable.IOApicCount) {
|
|
|
|
// ... return its version
|
|
|
|
return HalpIOApicVersion[ApicNo];
|
|
}
|
|
else
|
|
{
|
|
// Otherwise, return 0.
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
HalpMaskAcpiInterrupt(
|
|
VOID
|
|
)
|
|
{
|
|
USHORT inti = 0;
|
|
ULONG apicEntry;
|
|
|
|
HalpGetApicInterruptDesc(
|
|
DEFAULT_PC_BUS,
|
|
0,
|
|
HalpPicVectorRedirect[HalpFixedAcpiDescTable.sci_int_vector],
|
|
&inti
|
|
);
|
|
|
|
apicEntry = HalpIntiInfo[inti].Entry;
|
|
apicEntry |= INTERRUPT_MASKED;
|
|
|
|
HalpSetRedirEntry((UCHAR)inti,
|
|
apicEntry,
|
|
0);
|
|
|
|
|
|
}
|
|
|
|
VOID
|
|
HalpUnmaskAcpiInterrupt(
|
|
VOID
|
|
)
|
|
{
|
|
USHORT inti = 0;
|
|
|
|
HalpGetApicInterruptDesc(
|
|
DEFAULT_PC_BUS,
|
|
0,
|
|
HalpPicVectorRedirect[HalpFixedAcpiDescTable.sci_int_vector],
|
|
&inti
|
|
);
|
|
|
|
HalpSetRedirEntry((UCHAR)inti,
|
|
HalpIntiInfo[inti].Entry,
|
|
HalpIntiInfo[inti].Destinations << DESTINATION_SHIFT);
|
|
|
|
}
|
|
|
|
|