mirror of
https://github.com/openbsd/src.git
synced 2024-12-22 16:42:56 -08:00
b9fc9a728f
possible. Annotate <sys/param.h> lines with their current reasons. Switch to PATH_MAX, NGROUPS_MAX, HOST_NAME_MAX+1, LOGIN_NAME_MAX, etc. Change MIN() and MAX() to local definitions of MINIMUM() and MAXIMUM() where sensible to avoid pulling in the pollution. These are the files confirmed through binary verification. ok guenther, millert, doug (helped with the verification protocol)
787 lines
19 KiB
C
787 lines
19 KiB
C
/* $OpenBSD: pcidump.c,v 1.37 2015/01/16 06:40:19 deraadt Exp $ */
|
|
|
|
/*
|
|
* Copyright (c) 2006, 2007 David Gwynne <loki@animata.net>
|
|
*
|
|
* Permission to use, copy, modify, and distribute this software for any
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
* copyright notice and this permission notice appear in all copies.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*/
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/ioctl.h>
|
|
#include <sys/pciio.h>
|
|
|
|
#include <dev/pci/pcireg.h>
|
|
#include <dev/pci/pcidevs.h>
|
|
#include <dev/pci/pcidevs_data.h>
|
|
|
|
#include <err.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <paths.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <limits.h>
|
|
|
|
#define PCIDEV "/dev/pci"
|
|
|
|
#ifndef nitems
|
|
#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
|
|
#endif
|
|
|
|
__dead void usage(void);
|
|
void scanpcidomain(void);
|
|
int probe(int, int, int);
|
|
void dump(int, int, int);
|
|
void hexdump(int, int, int, int);
|
|
const char *str2busdevfunc(const char *, int *, int *, int *);
|
|
int pci_nfuncs(int, int);
|
|
int pci_read(int, int, int, u_int32_t, u_int32_t *);
|
|
int pci_readmask(int, int, int, u_int32_t, u_int32_t *);
|
|
void dump_caplist(int, int, int, u_int8_t);
|
|
void dump_pcie_linkspeed(int, int, int, uint8_t);
|
|
void print_pcie_ls(uint8_t);
|
|
int dump_rom(int, int, int);
|
|
int dump_vga_bios(void);
|
|
|
|
void dump_type0(int bus, int dev, int func);
|
|
void dump_type1(int bus, int dev, int func);
|
|
void dump_type2(int bus, int dev, int func);
|
|
|
|
__dead void
|
|
usage(void)
|
|
{
|
|
extern char *__progname;
|
|
|
|
fprintf(stderr,
|
|
"usage: %s [-v] [-x | -xx | -xxx] [-d pcidev] [bus:dev:func]\n"
|
|
" %s -r file [-d pcidev] bus:dev:func\n",
|
|
__progname, __progname);
|
|
exit(1);
|
|
}
|
|
|
|
int pcifd;
|
|
int romfd;
|
|
int verbose = 0;
|
|
int hex = 0;
|
|
int size = 64;
|
|
|
|
const char *pci_capnames[] = {
|
|
"Reserved",
|
|
"Power Management",
|
|
"AGP",
|
|
"Vital Product Data (VPD)",
|
|
"Slot Identification",
|
|
"Message Signaled Interrupts (MSI)",
|
|
"CompactPCI Hot Swap",
|
|
"PCI-X",
|
|
"AMD LDT/HT",
|
|
"Vendor Specific",
|
|
"Debug Port",
|
|
"CompactPCI Central Resource Control",
|
|
"PCI Hot-Plug",
|
|
"PCI-PCI",
|
|
"AGP8",
|
|
"Secure",
|
|
"PCI Express",
|
|
"Extended Message Signaled Interrupts (MSI-X)",
|
|
"SATA",
|
|
"PCI Advanced Features"
|
|
};
|
|
|
|
int
|
|
main(int argc, char *argv[])
|
|
{
|
|
int nfuncs;
|
|
int bus, dev, func;
|
|
char pcidev[PATH_MAX] = PCIDEV;
|
|
char *romfile = NULL;
|
|
const char *errstr;
|
|
int c, error = 0, dumpall = 1, domid = 0;
|
|
|
|
while ((c = getopt(argc, argv, "d:r:vx")) != -1) {
|
|
switch (c) {
|
|
case 'd':
|
|
strlcpy(pcidev, optarg, sizeof(pcidev));
|
|
dumpall = 0;
|
|
break;
|
|
case 'r':
|
|
romfile = optarg;
|
|
dumpall = 0;
|
|
break;
|
|
case 'v':
|
|
verbose = 1;
|
|
break;
|
|
case 'x':
|
|
hex++;
|
|
break;
|
|
default:
|
|
usage();
|
|
}
|
|
}
|
|
argc -= optind;
|
|
argv += optind;
|
|
|
|
if (argc > 1 || (romfile && argc != 1))
|
|
usage();
|
|
|
|
if (romfile) {
|
|
romfd = open(romfile, O_WRONLY|O_CREAT|O_TRUNC, 0777);
|
|
if (romfd == -1)
|
|
err(1, "%s", romfile);
|
|
}
|
|
|
|
if (hex > 1)
|
|
size = 256;
|
|
if (hex > 2)
|
|
size = 4096;
|
|
|
|
if (argc == 1)
|
|
dumpall = 0;
|
|
|
|
if (dumpall == 0) {
|
|
pcifd = open(pcidev, O_RDONLY, 0777);
|
|
if (pcifd == -1)
|
|
err(1, "%s", pcidev);
|
|
} else {
|
|
for (;;) {
|
|
snprintf(pcidev, 16, "/dev/pci%d", domid++);
|
|
pcifd = open(pcidev, O_RDONLY, 0777);
|
|
if (pcifd == -1) {
|
|
if (errno == ENXIO || errno == ENOENT) {
|
|
return 0;
|
|
} else {
|
|
err(1, "%s", pcidev);
|
|
}
|
|
}
|
|
printf("Domain %s:\n", pcidev);
|
|
scanpcidomain();
|
|
close(pcifd);
|
|
}
|
|
}
|
|
|
|
if (argc == 1) {
|
|
errstr = str2busdevfunc(argv[0], &bus, &dev, &func);
|
|
if (errstr != NULL)
|
|
errx(1, "\"%s\": %s", argv[0], errstr);
|
|
|
|
nfuncs = pci_nfuncs(bus, dev);
|
|
if (nfuncs == -1 || func > nfuncs)
|
|
error = ENXIO;
|
|
else if (romfile)
|
|
error = dump_rom(bus, dev, func);
|
|
else
|
|
error = probe(bus, dev, func);
|
|
|
|
if (error != 0)
|
|
errc(1, error, "\"%s\"", argv[0]);
|
|
} else {
|
|
printf("Domain %s:\n", pcidev);
|
|
scanpcidomain();
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
void
|
|
scanpcidomain(void)
|
|
{
|
|
int nfuncs;
|
|
int bus, dev, func;
|
|
|
|
for (bus = 0; bus < 256; bus++) {
|
|
for (dev = 0; dev < 32; dev++) {
|
|
nfuncs = pci_nfuncs(bus, dev);
|
|
for (func = 0; func < nfuncs; func++) {
|
|
probe(bus, dev, func);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
const char *
|
|
str2busdevfunc(const char *string, int *bus, int *dev, int *func)
|
|
{
|
|
const char *errstr;
|
|
char b[80], *d, *f;
|
|
|
|
strlcpy(b, string, sizeof(b));
|
|
|
|
d = strchr(b, ':');
|
|
if (d == NULL)
|
|
return("device not specified");
|
|
*d++ = '\0';
|
|
|
|
f = strchr(d, ':');
|
|
if (f == NULL)
|
|
return("function not specified");
|
|
*f++ = '\0';
|
|
|
|
*bus = strtonum(b, 0, 255, &errstr);
|
|
if (errstr != NULL)
|
|
return (errstr);
|
|
*dev = strtonum(d, 0, 31, &errstr);
|
|
if (errstr != NULL)
|
|
return (errstr);
|
|
*func = strtonum(f, 0, 7, &errstr);
|
|
if (errstr != NULL)
|
|
return (errstr);
|
|
|
|
return (NULL);
|
|
}
|
|
|
|
int
|
|
probe(int bus, int dev, int func)
|
|
{
|
|
u_int32_t id_reg;
|
|
const struct pci_known_vendor *pkv;
|
|
const struct pci_known_product *pkp;
|
|
const char *vendor = NULL, *product = NULL;
|
|
|
|
if (pci_read(bus, dev, func, PCI_ID_REG, &id_reg) != 0)
|
|
return (errno);
|
|
|
|
if (PCI_VENDOR(id_reg) == PCI_VENDOR_INVALID ||
|
|
PCI_VENDOR(id_reg) == 0)
|
|
return (ENXIO);
|
|
|
|
for (pkv = pci_known_vendors; pkv->vendorname != NULL; pkv++) {
|
|
if (pkv->vendor == PCI_VENDOR(id_reg)) {
|
|
vendor = pkv->vendorname;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (vendor != NULL) {
|
|
for (pkp = pci_known_products; pkp->productname != NULL; pkp++)
|
|
if (pkp->vendor == PCI_VENDOR(id_reg) &&
|
|
pkp->product == PCI_PRODUCT(id_reg)) {
|
|
product = pkp->productname;
|
|
break;
|
|
}
|
|
}
|
|
|
|
printf(" %d:%d:%d: %s %s\n", bus, dev, func,
|
|
(vendor == NULL) ? "unknown" : vendor,
|
|
(product == NULL) ? "unknown" : product);
|
|
|
|
if (verbose)
|
|
dump(bus, dev, func);
|
|
if (hex > 0)
|
|
hexdump(bus, dev, func, size);
|
|
|
|
return (0);
|
|
}
|
|
|
|
void
|
|
print_pcie_ls(uint8_t speed)
|
|
{
|
|
if (speed & 4)
|
|
printf("8.0");
|
|
else if (speed & 2)
|
|
printf("5.0");
|
|
else if (speed & 1)
|
|
printf("2.5");
|
|
else
|
|
printf("unknown (%d)", speed);
|
|
}
|
|
|
|
void
|
|
dump_pcie_linkspeed(int bus, int dev, int func, uint8_t ptr)
|
|
{
|
|
u_int32_t lcap, sreg, lcap2 = 0, xcap;
|
|
u_int8_t cwidth, cspeed, swidth, sspeed;
|
|
|
|
if (pci_read(bus, dev, func, ptr + PCI_PCIE_XCAP, &xcap) != 0)
|
|
return;
|
|
|
|
if (PCI_PCIE_XCAP_VER(xcap) >= 2) {
|
|
if (pci_read(bus, dev, func, ptr + PCI_PCIE_LCAP2, &lcap2) != 0)
|
|
lcap2 = 0;
|
|
else
|
|
cspeed = (lcap2 & 0x0e) >> 1;
|
|
}
|
|
|
|
if (pci_read(bus, dev, func, ptr + PCI_PCIE_LCAP, &lcap) != 0)
|
|
return;
|
|
if (lcap2 == 0)
|
|
cspeed = lcap & 0x0f;
|
|
|
|
if (pci_read(bus, dev, func, ptr + PCI_PCIE_LCSR, &sreg) != 0)
|
|
return;
|
|
sreg = sreg >> 16;
|
|
|
|
cwidth = (lcap >> 4) & 0x3f;
|
|
if (cwidth == 0)
|
|
return;
|
|
|
|
swidth = (sreg >> 4) & 0x3f;
|
|
sspeed = sreg & 0x0f;
|
|
|
|
printf("\t Link Speed: ");
|
|
print_pcie_ls(sspeed);
|
|
printf(" / ");
|
|
print_pcie_ls(cspeed);
|
|
|
|
printf(" GT/s Link Width: x%d / x%d\n", swidth, cwidth);
|
|
}
|
|
|
|
void
|
|
dump_caplist(int bus, int dev, int func, u_int8_t ptr)
|
|
{
|
|
u_int32_t reg;
|
|
u_int8_t cap;
|
|
|
|
if (pci_read(bus, dev, func, PCI_COMMAND_STATUS_REG, ®) != 0)
|
|
return;
|
|
if (!(reg & PCI_STATUS_CAPLIST_SUPPORT))
|
|
return;
|
|
|
|
if (pci_read(bus, dev, func, ptr, ®) != 0)
|
|
return;
|
|
ptr = PCI_CAPLIST_PTR(reg);
|
|
while (ptr != 0) {
|
|
if (pci_read(bus, dev, func, ptr, ®) != 0)
|
|
return;
|
|
cap = PCI_CAPLIST_CAP(reg);
|
|
printf("\t0x%04x: Capability 0x%02x: ", ptr, cap);
|
|
if (cap >= nitems(pci_capnames))
|
|
cap = 0;
|
|
printf("%s\n", pci_capnames[cap]);
|
|
if (cap == PCI_CAP_PCIEXPRESS)
|
|
dump_pcie_linkspeed(bus, dev, func, ptr);
|
|
ptr = PCI_CAPLIST_NEXT(reg);
|
|
}
|
|
}
|
|
|
|
void
|
|
dump_type0(int bus, int dev, int func)
|
|
{
|
|
const char *memtype;
|
|
u_int64_t mem;
|
|
u_int64_t mask;
|
|
u_int32_t reg, reg1;
|
|
int bar;
|
|
|
|
for (bar = PCI_MAPREG_START; bar < PCI_MAPREG_END; bar += 0x4) {
|
|
if (pci_read(bus, dev, func, bar, ®) != 0 ||
|
|
pci_readmask(bus, dev, func, bar, ®1) != 0)
|
|
warn("unable to read PCI_MAPREG 0x%02x", bar);
|
|
|
|
printf("\t0x%04x: BAR ", bar);
|
|
|
|
if (reg == 0 && reg1 == 0) {
|
|
printf("empty (%08x)\n", reg);
|
|
continue;
|
|
}
|
|
|
|
switch (PCI_MAPREG_TYPE(reg)) {
|
|
case PCI_MAPREG_TYPE_MEM:
|
|
printf("mem ");
|
|
if (PCI_MAPREG_MEM_PREFETCHABLE(reg))
|
|
printf("prefetchable ");
|
|
|
|
memtype = "32bit 1m";
|
|
switch (PCI_MAPREG_MEM_TYPE(reg)) {
|
|
case PCI_MAPREG_MEM_TYPE_32BIT:
|
|
memtype = "32bit";
|
|
case PCI_MAPREG_MEM_TYPE_32BIT_1M:
|
|
printf("%s ", memtype);
|
|
|
|
printf("addr: 0x%08x/0x%08x\n",
|
|
PCI_MAPREG_MEM_ADDR(reg),
|
|
PCI_MAPREG_MEM_SIZE(reg1));
|
|
|
|
break;
|
|
case PCI_MAPREG_MEM_TYPE_64BIT:
|
|
mem = reg;
|
|
mask = reg1;
|
|
bar += 0x04;
|
|
if (pci_read(bus, dev, func, bar, ®) != 0 ||
|
|
pci_readmask(bus, dev, func, bar, ®1) != 0)
|
|
warn("unable to read 0x%02x", bar);
|
|
|
|
mem |= (u_int64_t)reg << 32;
|
|
mask |= (u_int64_t)reg1 << 32;
|
|
|
|
printf("64bit addr: 0x%016llx/0x%08llx\n",
|
|
PCI_MAPREG_MEM64_ADDR(mem),
|
|
PCI_MAPREG_MEM64_SIZE(mask));
|
|
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case PCI_MAPREG_TYPE_IO:
|
|
printf("io addr: 0x%08x/0x%04x\n",
|
|
PCI_MAPREG_IO_ADDR(reg),
|
|
PCI_MAPREG_IO_SIZE(reg1));
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (pci_read(bus, dev, func, PCI_CARDBUS_CIS_REG, ®) != 0)
|
|
warn("unable to read PCI_CARDBUS_CIS_REG");
|
|
printf("\t0x%04x: Cardbus CIS: %08x\n", PCI_CARDBUS_CIS_REG, reg);
|
|
|
|
if (pci_read(bus, dev, func, PCI_SUBSYS_ID_REG, ®) != 0)
|
|
warn("unable to read PCI_SUBSYS_ID_REG");
|
|
printf("\t0x%04x: Subsystem Vendor ID: %04x Product ID: %04x\n",
|
|
PCI_SUBSYS_ID_REG, PCI_VENDOR(reg), PCI_PRODUCT(reg));
|
|
|
|
if (pci_read(bus, dev, func, PCI_ROM_REG, ®) != 0)
|
|
warn("unable to read PCI_ROM_REG");
|
|
printf("\t0x%04x: Expansion ROM Base Address: %08x\n",
|
|
PCI_ROM_REG, reg);
|
|
|
|
if (pci_read(bus, dev, func, 0x38, ®) != 0)
|
|
warn("unable to read 0x38 (reserved)");
|
|
printf("\t0x%04x: %08x\n", 0x38, reg);
|
|
|
|
if (pci_read(bus, dev, func, PCI_INTERRUPT_REG, ®) != 0)
|
|
warn("unable to read PCI_INTERRUPT_REG");
|
|
printf("\t0x%04x: Interrupt Pin: %02x Line: %02x Min Gnt: %02x"
|
|
" Max Lat: %02x\n", PCI_INTERRUPT_REG, PCI_INTERRUPT_PIN(reg),
|
|
PCI_INTERRUPT_LINE(reg), PCI_MIN_GNT(reg), PCI_MAX_LAT(reg));
|
|
}
|
|
|
|
void
|
|
dump_type1(int bus, int dev, int func)
|
|
{
|
|
u_int32_t reg;
|
|
int bar;
|
|
|
|
for (bar = PCI_MAPREG_START; bar < PCI_MAPREG_PPB_END; bar += 0x4) {
|
|
if (pci_read(bus, dev, func, bar, ®) != 0)
|
|
warn("unable to read PCI_MAPREG 0x%02x", bar);
|
|
printf("\t0x%04x: %08x\n", bar, reg);
|
|
}
|
|
|
|
if (pci_read(bus, dev, func, PCI_PRIBUS_1, ®) != 0)
|
|
warn("unable to read PCI_PRIBUS_1");
|
|
printf("\t0x%04x: Primary Bus: %d Secondary Bus: %d "
|
|
"Subordinate Bus: %d \n\t Secondary Latency Timer: %02x\n",
|
|
PCI_PRIBUS_1, (reg >> 0) & 0xff, (reg >> 8) & 0xff,
|
|
(reg >> 16) & 0xff, (reg >> 24) & 0xff);
|
|
|
|
if (pci_read(bus, dev, func, PCI_IOBASEL_1, ®) != 0)
|
|
warn("unable to read PCI_IOBASEL_1");
|
|
printf("\t0x%04x: I/O Base: %02x I/O Limit: %02x "
|
|
"Secondary Status: %04x\n", PCI_IOBASEL_1, (reg >> 0 ) & 0xff,
|
|
(reg >> 8) & 0xff, (reg >> 16) & 0xffff);
|
|
|
|
if (pci_read(bus, dev, func, PCI_MEMBASE_1, ®) != 0)
|
|
warn("unable to read PCI_MEMBASE_1");
|
|
printf("\t0x%04x: Memory Base: %04x Memory Limit: %04x\n",
|
|
PCI_MEMBASE_1, (reg >> 0) & 0xffff, (reg >> 16) & 0xffff);
|
|
|
|
if (pci_read(bus, dev, func, PCI_PMBASEL_1, ®) != 0)
|
|
warn("unable to read PCI_PMBASEL_1");
|
|
printf("\t0x%04x: Prefetch Memory Base: %04x "
|
|
"Prefetch Memory Limit: %04x\n", PCI_PMBASEL_1,
|
|
(reg >> 0) & 0xffff, (reg >> 16) & 0xffff);
|
|
|
|
#undef PCI_PMBASEH_1
|
|
#define PCI_PMBASEH_1 0x28
|
|
if (pci_read(bus, dev, func, PCI_PMBASEH_1, ®) != 0)
|
|
warn("unable to read PCI_PMBASEH_1");
|
|
printf("\t0x%04x: Prefetch Memory Base Upper 32 Bits: %08x\n",
|
|
PCI_PMBASEH_1, reg);
|
|
|
|
#undef PCI_PMLIMITH_1
|
|
#define PCI_PMLIMITH_1 0x2c
|
|
if (pci_read(bus, dev, func, PCI_PMLIMITH_1, ®) != 0)
|
|
warn("unable to read PCI_PMLIMITH_1");
|
|
printf("\t0x%04x: Prefetch Memory Limit Upper 32 Bits: %08x\n",
|
|
PCI_PMLIMITH_1, reg);
|
|
|
|
#undef PCI_IOBASEH_1
|
|
#define PCI_IOBASEH_1 0x30
|
|
if (pci_read(bus, dev, func, PCI_IOBASEH_1, ®) != 0)
|
|
warn("unable to read PCI_IOBASEH_1");
|
|
printf("\t0x%04x: I/O Base Upper 16 Bits: %04x "
|
|
"I/O Limit Upper 16 Bits: %04x\n", PCI_IOBASEH_1,
|
|
(reg >> 0) & 0xffff, (reg >> 16) & 0xffff);
|
|
|
|
#define PCI_PPB_ROM_REG 0x38
|
|
if (pci_read(bus, dev, func, PCI_PPB_ROM_REG, ®) != 0)
|
|
warn("unable to read PCI_PPB_ROM_REG");
|
|
printf("\t0x%04x: Expansion ROM Base Address: %08x\n",
|
|
PCI_PPB_ROM_REG, reg);
|
|
|
|
if (pci_read(bus, dev, func, PCI_INTERRUPT_REG, ®) != 0)
|
|
warn("unable to read PCI_INTERRUPT_REG");
|
|
printf("\t0x%04x: Interrupt Pin: %02x Line: %02x "
|
|
"Bridge Control: %04x\n",
|
|
PCI_INTERRUPT_REG, PCI_INTERRUPT_PIN(reg),
|
|
PCI_INTERRUPT_LINE(reg), reg >> 16);
|
|
}
|
|
|
|
void
|
|
dump_type2(int bus, int dev, int func)
|
|
{
|
|
u_int32_t reg;
|
|
|
|
if (pci_read(bus, dev, func, PCI_MAPREG_START, ®) != 0)
|
|
warn("unable to read PCI_MAPREG\n");
|
|
printf("\t0x%04x: Cardbus Control Registers Base Address: %08x\n",
|
|
PCI_MAPREG_START, reg);
|
|
|
|
if (pci_read(bus, dev, func, PCI_PRIBUS_2, ®) != 0)
|
|
warn("unable to read PCI_PRIBUS_2");
|
|
printf("\t0x%04x: Primary Bus: %d Cardbus Bus: %d "
|
|
"Subordinate Bus: %d \n\t Cardbus Latency Timer: %02x\n",
|
|
PCI_PRIBUS_2, (reg >> 0) & 0xff, (reg >> 8) & 0xff,
|
|
(reg >> 16) & 0xff, (reg >> 24) & 0xff);
|
|
|
|
if (pci_read(bus, dev, func, PCI_MEMBASE0_2, ®) != 0)
|
|
warn("unable to read PCI_MEMBASE0_2\n");
|
|
printf("\t0x%04x: Memory Base 0: %08x\n", PCI_MEMBASE0_2, reg);
|
|
|
|
if (pci_read(bus, dev, func, PCI_MEMLIMIT0_2, ®) != 0)
|
|
warn("unable to read PCI_MEMLIMIT0_2\n");
|
|
printf("\t0x%04x: Memory Limit 0: %08x\n", PCI_MEMLIMIT0_2, reg);
|
|
|
|
if (pci_read(bus, dev, func, PCI_MEMBASE1_2, ®) != 0)
|
|
warn("unable to read PCI_MEMBASE1_2\n");
|
|
printf("\t0x%04x: Memory Base 1: %08x\n", PCI_MEMBASE1_2, reg);
|
|
|
|
if (pci_read(bus, dev, func, PCI_MEMLIMIT1_2, ®) != 0)
|
|
warn("unable to read PCI_MEMLIMIT1_2\n");
|
|
printf("\t0x%04x: Memory Limit 1: %08x\n", PCI_MEMLIMIT1_2, reg);
|
|
|
|
if (pci_read(bus, dev, func, PCI_IOBASE0_2, ®) != 0)
|
|
warn("unable to read PCI_IOBASE0_2\n");
|
|
printf("\t0x%04x: I/O Base 0: %08x\n", PCI_IOBASE0_2, reg);
|
|
|
|
if (pci_read(bus, dev, func, PCI_IOLIMIT0_2, ®) != 0)
|
|
warn("unable to read PCI_IOLIMIT0_2\n");
|
|
printf("\t0x%04x: I/O Limit 0: %08x\n", PCI_IOLIMIT0_2, reg);
|
|
|
|
if (pci_read(bus, dev, func, PCI_IOBASE1_2, ®) != 0)
|
|
warn("unable to read PCI_IOBASE1_2\n");
|
|
printf("\t0x%04x: I/O Base 1: %08x\n", PCI_IOBASE1_2, reg);
|
|
|
|
if (pci_read(bus, dev, func, PCI_IOLIMIT1_2, ®) != 0)
|
|
warn("unable to read PCI_IOLIMIT1_2\n");
|
|
printf("\t0x%04x: I/O Limit 1: %08x\n", PCI_IOLIMIT1_2, reg);
|
|
|
|
if (pci_read(bus, dev, func, PCI_INTERRUPT_REG, ®) != 0)
|
|
warn("unable to read PCI_INTERRUPT_REG");
|
|
printf("\t0x%04x: Interrupt Pin: %02x Line: %02x "
|
|
"Bridge Control: %04x\n",
|
|
PCI_INTERRUPT_REG, PCI_INTERRUPT_PIN(reg),
|
|
PCI_INTERRUPT_LINE(reg), reg >> 16);
|
|
|
|
if (pci_read(bus, dev, func, PCI_SUBVEND_2, ®) != 0)
|
|
warn("unable to read PCI_SUBVEND_2");
|
|
printf("\t0x%04x: Subsystem Vendor ID: %04x Product ID: %04x\n",
|
|
PCI_SUBVEND_2, PCI_VENDOR(reg), PCI_PRODUCT(reg));
|
|
|
|
if (pci_read(bus, dev, func, PCI_PCCARDIF_2, ®) != 0)
|
|
warn("unable to read PCI_PCCARDIF_2\n");
|
|
printf("\t0x%04x: 16-bit Legacy Mode Base Address: %08x\n",
|
|
PCI_PCCARDIF_2, reg);
|
|
}
|
|
|
|
void
|
|
dump(int bus, int dev, int func)
|
|
{
|
|
u_int32_t reg;
|
|
u_int8_t capptr = PCI_CAPLISTPTR_REG;
|
|
|
|
if (pci_read(bus, dev, func, PCI_ID_REG, ®) != 0)
|
|
warn("unable to read PCI_ID_REG");
|
|
printf("\t0x%04x: Vendor ID: %04x Product ID: %04x\n", PCI_ID_REG,
|
|
PCI_VENDOR(reg), PCI_PRODUCT(reg));
|
|
|
|
if (pci_read(bus, dev, func, PCI_COMMAND_STATUS_REG, ®) != 0)
|
|
warn("unable to read PCI_COMMAND_STATUS_REG");
|
|
printf("\t0x%04x: Command: %04x Status: %04x\n",
|
|
PCI_COMMAND_STATUS_REG, reg & 0xffff, (reg >> 16) & 0xffff);
|
|
|
|
if (pci_read(bus, dev, func, PCI_CLASS_REG, ®) != 0)
|
|
warn("unable to read PCI_CLASS_REG");
|
|
printf("\t0x%04x: Class: %02x Subclass: %02x Interface: %02x "
|
|
"Revision: %02x\n", PCI_CLASS_REG, PCI_CLASS(reg),
|
|
PCI_SUBCLASS(reg), PCI_INTERFACE(reg), PCI_REVISION(reg));
|
|
|
|
if (pci_read(bus, dev, func, PCI_BHLC_REG, ®) != 0)
|
|
warn("unable to read PCI_BHLC_REG");
|
|
printf("\t0x%04x: BIST: %02x Header Type: %02x Latency Timer: %02x "
|
|
"Cache Line Size: %02x\n", PCI_BHLC_REG, PCI_BIST(reg),
|
|
PCI_HDRTYPE(reg), PCI_LATTIMER(reg), PCI_CACHELINE(reg));
|
|
|
|
switch (PCI_HDRTYPE_TYPE(reg)) {
|
|
case 2:
|
|
dump_type2(bus, dev, func);
|
|
capptr = PCI_CARDBUS_CAPLISTPTR_REG;
|
|
break;
|
|
case 1:
|
|
dump_type1(bus, dev, func);
|
|
break;
|
|
case 0:
|
|
dump_type0(bus, dev, func);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
dump_caplist(bus, dev, func, capptr);
|
|
}
|
|
|
|
void
|
|
hexdump(int bus, int dev, int func, int size)
|
|
{
|
|
u_int32_t reg;
|
|
int i;
|
|
|
|
for (i = 0; i < size; i += 4) {
|
|
if (pci_read(bus, dev, func, i, ®) != 0) {
|
|
if (errno == EINVAL)
|
|
return;
|
|
warn("unable to read 0x%02x", i);
|
|
}
|
|
|
|
if ((i % 16) == 0)
|
|
printf("\t0x%04x:", i);
|
|
printf(" %08x", reg);
|
|
|
|
if ((i % 16) == 12)
|
|
printf("\n");
|
|
}
|
|
}
|
|
|
|
int
|
|
pci_nfuncs(int bus, int dev)
|
|
{
|
|
u_int32_t hdr;
|
|
|
|
if (pci_read(bus, dev, 0, PCI_BHLC_REG, &hdr) != 0)
|
|
return (-1);
|
|
|
|
return (PCI_HDRTYPE_MULTIFN(hdr) ? 8 : 1);
|
|
}
|
|
|
|
int
|
|
pci_read(int bus, int dev, int func, u_int32_t reg, u_int32_t *val)
|
|
{
|
|
struct pci_io io;
|
|
int rv;
|
|
|
|
bzero(&io, sizeof(io));
|
|
io.pi_sel.pc_bus = bus;
|
|
io.pi_sel.pc_dev = dev;
|
|
io.pi_sel.pc_func = func;
|
|
io.pi_reg = reg;
|
|
io.pi_width = 4;
|
|
|
|
rv = ioctl(pcifd, PCIOCREAD, &io);
|
|
if (rv != 0)
|
|
return (rv);
|
|
|
|
*val = io.pi_data;
|
|
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
pci_readmask(int bus, int dev, int func, u_int32_t reg, u_int32_t *val)
|
|
{
|
|
struct pci_io io;
|
|
int rv;
|
|
|
|
bzero(&io, sizeof(io));
|
|
io.pi_sel.pc_bus = bus;
|
|
io.pi_sel.pc_dev = dev;
|
|
io.pi_sel.pc_func = func;
|
|
io.pi_reg = reg;
|
|
io.pi_width = 4;
|
|
|
|
rv = ioctl(pcifd, PCIOCREADMASK, &io);
|
|
if (rv != 0)
|
|
return (rv);
|
|
|
|
*val = io.pi_data;
|
|
|
|
return (0);
|
|
}
|
|
|
|
int
|
|
dump_rom(int bus, int dev, int func)
|
|
{
|
|
struct pci_rom rom;
|
|
u_int32_t cr, addr;
|
|
|
|
if (pci_read(bus, dev, func, PCI_ROM_REG, &addr) != 0 ||
|
|
pci_read(bus, dev, func, PCI_CLASS_REG, &cr) != 0)
|
|
return (errno);
|
|
|
|
if (addr == 0 && PCI_CLASS(cr) == PCI_CLASS_DISPLAY &&
|
|
PCI_SUBCLASS(cr) == PCI_SUBCLASS_DISPLAY_VGA)
|
|
return dump_vga_bios();
|
|
|
|
bzero(&rom, sizeof(rom));
|
|
rom.pr_sel.pc_bus = bus;
|
|
rom.pr_sel.pc_dev = dev;
|
|
rom.pr_sel.pc_func = func;
|
|
if (ioctl(pcifd, PCIOCGETROMLEN, &rom))
|
|
return (errno);
|
|
|
|
rom.pr_rom = malloc(rom.pr_romlen);
|
|
if (rom.pr_rom == NULL)
|
|
return (ENOMEM);
|
|
|
|
if (ioctl(pcifd, PCIOCGETROM, &rom))
|
|
return (errno);
|
|
|
|
if (write(romfd, rom.pr_rom, rom.pr_romlen) == -1)
|
|
return (errno);
|
|
|
|
return (0);
|
|
}
|
|
|
|
#define VGA_BIOS_ADDR 0xc0000
|
|
#define VGA_BIOS_LEN 0x10000
|
|
|
|
int
|
|
dump_vga_bios(void)
|
|
{
|
|
#if defined(__amd64__) || defined(__i386__)
|
|
void *bios;
|
|
int fd;
|
|
|
|
fd = open(_PATH_MEM, O_RDONLY, 0777);
|
|
if (fd == -1)
|
|
err(1, "%s", _PATH_MEM);
|
|
|
|
bios = malloc(VGA_BIOS_LEN);
|
|
if (bios == NULL)
|
|
return (ENOMEM);
|
|
|
|
if (pread(fd, bios, VGA_BIOS_LEN, VGA_BIOS_ADDR) == -1)
|
|
err(1, "%s", _PATH_MEM);
|
|
|
|
if (write(romfd, bios, VGA_BIOS_LEN) == -1) {
|
|
free(bios);
|
|
return (errno);
|
|
}
|
|
|
|
free(bios);
|
|
|
|
return (0);
|
|
#else
|
|
return (ENODEV);
|
|
#endif
|
|
}
|