mirror of https://github.com/tongzx/nt5src
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.
1091 lines
32 KiB
1091 lines
32 KiB
/*++
|
|
|
|
Copyright (c) 1992 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
pci.c
|
|
|
|
Abstract:
|
|
|
|
WinDbg Extension Api
|
|
|
|
Author:
|
|
|
|
Ken Reneris (kenr) 18-August-1997
|
|
|
|
Environment:
|
|
|
|
User Mode.
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#include "pci.h"
|
|
#pragma hdrstop
|
|
|
|
|
|
#define DUMP_VERBOSE 0x01
|
|
#define DUMP_TO_MAX_BUS 0x02 // from 0 to max
|
|
#define DUMP_RAW_BYTES 0x04 // hex dump dump raw bytes
|
|
#define DUMP_RAW_DWORDS 0x08 // hex dump dump raw dwords
|
|
|
|
#define DUMP_ALLOW_INVALID_DEVICE 0x10
|
|
#define DUMP_ALLOW_INVALID_FUNCTION 0x20
|
|
#define DUMP_CAPABILITIES 0x40
|
|
#define DUMP_INTEL 0x80
|
|
|
|
#define DUMP_CONFIGSPACE 0x100
|
|
|
|
|
|
|
|
|
|
#define ANY 0xFF
|
|
|
|
PSZ GetClassDesc(BYTE bBaseClass, BYTE bSubClass, BYTE bProgIF);
|
|
|
|
UCHAR PCIDeref[4][4] = { {4,1,2,2},{1,1,1,1},{2,1,2,2},{1,1,1,1} };
|
|
|
|
VOID
|
|
DumpCfgSpace (
|
|
IN PPCI_COMMON_CONFIG pcs
|
|
);
|
|
|
|
VOID
|
|
HexDump (
|
|
IN ULONG indent,
|
|
IN ULONG va,
|
|
IN ULONG len,
|
|
IN ULONG width,
|
|
IN PUCHAR buf
|
|
)
|
|
{
|
|
UCHAR s[80], t[80];
|
|
PUCHAR ps, pt;
|
|
ULONG i;
|
|
static UCHAR rgHexDigit[] = "0123456789abcdef";
|
|
|
|
i = 0;
|
|
|
|
//
|
|
// If width = 4, dull dump, similar to debugger's dd command.
|
|
//
|
|
|
|
if (width == 4) {
|
|
if (len & 3) {
|
|
dprintf("hexdump internal error, dump dword, (len & 3) != 0\n");
|
|
|
|
// round up.
|
|
|
|
len += 3;
|
|
len &= ~3;
|
|
}
|
|
while (len) {
|
|
if (i == 0) {
|
|
dprintf("%*s%08x: ", indent, "", va);
|
|
va += 16;
|
|
}
|
|
dprintf(" %08x", *(ULONG UNALIGNED *)buf);
|
|
len -= 4;
|
|
buf += 4;
|
|
if (i == 3) {
|
|
dprintf("\n");
|
|
i = 0;
|
|
} else {
|
|
i++;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (width != 1) {
|
|
dprintf ("hexdump internal error\n");
|
|
return ;
|
|
}
|
|
|
|
//
|
|
// Width = 1, pretty dump, similar to debugger's db command.
|
|
//
|
|
|
|
while (len) {
|
|
ps = s;
|
|
pt = t;
|
|
|
|
ps[0] = 0;
|
|
pt[0] = '*';
|
|
pt++;
|
|
|
|
for (i=0; i < 16; i++) {
|
|
ps[0] = ' ';
|
|
ps[1] = ' ';
|
|
ps[2] = ' ';
|
|
|
|
if (len) {
|
|
ps[0] = rgHexDigit[buf[0] >> 4];
|
|
ps[1] = rgHexDigit[buf[0] & 0xf];
|
|
pt[0] = buf[0] < ' ' || buf[0] > 'z' ? '.' : buf[0];
|
|
|
|
len -= 1;
|
|
buf += 1;
|
|
pt += 1;
|
|
}
|
|
ps += 3;
|
|
}
|
|
|
|
ps[0] = 0;
|
|
pt[0] = '*';
|
|
pt[1] = 0;
|
|
s[23] = '-';
|
|
|
|
if (s[0]) {
|
|
dprintf ("%*s%08lx: %s %s\n", indent, "", va, s, t);
|
|
va += 16;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
BOOL
|
|
ReadPci (
|
|
IN PPCI_TYPE1_CFG_BITS PciCfg1,
|
|
OUT PUCHAR Buffer,
|
|
IN ULONG Offset,
|
|
IN ULONG Length
|
|
)
|
|
{
|
|
ULONG InputSize;
|
|
ULONG IoSize;
|
|
ULONG i;
|
|
BUSDATA busData;
|
|
PCI_SLOT_NUMBER slot;
|
|
BOOL b;
|
|
|
|
//
|
|
// Zap input buffer
|
|
//
|
|
|
|
for (i=0; i < Length; i++) {
|
|
Buffer[i] = 0xff;
|
|
}
|
|
|
|
//
|
|
// It appears that we are only safe to call the HAL for reading
|
|
// configuration space if the HAL has actually been initialized far
|
|
// enough to do so. Since we have already hit a case where we hadnt
|
|
// initialized everything and it crashed the debugger, we are restoring
|
|
// X86 so that it reads configspace the way it always used to do.
|
|
//
|
|
// For non-X86 (i.e IA64) we are forced to call the HAL because we
|
|
// currently have no other option. This means we may still crash on
|
|
// those platforms in the case where
|
|
// the HAL hasnt been initialized enough to handle it.
|
|
//
|
|
|
|
if (TargetMachine == IMAGE_FILE_MACHINE_I386) {
|
|
|
|
while (Length) {
|
|
PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG);
|
|
IoSize = sizeof(ULONG);
|
|
#ifdef IG_IO_SPACE_RETURN
|
|
b =
|
|
#else
|
|
b = TRUE;
|
|
#endif
|
|
WriteIoSpace64 ( PCI_TYPE1_ADDR_PORT, PciCfg1->u.AsULONG, &IoSize );
|
|
if (!b) {
|
|
return FALSE;
|
|
}
|
|
IoSize = PCIDeref[Offset % sizeof(ULONG)][Length % sizeof(ULONG)];
|
|
i = IoSize;
|
|
|
|
ReadIoSpace64 (
|
|
PCI_TYPE1_DATA_PORT + (Offset % sizeof(ULONG)),
|
|
(PULONG) Buffer,
|
|
&i
|
|
);
|
|
|
|
Offset += IoSize;
|
|
Buffer += IoSize;
|
|
Length -= IoSize;
|
|
}
|
|
}else{
|
|
|
|
//
|
|
// Here we are going to call the debugger api that results in the
|
|
// call to HalGetBusDataByOffset for the read.
|
|
//
|
|
// Note: This will crash the current debug session of attempted too
|
|
// early in boot.
|
|
//
|
|
|
|
slot.u.AsULONG = 0;
|
|
slot.u.bits.DeviceNumber = PciCfg1->u.bits.DeviceNumber;
|
|
slot.u.bits.FunctionNumber = PciCfg1->u.bits.FunctionNumber;
|
|
|
|
busData.BusDataType = PCIConfiguration;
|
|
busData.BusNumber = PciCfg1->u.bits.BusNumber;
|
|
busData.SlotNumber = slot.u.AsULONG;
|
|
busData.Offset = Offset;
|
|
busData.Buffer = Buffer;
|
|
busData.Length = Length;
|
|
|
|
//
|
|
// Read it
|
|
//
|
|
#ifdef IG_IO_SPACE_RETURN
|
|
b =
|
|
#else
|
|
b = TRUE;
|
|
#endif
|
|
Ioctl(IG_GET_BUS_DATA, &busData, sizeof(busData));
|
|
if (!b) {
|
|
return FALSE;
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN
|
|
WritePci (
|
|
IN PPCI_TYPE1_CFG_BITS PciCfg1,
|
|
IN PUCHAR Buffer,
|
|
IN ULONG Offset,
|
|
IN ULONG Length
|
|
)
|
|
{
|
|
|
|
ULONG IoSize;
|
|
ULONG i;
|
|
BUSDATA busData;
|
|
PCI_SLOT_NUMBER slot;
|
|
|
|
if (TargetMachine == IMAGE_FILE_MACHINE_I386) {
|
|
|
|
//
|
|
// For the same reasons as the read, we are only calling the HAL
|
|
// on non-x86 targets for now.
|
|
//
|
|
|
|
while (Length) {
|
|
PciCfg1->u.bits.RegisterNumber = Offset / sizeof(ULONG);
|
|
IoSize = sizeof(ULONG);
|
|
WriteIoSpace64 ((ULONG) PCI_TYPE1_ADDR_PORT, PciCfg1->u.AsULONG, &IoSize );
|
|
|
|
IoSize = PCIDeref[Offset % sizeof(ULONG)][Length % sizeof(ULONG)];
|
|
i = IoSize;
|
|
|
|
WriteIoSpace64 (
|
|
PCI_TYPE1_DATA_PORT + (Offset % sizeof(ULONG)),
|
|
*(PULONG)Buffer,
|
|
&i);
|
|
|
|
Offset += IoSize;
|
|
Buffer += IoSize;
|
|
Length -= IoSize;
|
|
}
|
|
}else{
|
|
|
|
slot.u.AsULONG = 0;
|
|
slot.u.bits.DeviceNumber = PciCfg1->u.bits.DeviceNumber;
|
|
slot.u.bits.FunctionNumber = PciCfg1->u.bits.FunctionNumber;
|
|
|
|
busData.BusDataType = PCIConfiguration;
|
|
busData.BusNumber = PciCfg1->u.bits.BusNumber;
|
|
busData.SlotNumber = slot.u.AsULONG;
|
|
busData.Offset = Offset;
|
|
busData.Buffer = Buffer;
|
|
busData.Length = Length;
|
|
|
|
//
|
|
// Write it
|
|
//
|
|
if (!(Ioctl(IG_SET_BUS_DATA, &busData, sizeof(busData)))){
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
VOID
|
|
DumpPciBar (
|
|
IN ULONG barno,
|
|
IN ULONG indent,
|
|
IN ULONG bar,
|
|
IN OUT PULONG state
|
|
)
|
|
{
|
|
ULONG type, i;
|
|
CHAR m[20], str[80];
|
|
|
|
if (bar) {
|
|
|
|
if (bar & 1) {
|
|
sprintf (str, "IO[%d]:%x ", barno, bar);
|
|
|
|
} else {
|
|
type = (bar >> 1) & 0x3;
|
|
|
|
if (bar & 8) {
|
|
strcpy (m, "MPF");
|
|
} else {
|
|
strcpy (m, "MEM");
|
|
}
|
|
|
|
if (type == 0x01) {
|
|
m[1] = '1'; // less then 1M
|
|
}
|
|
|
|
sprintf (str, "%s[%d]:%x ", m, barno, bar);
|
|
|
|
if (type == 0x10) {
|
|
dprintf ("warning - 64bit bar not decoded\n");
|
|
*state = 0;
|
|
}
|
|
if (type == 0x11) {
|
|
dprintf ("bar type is reserved\n");
|
|
*state = 0;
|
|
}
|
|
}
|
|
|
|
if (!*state) {
|
|
dprintf ("%*s", indent, "");
|
|
}
|
|
|
|
i = strlen(str);
|
|
dprintf("%s%*s", str, 17-i, "");
|
|
*state += i;
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
DumpPciType2Bar(
|
|
IN BOOLEAN barIsIo,
|
|
IN BOOLEAN barIsBase,
|
|
IN ULONG barno,
|
|
IN ULONG indent,
|
|
IN ULONG bar,
|
|
IN OUT PULONG state
|
|
)
|
|
{
|
|
ULONG i;
|
|
CHAR str[80];
|
|
if (bar) {
|
|
if (barIsIo) {
|
|
sprintf (str, "IO[%d].%s:%x ", barno, (barIsBase?"base":"limit"), bar);
|
|
} else {
|
|
sprintf (str, "MEM[%d].%s:%x ", barno, (barIsBase?"base":"limit"), bar);
|
|
}
|
|
if (!*state) {
|
|
dprintf("%*s", indent, "");
|
|
}
|
|
i = strlen(str);
|
|
dprintf("%s%*s", str, 17-i, "");
|
|
*state += i;
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
DumpPciBarComplete(
|
|
IN OUT PULONG state
|
|
)
|
|
{
|
|
if (*state) {
|
|
dprintf ("\n");
|
|
*state = 0;
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
DumpCapabilities(
|
|
IN UCHAR CapPtr,
|
|
IN PPCI_TYPE1_CFG_BITS PciCfg1
|
|
)
|
|
{
|
|
union _cap_buffer {
|
|
PCI_CAPABILITIES_HEADER header;
|
|
PCI_PM_CAPABILITY pm;
|
|
PCI_AGP_CAPABILITY agp;
|
|
} cap;
|
|
|
|
PCHAR ts;
|
|
ULONG t;
|
|
|
|
do {
|
|
if (CapPtr < PCI_COMMON_HDR_LENGTH) {
|
|
|
|
dprintf(" Error: Capability pointer 0x%02x points to common header (invalid).\n",
|
|
CapPtr
|
|
);
|
|
break;
|
|
}
|
|
|
|
if (CapPtr & 0x3) {
|
|
|
|
dprintf(" Error: Capability pointer 0x%02x not DWORD aligned (invalid).\n",
|
|
CapPtr
|
|
);
|
|
break;
|
|
}
|
|
|
|
ReadPci (
|
|
PciCfg1,
|
|
(PUCHAR)&cap,
|
|
CapPtr,
|
|
sizeof(cap.header)
|
|
);
|
|
|
|
switch (cap.header.CapabilityID) {
|
|
case PCI_CAPABILITY_ID_POWER_MANAGEMENT:
|
|
|
|
ReadPci (
|
|
PciCfg1,
|
|
(PUCHAR)&cap,
|
|
CapPtr,
|
|
sizeof(cap.pm)
|
|
);
|
|
t = cap.pm.PMC.AsUSHORT;
|
|
dprintf(" Cap[%02x] ID %02x \n",
|
|
CapPtr,
|
|
cap.header.CapabilityID
|
|
);
|
|
dprintf(" PMC %04x (%s%s%s%s%s%s %s%s%s%s%s%sv%x)\n",
|
|
t,
|
|
t & 0xf800 ? "PME from D" : "<No PME>",
|
|
t & 0x8000 ? "3C" : "",
|
|
t & 0x4000 ? "3H" : "",
|
|
t & 0x2000 ? "2" : "",
|
|
t & 0x1000 ? "1" : "",
|
|
t & 0x0800 ? "0" : "",
|
|
t & 0x0600 ? "Supports D" : "",
|
|
cap.pm.PMC.Capabilities.Support.D2 ? "2" : "",
|
|
cap.pm.PMC.Capabilities.Support.D1 ? "1" : "",
|
|
t & 0x0600 ? " " : "",
|
|
cap.pm.PMC.Capabilities.DeviceSpecificInitialization ?
|
|
"DSI " : "",
|
|
cap.pm.PMC.Capabilities.PMEClock ? "PME needs Clock, " : "",
|
|
cap.pm.PMC.Capabilities.Version
|
|
);
|
|
|
|
t &= 0x01d0;
|
|
if (t) {
|
|
dprintf(" WARNING PMC non-zero reserved fields %04x\n",
|
|
t
|
|
);
|
|
}
|
|
|
|
t = cap.pm.PMCSR.AsUSHORT;
|
|
dprintf(" PMCSR %04x (PME_Status=%d PME_En=%d State=D%d%s)\n",
|
|
t,
|
|
cap.pm.PMCSR.ControlStatus.PMEStatus,
|
|
cap.pm.PMCSR.ControlStatus.PMEEnable,
|
|
cap.pm.PMCSR.ControlStatus.PowerState,
|
|
cap.pm.PMCSR.ControlStatus.PowerState == 3 ?
|
|
"hot" : ""
|
|
);
|
|
|
|
//
|
|
// Here would be a good time to run
|
|
// run down the data registers if
|
|
// they exist.
|
|
//
|
|
|
|
break;
|
|
|
|
case PCI_CAPABILITY_ID_AGP:
|
|
|
|
ReadPci (
|
|
PciCfg1,
|
|
(PUCHAR)&cap,
|
|
CapPtr,
|
|
sizeof(cap.agp)
|
|
);
|
|
|
|
switch (cap.agp.AGPStatus.Rate) {
|
|
case 1:
|
|
ts = "1X";
|
|
break;
|
|
case 2:
|
|
ts = "2X";
|
|
break;
|
|
case 3:
|
|
ts = "1,2X";
|
|
break;
|
|
default:
|
|
ts = "<inv>";
|
|
break;
|
|
}
|
|
t = *(PULONG)&cap.agp.AGPStatus;
|
|
|
|
dprintf(" Cap[%02x] ID %02x AGP mj/mn=%x/%x\n",
|
|
CapPtr,
|
|
cap.header.CapabilityID,
|
|
cap.agp.Major,
|
|
cap.agp.Minor
|
|
);
|
|
|
|
dprintf(" Status %08x (Rq:%02x SBA:%x Rate:%x (%s))\n",
|
|
t,
|
|
cap.agp.AGPStatus.RequestQueueDepthMaximum,
|
|
cap.agp.AGPStatus.SideBandAddressing,
|
|
cap.agp.AGPStatus.Rate,
|
|
ts
|
|
);
|
|
|
|
switch (cap.agp.AGPCommand.Rate) {
|
|
case 1:
|
|
ts = "1X";
|
|
break;
|
|
case 2:
|
|
ts = "2X";
|
|
break;
|
|
case 4:
|
|
ts = "4X";
|
|
break;
|
|
default:
|
|
ts = "<not set>";
|
|
break;
|
|
}
|
|
t = *(PULONG)&cap.agp.AGPCommand;
|
|
|
|
dprintf(" Command %08x (Rq:%02x SBA:%x AGP:%x Rate:%x (%s)\n",
|
|
t,
|
|
cap.agp.AGPCommand.RequestQueueDepth,
|
|
cap.agp.AGPCommand.SBAEnable,
|
|
cap.agp.AGPCommand.AGPEnable,
|
|
cap.agp.AGPCommand.Rate,
|
|
ts
|
|
);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
}
|
|
CapPtr = cap.header.Next;
|
|
} while (CapPtr != 0);
|
|
}
|
|
|
|
VOID
|
|
pcidump (
|
|
IN ULONG Flags,
|
|
IN ULONG MinBus,
|
|
IN ULONG MaxBus,
|
|
IN ULONG MinDevice,
|
|
IN ULONG MaxDevice,
|
|
IN ULONG MinFunction,
|
|
IN ULONG MaxFunction,
|
|
IN ULONG MinAddr,
|
|
IN ULONG MaxAddr
|
|
)
|
|
{
|
|
ULONG Bus, Device, Function;
|
|
PCI_TYPE1_CFG_BITS PciCfg1;
|
|
PCI_COMMON_CONFIG PciHdr;
|
|
BOOLEAN BusHeader, SkipLine, BarIsIo;
|
|
ULONG Type, Len, i;
|
|
UCHAR s[40];
|
|
PUCHAR Buf;
|
|
ULONG state;
|
|
ULONG bar, barno;
|
|
|
|
if (MinBus > 0xFF || MaxBus > 0xFF ||
|
|
MinDevice > PCI_MAX_DEVICES || MaxDevice > PCI_MAX_DEVICES ||
|
|
MinFunction > PCI_MAX_FUNCTION || MaxFunction > PCI_MAX_FUNCTION ||
|
|
MinAddr > 0xFF || MaxAddr > 0x100 || MinAddr > MaxAddr) {
|
|
|
|
dprintf ("Bad pci dump parameter\n");
|
|
|
|
//dprintf ("Flags %d MinBus %d MaxBus %d\n", Flags, MinBus, MaxBus);
|
|
//dprintf ("MinDev %d MaxDev %d MinFnc %d MinFnc %d\n", MinDevice, MaxDevice, MinFunction, MaxFunction);
|
|
|
|
return ;
|
|
}
|
|
|
|
//dprintf ("Flags %d MinAddr %d MaxAddr %d\n", Flags, MinAddr, MaxAddr);
|
|
|
|
for (Bus=MinBus; Bus <= MaxBus; Bus++) {
|
|
|
|
BusHeader = FALSE;
|
|
|
|
for (Device=MinDevice; Device <= MaxDevice; Device++) {
|
|
|
|
if (CheckControlC()) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Read the device ID
|
|
//
|
|
|
|
PciCfg1.u.AsULONG = 0;
|
|
PciCfg1.u.bits.BusNumber = Bus;
|
|
PciCfg1.u.bits.DeviceNumber = Device;
|
|
PciCfg1.u.bits.FunctionNumber = 0;
|
|
PciCfg1.u.bits.Enable = TRUE;
|
|
|
|
ReadPci (&PciCfg1, (PUCHAR) &PciHdr, 0, sizeof(ULONG));
|
|
|
|
//
|
|
// If not a valid ID, skip to next device
|
|
|
|
if (PciHdr.VendorID == PCI_INVALID_VENDORID) {
|
|
if (!(Flags & DUMP_ALLOW_INVALID_DEVICE)) {
|
|
dprintf ("%02x\r", Device);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
|
|
for (Function=MinFunction; Function <= MaxFunction; Function++) {
|
|
|
|
if (CheckControlC()) {
|
|
return;
|
|
}
|
|
|
|
PciCfg1.u.bits.FunctionNumber = Function;
|
|
|
|
//
|
|
// Read device ID
|
|
//
|
|
|
|
if (Function) {
|
|
ReadPci (&PciCfg1, (PUCHAR) &PciHdr, 0, sizeof(ULONG));
|
|
}
|
|
|
|
if (PciHdr.VendorID == PCI_INVALID_VENDORID) {
|
|
if (!(Flags & DUMP_ALLOW_INVALID_DEVICE)) {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Dump ID
|
|
//
|
|
|
|
if (!BusHeader) {
|
|
dprintf ("PCI Bus %d\n", Bus);
|
|
BusHeader = TRUE;
|
|
}
|
|
|
|
dprintf ("%02x:%x %04x:%04x",
|
|
Device,
|
|
Function,
|
|
PciHdr.VendorID,
|
|
PciHdr.DeviceID
|
|
);
|
|
|
|
//
|
|
// Read the rest of the common header
|
|
//
|
|
|
|
ReadPci (
|
|
&PciCfg1,
|
|
((PUCHAR) &PciHdr) + sizeof(ULONG),
|
|
0 + sizeof(ULONG),
|
|
PCI_COMMON_HDR_LENGTH
|
|
);
|
|
|
|
Type = PciHdr.HeaderType & ~PCI_MULTIFUNCTION;
|
|
|
|
if (Type == 0x7f && PciHdr.BaseClass == 0xff && PciHdr.SubClass == 0xff) {
|
|
if (!(Flags & DUMP_ALLOW_INVALID_FUNCTION)) {
|
|
dprintf (" bogus, skipping rest of device\n");
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Dump it
|
|
//
|
|
|
|
s[0] = PciHdr.Command & PCI_ENABLE_IO_SPACE ? 'i' : '.';
|
|
s[1] = PciHdr.Command & PCI_ENABLE_MEMORY_SPACE ? 'm' : '.';
|
|
s[2] = PciHdr.Command & PCI_ENABLE_BUS_MASTER ? 'b' : '.';
|
|
s[3] = PciHdr.Command & PCI_ENABLE_VGA_COMPATIBLE_PALETTE ? 'v' : '.';
|
|
s[4] = PciHdr.Command & PCI_ENABLE_PARITY ? 'p' : '.';
|
|
s[5] = PciHdr.Command & PCI_ENABLE_SERR ? 's' : '.';
|
|
s[6] = 0;
|
|
dprintf (".%02x Cmd[%04x:%s] ", PciHdr.RevisionID, PciHdr.Command, s);
|
|
|
|
s[0] = PciHdr.Status & PCI_STATUS_CAPABILITIES_LIST ? 'c' : '.';
|
|
s[1] = PciHdr.Status & PCI_STATUS_66MHZ_CAPABLE ? '6' : '.';
|
|
s[2] = PciHdr.Status & PCI_STATUS_DATA_PARITY_DETECTED ? 'P' : '.';
|
|
s[3] = PciHdr.Status & PCI_STATUS_SIGNALED_TARGET_ABORT ? 'A' : '.';
|
|
s[4] = PciHdr.Status & PCI_STATUS_SIGNALED_SYSTEM_ERROR ? 'S' : '.';
|
|
s[5] = 0;
|
|
dprintf ("Sts[%04x:%s] ", PciHdr.Status, s);
|
|
|
|
|
|
switch (Type) {
|
|
case PCI_DEVICE_TYPE:
|
|
dprintf ("Device");
|
|
|
|
if (PciHdr.u.type0.SubVendorID || PciHdr.u.type0.SubSystemID) {
|
|
dprintf (" SubID:%04x:%04x",
|
|
PciHdr.u.type0.SubVendorID,
|
|
PciHdr.u.type0.SubSystemID
|
|
);
|
|
}
|
|
break;
|
|
|
|
case PCI_BRIDGE_TYPE:
|
|
dprintf ("PciBridge %d->%d-%d",
|
|
PciHdr.u.type1.PrimaryBus,
|
|
PciHdr.u.type1.SecondaryBus,
|
|
PciHdr.u.type1.SubordinateBus
|
|
);
|
|
break;
|
|
|
|
case PCI_CARDBUS_BRIDGE_TYPE:
|
|
dprintf ("CardbusBridge %d->%d-%d",
|
|
PciHdr.u.type2.PrimaryBus,
|
|
PciHdr.u.type2.SecondaryBus,
|
|
PciHdr.u.type2.SubordinateBus
|
|
);
|
|
break;
|
|
|
|
default:
|
|
dprintf ("type %x", Type);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Search for a class code match
|
|
//
|
|
PCHAR Desc = GetClassDesc(PciHdr.BaseClass, PciHdr.SubClass, PciHdr.ProgIf);
|
|
|
|
if (Desc) {
|
|
dprintf (" %s", Desc);
|
|
} else {
|
|
dprintf (" Class:%x:%x:%x",
|
|
PciHdr.BaseClass,
|
|
PciHdr.SubClass,
|
|
PciHdr.ProgIf
|
|
);
|
|
}
|
|
|
|
dprintf ("\n");
|
|
SkipLine = FALSE;
|
|
|
|
if (Flags & DUMP_VERBOSE) {
|
|
SkipLine = TRUE;
|
|
PciCfg1.u.bits.RegisterNumber = 0;
|
|
switch (Type) {
|
|
case PCI_DEVICE_TYPE:
|
|
dprintf (" cf8:%x IntPin:%x IntLine:%x Rom:%x cis:%x cap:%x\n",
|
|
PciCfg1.u.AsULONG,
|
|
PciHdr.u.type0.InterruptPin,
|
|
PciHdr.u.type0.InterruptLine,
|
|
PciHdr.u.type0.ROMBaseAddress,
|
|
PciHdr.u.type0.CIS,
|
|
PciHdr.u.type0.CapabilitiesPtr
|
|
);
|
|
|
|
state = 0;
|
|
for (i=0; i < PCI_TYPE0_ADDRESSES; i++) {
|
|
bar = PciHdr.u.type0.BaseAddresses[i];
|
|
DumpPciBar(i, 6, bar, &state);
|
|
}
|
|
DumpPciBarComplete(&state);
|
|
break;
|
|
|
|
case PCI_BRIDGE_TYPE:
|
|
i = PciHdr.u.type1.BridgeControl;
|
|
dprintf (" cf8:%x IntPin:%x IntLine:%x Rom:%x cap:%x 2sts:%x BCtrl:%x%s%s%s\n",
|
|
PciCfg1.u.AsULONG,
|
|
PciHdr.u.type1.InterruptPin,
|
|
PciHdr.u.type1.InterruptLine,
|
|
PciHdr.u.type1.ROMBaseAddress,
|
|
PciHdr.u.type1.CapabilitiesPtr,
|
|
PciHdr.u.type1.SecondaryStatus,
|
|
PciHdr.u.type1.BridgeControl,
|
|
i & PCI_ENABLE_BRIDGE_VGA ? " VGA" : "",
|
|
i & PCI_ENABLE_BRIDGE_ISA ? " ISA" : "",
|
|
i & PCI_ASSERT_BRIDGE_RESET ? " RESET" : ""
|
|
);
|
|
|
|
dprintf (" IO:%x-%x Mem:%x-%x PMem:%x-%x\n",
|
|
PciBridgeIO2Base (PciHdr.u.type1.IOBase, PciHdr.u.type1.IOBaseUpper16),
|
|
PciBridgeIO2Limit(PciHdr.u.type1.IOLimit, PciHdr.u.type1.IOLimitUpper16),
|
|
PciBridgeMemory2Base (PciHdr.u.type1.MemoryBase),
|
|
PciBridgeMemory2Limit(PciHdr.u.type1.MemoryLimit),
|
|
PciBridgeMemory2Base (PciHdr.u.type1.PrefetchBase),
|
|
PciBridgeMemory2Limit(PciHdr.u.type1.PrefetchLimit)
|
|
);
|
|
|
|
state = 0;
|
|
for (i=0; i < PCI_TYPE1_ADDRESSES; i++) {
|
|
bar = PciHdr.u.type1.BaseAddresses[i];
|
|
DumpPciBar(i, 6, bar, &state);
|
|
}
|
|
DumpPciBarComplete(&state);
|
|
break;
|
|
|
|
case PCI_CARDBUS_BRIDGE_TYPE:
|
|
i = PciHdr.u.type2.BridgeControl;
|
|
dprintf (" cf8:%x IntPin:%x IntLine:%x SocketRegBase:%x cap:%x 2sts:%x BCtrl:%x%s%s%s\n",
|
|
PciCfg1.u.AsULONG,
|
|
PciHdr.u.type2.InterruptPin,
|
|
PciHdr.u.type2.InterruptLine,
|
|
PciHdr.u.type2.SocketRegistersBaseAddress,
|
|
PciHdr.u.type2.CapabilitiesPtr,
|
|
PciHdr.u.type2.SecondaryStatus,
|
|
PciHdr.u.type2.BridgeControl,
|
|
i & PCI_ENABLE_BRIDGE_VGA ? " VGA" : "",
|
|
i & PCI_ENABLE_BRIDGE_ISA ? " ISA" : "",
|
|
i & PCI_ASSERT_BRIDGE_RESET ? " RESET" : ""
|
|
);
|
|
dprintf("\n");
|
|
state=0;
|
|
for (i = 0; i < (PCI_TYPE2_ADDRESSES - 1); i++) {
|
|
bar = PciHdr.u.type2.Range[i].Base;
|
|
//
|
|
// First 2 BARs (base+limit) are memory
|
|
//
|
|
BarIsIo = (i > 1);
|
|
barno = i;
|
|
if (BarIsIo) {
|
|
barno -= 2;
|
|
}
|
|
DumpPciType2Bar(BarIsIo,TRUE, barno, 6, bar, &state);
|
|
|
|
bar = PciHdr.u.type2.Range[i].Limit;
|
|
DumpPciType2Bar(BarIsIo, FALSE, i, 6, bar, &state);
|
|
}
|
|
DumpPciBarComplete(&state);
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Dump CAPABILITIES if any.
|
|
//
|
|
|
|
if (Flags & DUMP_CAPABILITIES) {
|
|
if (PciHdr.Status & PCI_STATUS_CAPABILITIES_LIST) {
|
|
UCHAR capPtr = 0;
|
|
|
|
SkipLine = TRUE;
|
|
|
|
switch (Type) {
|
|
case PCI_DEVICE_TYPE:
|
|
capPtr = PciHdr.u.type0.CapabilitiesPtr;
|
|
break;
|
|
|
|
case PCI_BRIDGE_TYPE:
|
|
capPtr = PciHdr.u.type1.CapabilitiesPtr;
|
|
break;
|
|
|
|
case PCI_CARDBUS_BRIDGE_TYPE:
|
|
capPtr = PciHdr.u.type2.CapabilitiesPtr;
|
|
break;
|
|
}
|
|
|
|
if (capPtr != 0) {
|
|
DumpCapabilities(capPtr, &PciCfg1);
|
|
} else {
|
|
|
|
//
|
|
// Capabilities flag is set in Status but
|
|
// pointer is 0??? Something's broken.
|
|
//
|
|
|
|
dprintf(" Warning: Capability bit set in Status but capability pointer is 0.\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Dump hex bytes
|
|
//
|
|
|
|
if (Flags & DUMP_RAW_BYTES) {
|
|
|
|
ULONG w;
|
|
|
|
//
|
|
// Raw dump requested, if no range default to common
|
|
// config.
|
|
//
|
|
|
|
if (!MinAddr && !MaxAddr) {
|
|
MaxAddr = PCI_COMMON_HDR_LENGTH - 1;
|
|
}
|
|
|
|
//
|
|
// Default width to 1. If dumping dwords, set width
|
|
// width to 4 and round min and max accordingly.
|
|
//
|
|
|
|
w = 1;
|
|
if (Flags & DUMP_RAW_DWORDS) {
|
|
w = 4;
|
|
MinAddr &= ~3;
|
|
MaxAddr &= ~3;
|
|
MaxAddr += 3;
|
|
}
|
|
Buf = ((PUCHAR) &PciHdr) + MinAddr;
|
|
Len = MaxAddr - MinAddr + 1;
|
|
|
|
if (MinAddr <= PCI_COMMON_HDR_LENGTH) {
|
|
if (MaxAddr > PCI_COMMON_HDR_LENGTH) {
|
|
ReadPci (
|
|
&PciCfg1,
|
|
PciHdr.DeviceSpecific,
|
|
PCI_COMMON_HDR_LENGTH,
|
|
MaxAddr - PCI_COMMON_HDR_LENGTH
|
|
);
|
|
}
|
|
|
|
} else {
|
|
ReadPci (&PciCfg1, Buf, MinAddr, Len);
|
|
}
|
|
|
|
HexDump (w == 4 ? 6 : 1, MinAddr, Len, w, Buf);
|
|
SkipLine = TRUE;
|
|
|
|
} else if ((Flags & DUMP_INTEL) && PciHdr.VendorID == 0x8086) {
|
|
|
|
Buf = PciHdr.DeviceSpecific;
|
|
Len = sizeof (PciHdr) - PCI_COMMON_HDR_LENGTH;
|
|
|
|
ReadPci (&PciCfg1, Buf, PCI_COMMON_HDR_LENGTH, Len);
|
|
HexDump (1, PCI_COMMON_HDR_LENGTH, Len, 1, Buf);
|
|
SkipLine = TRUE;
|
|
}
|
|
|
|
if (Flags & DUMP_CONFIGSPACE) {
|
|
PCI_COMMON_CONFIG cs;
|
|
|
|
ReadPci(&PciCfg1, (PUCHAR)&cs, 0, sizeof(cs));
|
|
dprintf ("Config Space:\n",
|
|
PciCfg1.u.bits.BusNumber,
|
|
PciCfg1.u.bits.DeviceNumber,
|
|
PciCfg1.u.bits.FunctionNumber);
|
|
DumpCfgSpace(&cs);
|
|
dprintf ("\n");
|
|
}
|
|
|
|
if (SkipLine) {
|
|
dprintf ("\n");
|
|
}
|
|
|
|
//
|
|
// If no more functions on this device, skip the rest
|
|
// of the functions
|
|
//
|
|
|
|
if (Function == 0 && !(PciHdr.HeaderType & PCI_MULTIFUNCTION)) {
|
|
if (!(Flags & DUMP_ALLOW_INVALID_FUNCTION)) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
DECLARE_API( pci )
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Dumps pci type2 config data
|
|
|
|
Arguments:
|
|
|
|
args - Supplies the address in hex.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
LONG noargs;
|
|
ULONG Flags;
|
|
ULONG MinBus, MaxBus;
|
|
ULONG Device, MinDevice, MaxDevice;
|
|
ULONG Function, MinFunction, MaxFunction;
|
|
ULONG MinAddr, MaxAddr;
|
|
|
|
MinBus = 0;
|
|
MaxBus = 0;
|
|
MinDevice = 0;
|
|
MaxDevice = PCI_MAX_DEVICES - 1;
|
|
MinFunction = 0;
|
|
MaxFunction = PCI_MAX_FUNCTION - 1;
|
|
MinAddr = 0;
|
|
MaxAddr = 0;
|
|
Flags = 0;
|
|
|
|
if (g_TargetQual == DEBUG_DUMP_SMALL ||
|
|
g_TargetQual == DEBUG_DUMP_DEFAULT ||
|
|
g_TargetQual == DEBUG_DUMP_FULL) {
|
|
dprintf("!pci does not work for dump targets\n");
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
{
|
|
INIT_API();
|
|
|
|
|
|
noargs = sscanf(args,"%lX %lX %lX %lX %lX %lX",
|
|
&Flags, // 1
|
|
&MaxBus, // 2
|
|
&Device, // 3
|
|
&Function, // 4
|
|
&MinAddr, // 5
|
|
&MaxAddr // 6
|
|
);
|
|
|
|
MinBus = MaxBus;
|
|
if (Flags & DUMP_TO_MAX_BUS) {
|
|
MinBus = 0;
|
|
}
|
|
|
|
if (noargs >= 3) {
|
|
Flags |= DUMP_ALLOW_INVALID_DEVICE;
|
|
MinDevice = Device;
|
|
MaxDevice = Device;
|
|
}
|
|
|
|
if (noargs >= 4) {
|
|
MinFunction = Function;
|
|
MaxFunction = Function;
|
|
}
|
|
|
|
if (MinAddr || MaxAddr) {
|
|
Flags |= DUMP_RAW_BYTES;
|
|
}
|
|
|
|
if (Flags & DUMP_RAW_DWORDS) {
|
|
Flags |= DUMP_RAW_BYTES;
|
|
}
|
|
|
|
pcidump (
|
|
Flags,
|
|
MinBus, MaxBus,
|
|
MinDevice, MaxDevice,
|
|
MinFunction, MaxFunction,
|
|
MinAddr, MaxAddr
|
|
);
|
|
|
|
EXIT_API();
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|