windows-nt/Source/XPSP1/NT/base/tools/kdexts2/mps.c
2020-09-26 16:20:57 +08:00

671 lines
17 KiB
C

/*++
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;
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 ");
switch ((ULONG) ReadField(Revision)) {
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"
);
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;
}