summaryrefslogtreecommitdiff
path: root/usr.sbin/pcidump
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/pcidump')
-rw-r--r--usr.sbin/pcidump/pcidump.c138
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);