547 lines
13 KiB
C
547 lines
13 KiB
C
/*++
|
|
|
|
Copyright (c) 1991 Microsoft Corporation
|
|
Copyright (c) 1992 Intel Corporation
|
|
All rights reserved
|
|
|
|
INTEL CORPORATION PROPRIETARY INFORMATION
|
|
|
|
This software is supplied to Microsoft under the terms
|
|
of a license agreement with Intel Corporation and may not be
|
|
copied nor disclosed except in accordance with the terms
|
|
of that agreement.
|
|
|
|
Module Name:
|
|
|
|
mpdetect.c
|
|
|
|
Abstract:
|
|
|
|
This module detects an MPS system.
|
|
|
|
Author:
|
|
|
|
Ron Mosgrove (Intel) - Aug 1993.
|
|
|
|
Environment:
|
|
|
|
Kernel mode or from textmode setup.
|
|
|
|
Revision History:
|
|
Rajesh Shah (Intel) - Oct 1993. Added support for MPS table.
|
|
|
|
--*/
|
|
|
|
#ifndef _NTOS_
|
|
#include "halp.h"
|
|
#endif
|
|
|
|
#ifdef SETUP
|
|
#define FAILMSG(a)
|
|
#else
|
|
#define FAILMSG(a) HalDisplayString(a)
|
|
extern UCHAR rgzNoMpsTable[];
|
|
extern UCHAR rgzNoApic[];
|
|
extern UCHAR rgzBadApicVersion[];
|
|
extern UCHAR rgzApicNotVerified[];
|
|
extern UCHAR rgzMPPTRCheck[];
|
|
extern UCHAR rgzNoMPTable[];
|
|
extern UCHAR rgzMPSBadSig[];
|
|
extern UCHAR rgzMPSBadCheck[];
|
|
extern UCHAR rgzBadDefault[];
|
|
extern UCHAR rgzNoMem[];
|
|
#endif
|
|
|
|
|
|
// Include the code that actually detect a MPS system
|
|
#include "pcmpdtct.c"
|
|
|
|
|
|
BOOLEAN
|
|
HalpVerifyIOUnit (
|
|
IN PUCHAR BaseAddress
|
|
);
|
|
|
|
VOID
|
|
HalpInitMpInfo (
|
|
IN struct PcMpTable *MpTablePtr
|
|
);
|
|
|
|
ULONG
|
|
DetectMPS (
|
|
OUT PBOOLEAN IsConfiguredMp
|
|
);
|
|
|
|
ULONG
|
|
DetectUPMPS (
|
|
OUT PBOOLEAN IsConfiguredMp
|
|
);
|
|
|
|
extern struct PcMpTable *GetPcMpTable( VOID );
|
|
|
|
ULONG UserSpecifiedNoIoApic = 0;
|
|
|
|
struct HalpMpInfo HalpMpInfoTable;
|
|
struct PcMpTable HalpPcMpTable;
|
|
|
|
struct PcMpTable *PcMpTablePtr;
|
|
|
|
#ifndef SETUP
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGELK,HalpVerifyIOUnit)
|
|
#pragma alloc_text(PAGELK,HalpInitMpInfo)
|
|
#pragma alloc_text(PAGELK,DetectMPS)
|
|
#pragma alloc_text(PAGELK,DetectUPMPS)
|
|
#endif // ALLOC_PRAGMA
|
|
|
|
extern struct PcMpTable *PcMpDefaultTablePtrs[];
|
|
|
|
#endif // SETUP
|
|
|
|
|
|
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);
|
|
}
|
|
|
|
|
|
VOID
|
|
HalpInitMpInfo (
|
|
IN struct PcMpTable *MpTablePtr
|
|
)
|
|
|
|
/*++
|
|
Routine Description:
|
|
This routine initializes a HAL specific data structure that is
|
|
used by the HAL to simplify access to MP information.
|
|
|
|
Arguments:
|
|
MpTablePtr: Pointer to the MPS table.
|
|
|
|
Return Value:
|
|
Pointer to the HAL MP information table.
|
|
|
|
*/
|
|
{
|
|
PUCHAR TraversePtr, EndOfBaseTable;
|
|
UCHAR CheckSum;
|
|
|
|
// Walk the MPS table. The HAL MP information structure has
|
|
// pointers to the first entry for each entry type in the MPS
|
|
// table. Set these pointers.
|
|
|
|
TraversePtr = (PUCHAR) MpTablePtr + HEADER_SIZE;
|
|
EndOfBaseTable = (PUCHAR) MpTablePtr + MpTablePtr->TableLength;
|
|
|
|
HalpMpInfoTable.ApicVersion =
|
|
(ULONG) (((PPCMPPROCESSOR)(TraversePtr))->LocalApicVersion & 0xf0);
|
|
|
|
while (TraversePtr < EndOfBaseTable) {
|
|
switch (*TraversePtr) {
|
|
case ENTRY_PROCESSOR:
|
|
if(((PPCMPPROCESSOR)(TraversePtr))->CpuFlags & CPU_ENABLED) {
|
|
if (HalpMpInfoTable.ProcessorCount == 0) {
|
|
HalpMpInfoTable.ProcessorEntryPtr =
|
|
(PPCMPPROCESSOR) TraversePtr;
|
|
}
|
|
HalpMpInfoTable.ProcessorCount++;
|
|
}
|
|
TraversePtr += sizeof(PCMPPROCESSOR);
|
|
break;
|
|
|
|
case ENTRY_BUS:
|
|
if (HalpMpInfoTable.BusCount == 0) {
|
|
HalpMpInfoTable.BusEntryPtr = (PPCMPBUS) TraversePtr;
|
|
}
|
|
HalpMpInfoTable.BusCount += 1;
|
|
TraversePtr += sizeof(PCMPBUS);
|
|
break;
|
|
|
|
case ENTRY_IOAPIC:
|
|
if ((((PPCMPIOAPIC)(TraversePtr))->IoApicFlag &
|
|
IO_APIC_ENABLED) && (UserSpecifiedNoIoApic == 0)) {
|
|
if (HalpMpInfoTable.IOApicCount == 0) {
|
|
HalpMpInfoTable.IoApicEntryPtr =
|
|
(PPCMPIOAPIC) TraversePtr;
|
|
}
|
|
HalpMpInfoTable.IOApicCount += 1;
|
|
}
|
|
TraversePtr += sizeof(PCMPIOAPIC);
|
|
break;
|
|
|
|
case ENTRY_INTI:
|
|
if (HalpMpInfoTable.IntiCount == 0) {
|
|
HalpMpInfoTable.IntiEntryPtr = (PPCMPINTI) TraversePtr;
|
|
}
|
|
HalpMpInfoTable.IntiCount += 1;
|
|
TraversePtr += sizeof(PCMPINTI);
|
|
break;
|
|
|
|
case ENTRY_LINTI:
|
|
if (HalpMpInfoTable.LintiCount == 0) {
|
|
HalpMpInfoTable.LintiEntryPtr = (PPCMPLINTI) TraversePtr;
|
|
}
|
|
HalpMpInfoTable.LintiCount += 1;
|
|
TraversePtr += sizeof(PCMPLINTI);
|
|
break;
|
|
|
|
default:
|
|
//
|
|
// Unknown MPS entry. Since we don't know it's size, we will
|
|
// terminate parsing here.
|
|
//
|
|
DBGMSG("HAL: Invalid MPS table entry type detected\n");
|
|
TraversePtr = EndOfBaseTable;
|
|
break;
|
|
} // switch
|
|
} // while
|
|
|
|
|
|
//
|
|
// Check for Extension table defined
|
|
//
|
|
|
|
if (MpTablePtr->ExtTableLength &&
|
|
MpTablePtr->TableLength + MpTablePtr->ExtTableLength < 8192) {
|
|
|
|
CheckSum = ComputeCheckSum(
|
|
(PUCHAR) MpTablePtr + MpTablePtr->TableLength,
|
|
MpTablePtr->ExtTableLength
|
|
);
|
|
|
|
CheckSum += MpTablePtr->ExtTableChecksum;
|
|
|
|
if (CheckSum != 0) {
|
|
DBGMSG("HALMPS: InitMpInfo: Extension table checksum error\n");
|
|
|
|
} else {
|
|
HalpMpInfoTable.ExtensionTable = (PMPS_EXTENTRY)
|
|
(((PUCHAR) MpTablePtr) + MpTablePtr->TableLength);
|
|
|
|
HalpMpInfoTable.EndOfExtensionTable = (PMPS_EXTENTRY)
|
|
(((PUCHAR) MpTablePtr) + MpTablePtr->TableLength +
|
|
MpTablePtr->ExtTableLength);
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
ULONG
|
|
DetectMPS(
|
|
OUT PBOOLEAN IsConfiguredMp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called from HalInitializeProcessors to determine
|
|
if this is an appropriate system to run the MPS hal on.
|
|
|
|
The recommended detection mechanism is:
|
|
|
|
if ( MPS information does not exist )
|
|
then
|
|
System is not MPS compliant. Return false.
|
|
|
|
In MP table:
|
|
if ( number IO APICs < 1 )
|
|
then
|
|
Not a MPS System - return false
|
|
|
|
if ( # CPUs = 1 )
|
|
then
|
|
Found a Single Processor MPS System
|
|
else
|
|
Found a MP MPS System
|
|
|
|
|
|
A side effect of this routine is the mapping of the IO UNits and
|
|
Local unit virtual addresses.
|
|
|
|
Return TRUE
|
|
|
|
|
|
Arguments:
|
|
|
|
IsConfiguredMp - TRUE if this machine is a MP instance of the MPS spec, else FALSE.
|
|
|
|
Return Value:
|
|
0 - if not a MPS
|
|
1 - if MPS
|
|
|
|
*/
|
|
{
|
|
|
|
UCHAR ApicVersion, i;
|
|
PUCHAR LocalApic;
|
|
PPCMPIOAPIC IoEntryPtr;
|
|
PHYSICAL_ADDRESS physicalAddress;
|
|
|
|
//
|
|
// Initialize MpInfo table
|
|
//
|
|
|
|
RtlZeroMemory (&HalpMpInfoTable, sizeof HalpMpInfoTable);
|
|
|
|
//
|
|
// Set the return Values to the default
|
|
//
|
|
|
|
*IsConfiguredMp = FALSE;
|
|
|
|
//
|
|
// See if there is a MP Table
|
|
//
|
|
|
|
#if 1
|
|
if ((PcMpTablePtr = GetPcMpTable()) == NULL) {
|
|
FAILMSG (rgzNoMpsTable);
|
|
return(FALSE);
|
|
}
|
|
#else
|
|
//********
|
|
//******** HACK! To make down level 1.0 machine work
|
|
//********
|
|
|
|
if ((PcMpTablePtr = MPS10_GetPcMpTable()) == NULL) {
|
|
FAILMSG (rgzNoMpsTable);
|
|
return(FALSE);
|
|
}
|
|
#endif
|
|
|
|
#ifdef SETUP
|
|
// During setup, if we detected a default MPS configuration, we have
|
|
// no more checking to do.
|
|
if (PcMpTablePtr == (struct PcMpTable *) DEFAULT_MPS_INDICATOR) {
|
|
*IsConfiguredMp = TRUE;
|
|
return(TRUE);
|
|
}
|
|
#endif // SETUP
|
|
|
|
#if DEBUGGING
|
|
HalpDisplayConfigTable();
|
|
#endif
|
|
|
|
// We have a MPS table. Initialize a HAL specific MP information
|
|
// structure that gets information from the MPS table.
|
|
|
|
HalpInitMpInfo(PcMpTablePtr);
|
|
|
|
|
|
// Verify the information in the MPS 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 ..
|
|
//
|
|
FAILMSG (rgzNoApic);
|
|
return (FALSE);
|
|
}
|
|
|
|
//
|
|
// It's a MPS System. It could be a UP System though.
|
|
//
|
|
|
|
#ifdef SETUP
|
|
//
|
|
// If this is a MPS (MPS) compliant system, but has only 1 processor,
|
|
// for now we want to install a standard UP kernel and HAL.
|
|
//
|
|
|
|
if (HalpMpInfoTable.ProcessorCount <= 1) {
|
|
return FALSE;
|
|
}
|
|
#endif
|
|
|
|
if (HalpMpInfoTable.ProcessorCount > 1) {
|
|
*IsConfiguredMp = TRUE;
|
|
}
|
|
|
|
HalpMpInfoTable.LocalApicBase = (ULONG) PcMpTablePtr->LocalApicAddress;
|
|
physicalAddress.QuadPart = HalpMpInfoTable.LocalApicBase;
|
|
LocalApic = (PUCHAR) HalpMapPhysicalMemoryWriteThrough64(
|
|
physicalAddress,1);
|
|
|
|
if (!LocalApic) {
|
|
FAILMSG (rgzNoMem);
|
|
return (FALSE);
|
|
}
|
|
|
|
#ifndef SETUP
|
|
HalpRemapVirtualAddress64 (
|
|
(PVOID) LOCALAPIC,
|
|
physicalAddress,
|
|
TRUE
|
|
);
|
|
#endif
|
|
|
|
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(Cbuf, "HALMPS: apic version %x, read from %x\n",
|
|
ApicVersion, LocalApic + LU_VERS_REGISTER);
|
|
|
|
HalDisplayString(Cbuf);
|
|
#endif
|
|
|
|
FAILMSG (rgzBadApicVersion);
|
|
return (FALSE);
|
|
}
|
|
|
|
#ifdef SETUP
|
|
//
|
|
// MP MPS table, and the local APIC ID looked OK.
|
|
//
|
|
|
|
return TRUE;
|
|
#endif //SETUP
|
|
|
|
|
|
#ifdef DEBUGGING
|
|
if ((ApicVersion & 0xf0) == 0) {
|
|
if (HalpMpInfoTable.ApicVersion != APIC_82489DX)
|
|
HalDisplayString("HAL:Invalid Local Apic version in MP table\n");
|
|
else {
|
|
sprintf(Cbuf, "HAL: DetectMPS: Found 82489DX Local APIC (Ver 0x%x) at 0x%lx\n",
|
|
ApicVersion, LocalApic);
|
|
HalDisplayString(Cbuf);
|
|
}
|
|
} else {
|
|
sprintf(Cbuf, "HAL: DetectMPS: Found Embedded Local APIC (Ver 0x%x) at 0x%lx\n",
|
|
ApicVersion, LocalApic);
|
|
HalDisplayString(Cbuf);
|
|
|
|
}
|
|
#endif // DEBUGGING
|
|
|
|
#ifndef SETUP
|
|
HalpUnmapVirtualAddress(LocalApic,1);
|
|
#endif
|
|
|
|
IoEntryPtr = HalpMpInfoTable.IoApicEntryPtr;
|
|
|
|
for(i=0; i < HalpMpInfoTable.IOApicCount; i++, IoEntryPtr++)
|
|
{
|
|
if (IoEntryPtr->IoApicFlag & IO_APIC_ENABLED) {
|
|
//
|
|
// Verify the existance of the IO Units
|
|
//
|
|
|
|
physicalAddress.QuadPart = (ULONG)IoEntryPtr->IoApicAddress;
|
|
HalpMpInfoTable.IoApicPhys[i] = (ULONG)IoEntryPtr->IoApicAddress;
|
|
HalpMpInfoTable.IoApicBase[i] = (PULONG)
|
|
HalpMapPhysicalMemoryWriteThrough64(physicalAddress, 1);
|
|
|
|
//
|
|
// Verify the existance of the IO Unit
|
|
//
|
|
|
|
if (!(HalpVerifyIOUnit((PUCHAR)HalpMpInfoTable.IoApicBase[i]))) {
|
|
FAILMSG (rgzApicNotVerified);
|
|
return (FALSE);
|
|
}
|
|
}
|
|
}
|
|
|
|
DBGMSG("HAL: DetectMPS: MPS system found - Returning TRUE\n");
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
ULONG
|
|
DetectUPMPS(
|
|
OUT PBOOLEAN IsConfiguredMp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called by setup after DetectMPS has returned
|
|
false. During setup time DetectMPS will return false, if the
|
|
machine is an MPS system, but only has one processor. This
|
|
function is used to detect such a machine at setup time.
|
|
|
|
Arguments:
|
|
|
|
IsConfiguredMp - FALSE
|
|
|
|
Return Value:
|
|
0 - if not a UP MPS
|
|
1 - if UP MPS
|
|
|
|
--*/
|
|
{
|
|
*IsConfiguredMp = FALSE;
|
|
|
|
// we assume the caller has already called DetectMPS, and the
|
|
// MPS table has already been parsed.
|
|
|
|
return (HalpMpInfoTable.ProcessorCount == 1 ? TRUE : FALSE);
|
|
}
|