Source code of Windows XP (NT5)
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

/*++
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;
}