diff options
Diffstat (limited to 'usr.sbin/pcidump')
-rw-r--r-- | usr.sbin/pcidump/pcidump.c | 138 |
1 files changed, 137 insertions, 1 deletions
diff --git a/usr.sbin/pcidump/pcidump.c b/usr.sbin/pcidump/pcidump.c index fd8034d9136..1b239b732da 100644 --- a/usr.sbin/pcidump/pcidump.c +++ b/usr.sbin/pcidump/pcidump.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pcidump.c,v 1.56 2019/11/30 14:02:29 mestre Exp $ */ +/* $OpenBSD: pcidump.c,v 1.57 2020/06/22 05:54:26 dlg Exp $ */ /* * Copyright (c) 2006, 2007 David Gwynne <loki@animata.net> @@ -34,6 +34,7 @@ #include <string.h> #include <unistd.h> #include <limits.h> +#include <vis.h> #define PCIDEV "/dev/pci" @@ -52,6 +53,7 @@ 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_bars(int, int, int, int); void dump_caplist(int, int, int, u_int8_t); +void dump_vpd(int, int, int); void dump_pci_powerstate(int, int, int, uint8_t); void dump_pcie_linkspeed(int, int, int, uint8_t); void dump_pcie_devserial(int, int, int, uint16_t); @@ -335,6 +337,137 @@ probe(int bus, int dev, int func) return (0); } +int +print_bytes(const uint8_t *buf, size_t len) +{ + char dst[8]; + size_t i; + + for (i = 0; i < len; i++) { + vis(dst, buf[i], VIS_TAB|VIS_NL, 0); + printf("%s", dst); + } + printf("\n"); + + return (0); +} + +int +print_vpd(const uint8_t *buf, size_t len) +{ + const struct pci_vpd *vpd; + char key0[8]; + char key1[8]; + size_t vlen, i; + + while (len > 0) { + if (len < sizeof(*vpd)) + return (1); + + vpd = (const struct pci_vpd *)buf; + vis(key0, vpd->vpd_key0, VIS_TAB|VIS_NL, 0); + vis(key1, vpd->vpd_key1, VIS_TAB|VIS_NL, 0); + vlen = vpd->vpd_len; + + printf("\t\t %s%s: ", key0, key1); + + buf += sizeof(*vpd); + len -= sizeof(*vpd); + + if (len < vlen) + return (1); + print_bytes(buf, vlen); + + buf += vlen; + len -= vlen; + } + + return (0); +} + +void +dump_vpd(int bus, int dev, int func) +{ + struct pci_vpd_req io; + uint32_t data[64]; /* XXX this can be up to 32k of data */ + uint8_t *buf = (uint8_t *)data; + size_t len = sizeof(data); + size_t i; + + bzero(&io, sizeof(io)); + io.pv_sel.pc_bus = bus; + io.pv_sel.pc_dev = dev; + io.pv_sel.pc_func = func; + io.pv_offset = 0; + io.pv_count = nitems(data); + io.pv_data = data; + + if (ioctl(pcifd, PCIOCGETVPD, &io) == -1) + warn("PCIOCGETVPD"); + + do { + uint8_t vpd = *buf; + uint8_t type; + size_t hlen, vlen; + int (*print)(const uint8_t *, size_t) = print_bytes; + + if (PCI_VPDRES_ISLARGE(vpd)) { + struct pci_vpd_largeres *res; + type = PCI_VPDRES_LARGE_NAME(vpd); + + switch (type) { + case PCI_VPDRES_TYPE_IDENTIFIER_STRING: + printf("\t\tProduct Name: "); + break; + case PCI_VPDRES_TYPE_VPD: + print = print_vpd; + break; + default: + printf("%02x: ", type); + break; + } + + if (len < sizeof(*res)) + goto trunc; + res = (struct pci_vpd_largeres *)buf; + + hlen = sizeof(*res); + vlen = ((size_t)res->vpdres_len_msb << 8) | + (size_t)res->vpdres_len_lsb; + } else { /* small */ + type = PCI_VPDRES_SMALL_NAME(vpd); + if (type == PCI_VPDRES_TYPE_END_TAG) + break; + + printf("\t\t"); + switch (type) { + case PCI_VPDRES_TYPE_COMPATIBLE_DEVICE_ID: + case PCI_VPDRES_TYPE_VENDOR_DEFINED: + default: + printf("%02x", type); + break; + } + + hlen = sizeof(vpd); + vlen = PCI_VPDRES_SMALL_LENGTH(vpd); + } + buf += hlen; + len -= hlen; + + if (len < vlen) + goto trunc; + (*print)(buf, vlen); + + buf += vlen; + len -= vlen; + } while (len > 0); + + return; +trunc: + /* i have spent too much time in tcpdump - dlg */ + printf("[|vpd]\n"); +} + void dump_pci_powerstate(int bus, int dev, int func, uint8_t ptr) { @@ -512,6 +645,9 @@ dump_caplist(int bus, int dev, int func, u_int8_t ptr) case PCI_CAP_PWRMGMT: dump_pci_powerstate(bus, dev, func, ptr); break; + case PCI_CAP_VPD: + dump_vpd(bus, dev, func); + break; case PCI_CAP_PCIEXPRESS: dump_pcie_linkspeed(bus, dev, func, ptr); dump_pcie_enhanced_caplist(bus, dev, func); |