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.
672 lines
17 KiB
672 lines
17 KiB
/*++
|
|
|
|
Copyright (c) 1997 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
mps.c
|
|
|
|
Abstract:
|
|
|
|
WinDbg Extension Api
|
|
|
|
Author:
|
|
|
|
Peter Johnston (peterj) 30-September-1997
|
|
|
|
Environment:
|
|
|
|
User Mode.
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
//
|
|
// HACKHACK
|
|
//
|
|
// The debugger extensions are a little bit broken at the
|
|
// moment (6/6/00) and I can't read a bitfield. So I'm
|
|
// including the type here. And it doesn't matter
|
|
// because this code only runs on 32-bit machines.
|
|
//
|
|
|
|
typedef struct _CPUIDENTIFIER {
|
|
ULONG Stepping : 4;
|
|
ULONG Model : 4;
|
|
ULONG Family : 4;
|
|
ULONG Reserved : 20;
|
|
} CPUIDENTIFIER, *PCPUIDENTIFIER;
|
|
|
|
//
|
|
// xReadMemory is easier to use than ReadMemory and is
|
|
// defined in ..\devnode.c
|
|
//
|
|
|
|
BOOLEAN
|
|
xReadMemory(
|
|
ULONG64 S,
|
|
PVOID D,
|
|
ULONG Len
|
|
);
|
|
|
|
PUCHAR
|
|
mpsGetIntTypeDesc(
|
|
UCHAR IntType
|
|
)
|
|
{
|
|
switch (IntType) {
|
|
case INT_TYPE_INTR:
|
|
return "intr ";
|
|
case INT_TYPE_NMI:
|
|
return "nmi ";
|
|
case INT_TYPE_SMI:
|
|
return "smi ";
|
|
case INT_TYPE_EXTINT:
|
|
return "extint";
|
|
default:
|
|
return "unknwn";
|
|
}
|
|
}
|
|
|
|
PUCHAR
|
|
mpsExtAddrTypeToText(
|
|
UCHAR AddressType
|
|
)
|
|
{
|
|
switch (AddressType) {
|
|
case MPS_ADDRESS_MAP_IO:
|
|
return "io port ";
|
|
case MPS_ADDRESS_MAP_MEMORY:
|
|
return "memory ";
|
|
case MPS_ADDRESS_MAP_PREFETCH_MEMORY:
|
|
return "prefetch mem";
|
|
case MPS_ADDRESS_MAP_UNDEFINED:
|
|
return "mps undef ";
|
|
default:
|
|
return "unknown type";
|
|
}
|
|
}
|
|
|
|
PUCHAR
|
|
mpsExtCompatibleListToText(
|
|
ULONG List
|
|
)
|
|
{
|
|
switch (List) {
|
|
case 0:
|
|
return "ISA";
|
|
case 1:
|
|
return "VGA";
|
|
default:
|
|
return "unknown predefined range";
|
|
}
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
mpsBaseTable(
|
|
ULONG64 BaseTableAddress,
|
|
ULONG EntryCount
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Dumps entries from the MPS BASE table.
|
|
|
|
Arguments:
|
|
|
|
BaseTableAddress Address (in local memory) of the Base Entry Table
|
|
EntryCount Number of entries in this table.
|
|
|
|
Return Value:
|
|
|
|
TRUE is all is well
|
|
FALSE if execution cannot continue (ie we encountered an unknown
|
|
entry type. Can't continue because we don't know how big
|
|
it is.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG64 bp = BaseTableAddress;
|
|
ULONG offset;
|
|
ULONG featureFlags;
|
|
ULONG64 cpuAddr;
|
|
ULONG Family, Model, Stepping;
|
|
CHAR busId[8] = {0};
|
|
CPUIDENTIFIER cpuId;
|
|
|
|
//dprintf("BaseTableAddress: %x%x\n", BaseTableAddress);
|
|
|
|
while (EntryCount--) {
|
|
ULONG64 CharAtAddress;
|
|
|
|
GetFieldValue(bp, "UCHAR", NULL, CharAtAddress);
|
|
//dprintf("CharAtAddress: %x%x %x\n", bp, CharAtAddress);
|
|
dprintf(" ");
|
|
switch ((UCHAR) CharAtAddress) {
|
|
case ENTRY_PROCESSOR:
|
|
{
|
|
InitTypeRead(bp, hal!_PcMpProcessorEntry);
|
|
|
|
dprintf(
|
|
"processor. %s%sL.APIC ID %02x Vers %02x\n",
|
|
(ULONG) ReadField(CpuFlags) & CPU_ENABLED ? "EN " : "",
|
|
(ULONG) ReadField(CpuFlags) & BSP_CPU ? "BP " : "",
|
|
(ULONG) ReadField(LocalApicId),
|
|
(ULONG) ReadField(LocalApicVersion)
|
|
);
|
|
|
|
featureFlags = (ULONG)ReadField(FeatureFlags);
|
|
|
|
GetFieldOffset("hal!_PcMpProcessorEntry", "CpuIdentification", &offset);
|
|
cpuAddr = (bp + offset);
|
|
|
|
xReadMemory(cpuAddr, &cpuId, 4);
|
|
|
|
dprintf(
|
|
" Family %x, Model %x, Stepping %x, CPUID Flags %04x\n",
|
|
cpuId.Family,
|
|
cpuId.Model,
|
|
cpuId.Stepping,
|
|
featureFlags
|
|
);
|
|
|
|
bp += GetTypeSize("hal!_PcMpProcessorEntry");
|
|
}
|
|
break;
|
|
case ENTRY_BUS:
|
|
{
|
|
GetFieldOffset("hal!_PcMpBusEntry", "BusType", &offset);
|
|
xReadMemory((bp + offset), busId, 6);
|
|
|
|
InitTypeRead(bp, hal!_PcMpBusEntry);
|
|
dprintf(
|
|
"bus. id %02x, type %6.6s\n",
|
|
(ULONG) ReadField(BusId),
|
|
busId
|
|
);
|
|
|
|
bp += GetTypeSize("hal!_PcMpBusEntry");
|
|
}
|
|
break;
|
|
case ENTRY_IOAPIC:
|
|
{
|
|
InitTypeRead(bp, hal!_PcMpIoApicEntry);
|
|
bp += GetTypeSize("hal!_PcMpIoApicEntry");
|
|
|
|
dprintf(
|
|
"io apic. %s id %02x vers %02x @ %08x\n",
|
|
(ULONG) ReadField(IoApicFlag) & IO_APIC_ENABLED ? "EN" : "DI",
|
|
(ULONG) ReadField(IoApicId),
|
|
(ULONG) ReadField(IoApicVersion),
|
|
(ULONG) ReadField(IoApicAddress)
|
|
);
|
|
}
|
|
break;
|
|
case ENTRY_INTI:
|
|
{
|
|
InitTypeRead(bp, hal!_PcMpApicIntiEntry);
|
|
bp += GetTypeSize("hal!_PcMpApicIntiEntry");
|
|
|
|
dprintf(
|
|
"io int. %s po=%x el=%x, srcbus %02x irq %02x dst apic %02x intin %02x\n",
|
|
mpsGetIntTypeDesc((UCHAR) ReadField(IntType)),
|
|
(ULONG) ReadField(Signal.Polarity),
|
|
(ULONG) ReadField(Signal.Level),
|
|
(ULONG) ReadField(SourceBusId),
|
|
(ULONG) ReadField(SourceBusIrq),
|
|
(ULONG) ReadField(IoApicId),
|
|
(ULONG) ReadField(IoApicInti)
|
|
);
|
|
}
|
|
break;
|
|
case ENTRY_LINTI:
|
|
{
|
|
InitTypeRead(bp, hal!_PcMpLintiEntry);
|
|
bp += GetTypeSize("hal!_PcMpLintiEntry");
|
|
|
|
dprintf(
|
|
"lcl int. %s po=%x el=%x, srcbus %02x irq %02x dst apic %02x intin %02x\n",
|
|
mpsGetIntTypeDesc((UCHAR) ReadField(IntType)),
|
|
(ULONG) ReadField(Signal.Polarity),
|
|
(ULONG) ReadField(Signal.Level),
|
|
(ULONG) ReadField(SourceBusId),
|
|
(ULONG) ReadField(SourceBusIrq),
|
|
(ULONG) ReadField(DestLocalApicId),
|
|
(ULONG) ReadField(DestLocalApicInti)
|
|
);
|
|
}
|
|
break;
|
|
default:
|
|
dprintf(
|
|
"Unknown MPS base type 0x%02x, cannot continue.\n",
|
|
CharAtAddress
|
|
);
|
|
return FALSE;
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
mpsExtendedTable(
|
|
ULONG64 ExtendedTableAddress,
|
|
ULONG64 ExtendedTableAddressEnd
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Dumps entries from the MPS Extended table.
|
|
|
|
Arguments:
|
|
|
|
BaseTableAddress Address (in local memory) of the Base Entry Table
|
|
EntryCount Number of entries in this table.
|
|
|
|
Return Value:
|
|
|
|
TRUE is all is well
|
|
FALSE if execution cannot continue (ie we encountered an unknown
|
|
entry type. Can't continue because we don't know how big
|
|
it is.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG64 bp = ExtendedTableAddress;
|
|
|
|
if (!bp) {
|
|
return TRUE;
|
|
}
|
|
dprintf(" extended table entries\n");
|
|
|
|
while (bp < ExtendedTableAddressEnd) {
|
|
|
|
if (InitTypeRead(bp, hal!MPS_EXTENTRY)) {
|
|
dprintf("Cannot get hal!MPS_EXTENTRY at %p\n", bp);
|
|
return FALSE;
|
|
}
|
|
|
|
if (ReadField(Length) == 0) {
|
|
dprintf("Malformed extended entry, length = 0, cannot continue.\n");
|
|
return FALSE;
|
|
}
|
|
|
|
dprintf(" ");
|
|
|
|
switch ((ULONG) ReadField(Type)) {
|
|
case EXTTYPE_BUS_ADDRESS_MAP:
|
|
dprintf(
|
|
"address. bus %02x %s % 16I64x len %16I64x\n",
|
|
(ULONG) ReadField(u.AddressMap.BusId),
|
|
mpsExtAddrTypeToText((UCHAR) ReadField(u.AddressMap.Type)),
|
|
ReadField(u.AddressMap.Base),
|
|
ReadField(u.AddressMap.Length)
|
|
);
|
|
break;
|
|
case EXTTYPE_BUS_HIERARCHY:
|
|
dprintf(
|
|
"child bus. bus %02x is child of bus %02x%s\n",
|
|
(ULONG) ReadField(u.BusHierarchy.BusId),
|
|
(ULONG) ReadField(u.BusHierarchy.ParentBusId),
|
|
(ULONG) ReadField(u.BusHierarchy.SubtractiveDecode) ? " subtractive" : ""
|
|
);
|
|
break;
|
|
case EXTTYPE_BUS_COMPATIBLE_MAP:
|
|
dprintf(
|
|
"bus comp. bus %02x %s %s ranges\n",
|
|
(ULONG) ReadField(u.CompatibleMap.BusId),
|
|
(ULONG) ReadField(u.CompatibleMap.Modifier) ? "exclude" : "include",
|
|
mpsExtCompatibleListToText((ULONG) ReadField(u.CompatibleMap.List))
|
|
);
|
|
break;
|
|
case EXTTYPE_PERSISTENT_STORE:
|
|
dprintf(
|
|
"persist. % 16I64x len %16I64x\n",
|
|
ReadField(u.PersistentStore.Address),
|
|
ReadField(u.PersistentStore.Length)
|
|
);
|
|
break;
|
|
default:
|
|
dprintf(
|
|
"Unknown MPS extended type 0x%02x, cannot continue.\n",
|
|
(ULONG) ReadField(Type)
|
|
);
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Advance to the next entry.
|
|
//
|
|
|
|
bp += (ULONG) ReadField(Length);
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
DECLARE_API( mps )
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Dumps the MPS (Multi Processor Specification) BIOS Tables.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG64 addr;
|
|
UCHAR halName[32];
|
|
UCHAR OemId[20]={0}, OemProductId[20]={0};
|
|
ULONG64 PcMpTablePtr;
|
|
ULONG entryCount;
|
|
PUCHAR bp;
|
|
UCHAR c;
|
|
ULONG i, TableLength, ExtTableLength, Sz;
|
|
UCHAR PcMpCfgTable[100];
|
|
PUCHAR MpsBaseTable = NULL;
|
|
PUCHAR MpsExtendedTable = NULL;
|
|
PUCHAR MpsExtendedTableEnd;
|
|
ULONG OemOffset, SigOffset, Sig = 0;
|
|
ULONG BiosRev = 0;
|
|
|
|
BOOLEAN halNameKnown = FALSE;
|
|
|
|
if (TargetIsDump) {
|
|
dprintf("!mps doesnt work on dump targets\n");
|
|
return E_INVALIDARG;
|
|
}
|
|
//
|
|
// Check to see if user entered the address of the MPS tables.
|
|
// If not, try to obtain it using HAL symbols.
|
|
//
|
|
|
|
PcMpTablePtr = GetExpression(args);
|
|
if (PcMpTablePtr == 0) {
|
|
|
|
//
|
|
// Get address of PC+MP structure from the HAL.
|
|
// N.B. Should add code to allow hunting for the floating pointer.
|
|
//
|
|
|
|
addr = GetExpression("hal!HalName");
|
|
|
|
if (addr == 0) {
|
|
dprintf(
|
|
"Unable to use HAL symbols (hal!HalName), please verify symbols.\n"
|
|
);
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if (!xReadMemory(addr, halName, sizeof(halName))) {
|
|
dprintf(
|
|
"Failed to read HalName from host memory, quitting.\n"
|
|
);
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
halName[sizeof(halName)-1] = '\0';
|
|
if (strstr(halName, "MPS ") == NULL) {
|
|
dprintf("HAL = \"%s\".\n", halName);
|
|
dprintf("HAL does not appear to be an MPS HAL, quitting.\n");
|
|
return E_INVALIDARG;
|
|
}
|
|
halNameKnown = TRUE;
|
|
|
|
addr = GetExpression("hal!PcMpTablePtr");
|
|
|
|
if (addr == 0) {
|
|
dprintf(
|
|
"Unable to get address of hal!PcMpTablePtr, cannot continue.\n"
|
|
);
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if (!ReadPointer(addr, &PcMpTablePtr)) {
|
|
dprintf(
|
|
"Failed to read PcMpTablePtr from host memory, cannot continue.\n"
|
|
);
|
|
return E_INVALIDARG;
|
|
}
|
|
}
|
|
|
|
if (InitTypeRead(PcMpTablePtr, hal!PcMpTable)) {
|
|
dprintf(
|
|
"Failed to read MP Configuration Table Header @%08p\n"
|
|
"Cannot continue.\n",
|
|
PcMpTablePtr
|
|
);
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
GetFieldOffset("hal!PcMpTable", "Signature", &SigOffset);
|
|
xReadMemory(PcMpTablePtr + SigOffset, &Sig, sizeof(Sig));
|
|
|
|
if (Sig != PCMP_SIGNATURE) {
|
|
dprintf(
|
|
"MP Config Table Signature doesn't match. Cannot continue.\n"
|
|
);
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
dprintf(" BIOS Revision ");
|
|
|
|
BiosRev = (ULONG) ReadField(Revision);
|
|
switch (BiosRev) {
|
|
case 1:
|
|
dprintf(
|
|
"MPS 1.1 (WARNING: This BIOS might not support NT 5 depending\n"
|
|
" upon system configuration.)\n"
|
|
);
|
|
break;
|
|
case 4:
|
|
dprintf(
|
|
"MPS 1.4 "
|
|
);
|
|
break;
|
|
default:
|
|
dprintf(
|
|
"Unknown MPS revision byte 0x%2x, dumped values\n"
|
|
" may be incorrect.\n",
|
|
BiosRev);
|
|
break;
|
|
}
|
|
|
|
if (halNameKnown) {
|
|
dprintf(" HAL = %s", halName);
|
|
}
|
|
dprintf("\n");
|
|
|
|
GetFieldOffset("hal!PcMpTable", "OemId", &OemOffset);
|
|
xReadMemory(PcMpTablePtr + OemOffset, OemId, 8);
|
|
|
|
dprintf(
|
|
" OEM ID :%s\n",
|
|
OemId
|
|
);
|
|
|
|
GetFieldOffset("hal!PcMpTable", "OemProductId", &OemOffset);
|
|
xReadMemory(PcMpTablePtr + OemOffset, OemProductId, 12);
|
|
|
|
dprintf(
|
|
" OEM Product ID :%s\n",
|
|
OemProductId
|
|
);
|
|
|
|
TableLength = (ULONG) ReadField(TableLength);
|
|
Sz = GetTypeSize("hal!PcMpTable");
|
|
if (TableLength <= Sz) {
|
|
dprintf(
|
|
"MPS Base Table length (%d) is too small to be reasonable,\n",
|
|
TableLength
|
|
);
|
|
dprintf(
|
|
"Must be >= sizeof(fixed table header) (%d bytes). "
|
|
"Cannot continue.\n",
|
|
Sz
|
|
);
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
//
|
|
// Get memory for the base and extended tables and read them from
|
|
// memory.
|
|
//
|
|
|
|
MpsBaseTable = malloc( TableLength - Sz);
|
|
if (!MpsBaseTable) {
|
|
dprintf(
|
|
"Could not allocate %d bytes local memory, quitting.\n",
|
|
TableLength - Sz
|
|
);
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
if (!xReadMemory(PcMpTablePtr + Sz,
|
|
MpsBaseTable,
|
|
TableLength - Sz)) {
|
|
dprintf("Failed to read MPS Base Table from host memory. Quitting.\n");
|
|
goto cleanup;
|
|
}
|
|
|
|
if (ExtTableLength = (ULONG) ReadField(ExtTableLength)) {
|
|
MpsExtendedTable = malloc(ExtTableLength);
|
|
if (!MpsExtendedTable) {
|
|
dprintf(
|
|
"Could not allocate %d bytes local memory for extended MPS Table, quitting.\n",
|
|
ExtTableLength
|
|
);
|
|
goto cleanup;
|
|
}
|
|
|
|
if (!xReadMemory(PcMpTablePtr + TableLength,
|
|
MpsExtendedTable,
|
|
ExtTableLength)) {
|
|
dprintf(
|
|
"Could not read MPS Extended table from host memory.\n"
|
|
"Will attempt to dump base structures.\n"
|
|
);
|
|
free(MpsExtendedTable);
|
|
MpsExtendedTable = NULL;
|
|
}
|
|
MpsExtendedTableEnd = MpsExtendedTable + ExtTableLength;
|
|
}
|
|
|
|
//
|
|
// Validate checksums.
|
|
//
|
|
// Base checksum is the sum of all bytes (inc checksum) in the
|
|
// base table (including the fixed header).
|
|
//
|
|
|
|
c = 0;
|
|
|
|
//
|
|
// Sum fixed header.
|
|
//
|
|
|
|
if (Sz > sizeof(PcMpCfgTable)) {
|
|
return E_INVALIDARG;
|
|
}
|
|
xReadMemory(PcMpTablePtr, PcMpCfgTable, Sz);
|
|
bp = (PUCHAR)&PcMpCfgTable[0];
|
|
for (i = 0; i < Sz; i++) {
|
|
c += *bp++;
|
|
}
|
|
|
|
//
|
|
// Add rest of base table.
|
|
//
|
|
|
|
bp = MpsBaseTable;
|
|
for (i = 0; i < TableLength - Sz; i++) {
|
|
c += *bp++;
|
|
}
|
|
|
|
//
|
|
// The result should be zero.
|
|
//
|
|
|
|
if (c) {
|
|
dprintf(
|
|
"MPS Base Table checksum is in error.\n"
|
|
"Found 0x%02x, Computed 0x%02x (Total 0x%02x).\n",
|
|
(ULONG) ReadField(Checksum),
|
|
(UCHAR)(c - (UCHAR) ReadField(Checksum)),
|
|
c
|
|
);
|
|
}
|
|
|
|
//
|
|
// Now do the extended table checksum. This one doesn't include
|
|
// itself so we should just match (rather than end up with zero).
|
|
//
|
|
|
|
if (MpsExtendedTable) {
|
|
c = 0;
|
|
bp = MpsExtendedTable;
|
|
for (i = 0; i < ExtTableLength; i++) {
|
|
c += *bp++;
|
|
}
|
|
|
|
//
|
|
// To sum to zero it needs to end up being it's opposite.
|
|
//
|
|
|
|
c = -c;
|
|
|
|
if (c != (UCHAR) ReadField(ExtTableChecksum)) {
|
|
dprintf(
|
|
"MPS Extended Table checksum is in error.\n"
|
|
"Found 0x%02x, Computed 0x%02x.\n",
|
|
(ULONG) ReadField(ExtTableChecksum),
|
|
c
|
|
);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Dump the base table.
|
|
//
|
|
|
|
if (!mpsBaseTable(PcMpTablePtr + Sz, (ULONG) ReadField(NumOfEntries))) {
|
|
goto cleanup;
|
|
}
|
|
|
|
|
|
//
|
|
// Dump the extended table.
|
|
//
|
|
|
|
if (!mpsExtendedTable(PcMpTablePtr + TableLength, PcMpTablePtr + TableLength + ExtTableLength )) {
|
|
goto cleanup;
|
|
}
|
|
|
|
cleanup:
|
|
if (MpsBaseTable) {
|
|
free(MpsBaseTable);
|
|
}
|
|
if (MpsExtendedTable) {
|
|
free(MpsExtendedTable);
|
|
}
|
|
return S_OK;
|
|
}
|