Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 1 Aug 2018 19:02:06 +0000 (UTC)
From:      Konstantin Belousov <kib@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r337054 - head/usr.sbin/pciconf
Message-ID:  <201808011902.w71J26PK030020@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: kib
Date: Wed Aug  1 19:02:05 2018
New Revision: 337054
URL: https://svnweb.freebsd.org/changeset/base/337054

Log:
  Add -D option to pciconf(8) to mmap and dump content of the device BAR.
  
  Discussed with:	imp, jhb
  Sponsored by:	The FreeBSD Foundation, Mellanox Technologies
  MFC after:	2 weeks
  Differential revision:	https://reviews.freebsd.org/D15583

Modified:
  head/usr.sbin/pciconf/pciconf.8
  head/usr.sbin/pciconf/pciconf.c

Modified: head/usr.sbin/pciconf/pciconf.8
==============================================================================
--- head/usr.sbin/pciconf/pciconf.8	Wed Aug  1 18:58:24 2018	(r337053)
+++ head/usr.sbin/pciconf/pciconf.8	Wed Aug  1 19:02:05 2018	(r337054)
@@ -25,7 +25,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd November 23, 2015
+.Dd June 14, 2018
 .Dt PCICONF 8
 .Os
 .Sh NAME
@@ -40,6 +40,8 @@
 .Fl r Oo Fl b | h Oc Ar device addr Ns Op : Ns Ar addr2
 .Nm
 .Fl w Oo Fl b | h Oc Ar device addr value
+.Nm
+.Fl D Oo Fl b | h | x Oc Ar device addr Op start Ns Op : Ns Ar count
 .Sh DESCRIPTION
 The
 .Nm
@@ -305,17 +307,38 @@ into a configuration space register at byte offset
 .Ar addr
 of device
 .Ar selector .
-For both operations, the flags
-.Fl b
+.Pp
+The
+.Fl D
+option request a dump of the specified BAR.
+Dump is performed to the standard output, raw register values
+are written.
+Use
+.Xr hexdump 1
+to convert them to human-readable dump,
+or redirect into a file to save the snapshot of the device state.
+Optionally, the
+.Ar start
 and
-.Fl h
+.Ar count
+of the registers dumped can be specified, in multiple of the operation width,
+see next paragraph.
+.Pp
+For read, write, and dump operations, the flags
+.Fl b ,
+.Fl h ,
+and
+.Fl x
 select the width of the operation;
 .Fl b
 indicates a byte operation, and
 .Fl h
 indicates a halfword (two-byte) operation.
+.Fl x
+indicates a quadword (four-byte) operation.
 The default is to read or
 write a longword (four bytes).
+The quadword mode is only valid for BAR dump.
 .Sh ENVIRONMENT
 PCI vendor and device information is read from
 .Pa /usr/local/share/pciids/pci.ids .
@@ -368,3 +391,11 @@ to provide the device with a driver KLD, and reading o
 registers may cause a failure in badly designed
 .Tn PCI
 chips.
+.Pp
+There is currently no way to specify the caching mode for the mapping
+established by the
+.Fl D
+option,
+.Nm
+always uses uncached access.
+This is fine for control register BARs.

Modified: head/usr.sbin/pciconf/pciconf.c
==============================================================================
--- head/usr.sbin/pciconf/pciconf.c	Wed Aug  1 18:58:24 2018	(r337053)
+++ head/usr.sbin/pciconf/pciconf.c	Wed Aug  1 19:02:05 2018	(r337054)
@@ -34,7 +34,14 @@ static const char rcsid[] =
 
 #include <sys/types.h>
 #include <sys/fcntl.h>
+#include <sys/mman.h>
+#include <sys/pciio.h>
+#include <sys/queue.h>
 
+#include <vm/vm.h>
+
+#include <dev/pci/pcireg.h>
+
 #include <assert.h>
 #include <ctype.h>
 #include <err.h>
@@ -44,11 +51,7 @@ static const char rcsid[] =
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
-#include <sys/pciio.h>
-#include <sys/queue.h>
 
-#include <dev/pci/pcireg.h>
-
 #include "pathnames.h"
 #include "pciconf.h"
 
@@ -82,32 +85,37 @@ static int load_vendors(void);
 static void readit(const char *, const char *, int);
 static void writeit(const char *, const char *, const char *, int);
 static void chkattached(const char *);
+static void dump_bar(const char *name, const char *reg, const char *bar_start,
+    const char *bar_count, int width, int verbose);
 
 static int exitstatus = 0;
 
 static void
 usage(void)
 {
-	fprintf(stderr, "%s\n%s\n%s\n%s\n",
-		"usage: pciconf -l [-BbcevV] [device]",
-		"       pciconf -a device",
-		"       pciconf -r [-b | -h] device addr[:addr2]",
-		"       pciconf -w [-b | -h] device addr value");
-	exit (1);
+
+	fprintf(stderr, "%s",
+		"usage: pciconf -l [-BbcevV] [device]\n"
+		"       pciconf -a device\n"
+		"       pciconf -r [-b | -h] device addr[:addr2]\n"
+		"       pciconf -w [-b | -h] device addr value\n"
+		"       pciconf -D [-b | -h | -x] device bar [start [count]]"
+		"\n");
+	exit(1);
 }
 
 int
 main(int argc, char **argv)
 {
-	int c;
-	int listmode, readmode, writemode, attachedmode;
+	int c, width;
+	int listmode, readmode, writemode, attachedmode, dumpbarmode;
 	int bars, bridge, caps, errors, verbose, vpd;
-	int byte, isshort;
 
-	listmode = readmode = writemode = attachedmode = 0;
-	bars = bridge = caps = errors = verbose = vpd = byte = isshort = 0;
+	listmode = readmode = writemode = attachedmode = dumpbarmode = 0;
+	bars = bridge = caps = errors = verbose = vpd= 0;
+	width = 4;
 
-	while ((c = getopt(argc, argv, "aBbcehlrwVv")) != -1) {
+	while ((c = getopt(argc, argv, "aBbcDehlrwVv")) != -1) {
 		switch(c) {
 		case 'a':
 			attachedmode = 1;
@@ -119,19 +127,23 @@ main(int argc, char **argv)
 
 		case 'b':
 			bars = 1;
-			byte = 1;
+			width = 1;
 			break;
 
 		case 'c':
 			caps = 1;
 			break;
 
+		case 'D':
+			dumpbarmode = 1;
+			break;
+
 		case 'e':
 			errors = 1;
 			break;
 
 		case 'h':
-			isshort = 1;
+			width = 2;
 			break;
 
 		case 'l':
@@ -154,6 +166,10 @@ main(int argc, char **argv)
 			vpd = 1;
 			break;
 
+		case 'x':
+			width = 8;
+			break;
+
 		default:
 			usage();
 		}
@@ -162,7 +178,9 @@ main(int argc, char **argv)
 	if ((listmode && optind >= argc + 1)
 	    || (writemode && optind + 3 != argc)
 	    || (readmode && optind + 2 != argc)
-	    || (attachedmode && optind + 1 != argc))
+	    || (attachedmode && optind + 1 != argc)
+	    || (dumpbarmode && (optind + 2 > argc || optind + 4 < argc))
+	    || (width == 8 && !dumpbarmode))
 		usage();
 
 	if (listmode) {
@@ -171,16 +189,20 @@ main(int argc, char **argv)
 	} else if (attachedmode) {
 		chkattached(argv[optind]);
 	} else if (readmode) {
-		readit(argv[optind], argv[optind + 1],
-		    byte ? 1 : isshort ? 2 : 4);
+		readit(argv[optind], argv[optind + 1], width);
 	} else if (writemode) {
 		writeit(argv[optind], argv[optind + 1], argv[optind + 2],
-		    byte ? 1 : isshort ? 2 : 4);
+		    width);
+	} else if (dumpbarmode) {
+		dump_bar(argv[optind], argv[optind + 1],
+		    optind + 2 < argc ? argv[optind + 2] : NULL, 
+		    optind + 3 < argc ? argv[optind + 3] : NULL, 
+		    width, verbose);
 	} else {
 		usage();
 	}
 
-	return exitstatus;
+	return (exitstatus);
 }
 
 static void
@@ -1025,5 +1047,119 @@ chkattached(const char *name)
 
 	exitstatus = pi.pi_data ? 0 : 2; /* exit(2), if NOT attached */
 	printf("%s: %s%s\n", name, pi.pi_data == 0 ? "not " : "", "attached");
+	close(fd);
+}
+
+static void
+dump_bar(const char *name, const char *reg, const char *bar_start,
+    const char *bar_count, int width, int verbose)
+{
+	struct pci_bar_mmap pbm;
+	uint32_t *dd;
+	uint16_t *dh;
+	uint8_t *db;
+	uint64_t *dx, a, start, count;
+	char *el;
+	size_t res;
+	int fd;
+
+	start = 0;
+	if (bar_start != NULL) {
+		start = strtoul(bar_start, &el, 0);
+		if (*el != '\0')
+			errx(1, "Invalid bar start specification %s",
+			    bar_start);
+	}
+	count = 0;
+	if (bar_count != NULL) {
+		count = strtoul(bar_count, &el, 0);
+		if (*el != '\0')
+			errx(1, "Invalid count specification %s",
+			    bar_count);
+	}
+
+	pbm.pbm_sel = getsel(name);
+	pbm.pbm_reg = strtoul(reg, &el, 0);
+	if (*reg == '\0' || *el != '\0')
+		errx(1, "Invalid bar specification %s", reg);
+	pbm.pbm_flags = 0;
+	pbm.pbm_memattr = VM_MEMATTR_UNCACHEABLE; /* XXX */
+
+	fd = open(_PATH_DEVPCI, O_RDONLY, 0);
+	if (fd < 0)
+		err(1, "%s", _PATH_DEVPCI);
+
+	if (ioctl(fd, PCIOCBARMMAP, &pbm) < 0)
+		err(1, "ioctl(PCIOCBARMMAP)");
+
+	if (count == 0)
+		count = pbm.pbm_bar_length / width;
+	if (start + count < start || (start + count) * width < (uint64_t)width)
+		errx(1, "(start + count) x width overflow");
+	if ((start + count) * width > pbm.pbm_bar_length) {
+		if (start * width > pbm.pbm_bar_length)
+			count = 0;
+		else
+			count = (pbm.pbm_bar_length - start * width) / width;
+	}
+	if (verbose) {
+		fprintf(stderr,
+		    "Dumping pci%d:%d:%d:%d BAR %x mapped base %p "
+		    "off %#x length %#jx from %#jx count %#jx in %d-bytes\n",
+		    pbm.pbm_sel.pc_domain, pbm.pbm_sel.pc_bus,
+		    pbm.pbm_sel.pc_dev, pbm.pbm_sel.pc_func,
+		    pbm.pbm_reg, pbm.pbm_map_base, pbm.pbm_bar_off,
+		    pbm.pbm_bar_length, start, count, width);
+	}
+	switch (width) {
+	case 1:
+		db = (uint8_t *)(uintptr_t)((uintptr_t)pbm.pbm_map_base +
+		    pbm.pbm_bar_off + start * width);
+		for (a = 0; a < count; a += width, db++) {
+			res = fwrite(db, width, 1, stdout);
+			if (res != 1) {
+				errx(1, "error writing to stdout");
+				break;
+			}
+		}
+		break;
+	case 2:
+		dh = (uint16_t *)(uintptr_t)((uintptr_t)pbm.pbm_map_base +
+		    pbm.pbm_bar_off + start * width);
+		for (a = 0; a < count; a += width, dh++) {
+			res = fwrite(dh, width, 1, stdout);
+			if (res != 1) {
+				errx(1, "error writing to stdout");
+				break;
+			}
+		}
+		break;
+	case 4:
+		dd = (uint32_t *)(uintptr_t)((uintptr_t)pbm.pbm_map_base +
+		    pbm.pbm_bar_off + start * width);
+		for (a = 0; a < count; a += width) {
+			res = fwrite(dd, width, 1, stdout);
+			if (res != 1) {
+				errx(1, "error writing to stdout");
+				break;
+			}
+		}
+		break;
+	case 8:
+		dx = (uint64_t *)(uintptr_t)((uintptr_t)pbm.pbm_map_base +
+		    pbm.pbm_bar_off + start * width);
+		for (a = 0; a < count; a += width, dx++) {
+			res = fwrite(dx, width, 1, stdout);
+			if (res != 1) {
+				errx(1, "error writing to stdout");
+				break;
+			}
+		}
+		break;
+	default:
+		errx(1, "invalid access width");
+	}
+
+	munmap((void *)pbm.pbm_map_base, pbm.pbm_map_length);
 	close(fd);
 }



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201808011902.w71J26PK030020>