From owner-svn-src-all@freebsd.org Wed Aug 1 19:02:07 2018 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id DA4CD1066720; Wed, 1 Aug 2018 19:02:06 +0000 (UTC) (envelope-from kib@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 8FA0D82E7D; Wed, 1 Aug 2018 19:02:06 +0000 (UTC) (envelope-from kib@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 7218A26902; Wed, 1 Aug 2018 19:02:06 +0000 (UTC) (envelope-from kib@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id w71J26eE030137; Wed, 1 Aug 2018 19:02:06 GMT (envelope-from kib@FreeBSD.org) Received: (from kib@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id w71J26PK030020; Wed, 1 Aug 2018 19:02:06 GMT (envelope-from kib@FreeBSD.org) Message-Id: <201808011902.w71J26PK030020@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: kib set sender to kib@FreeBSD.org using -f From: Konstantin Belousov Date: Wed, 1 Aug 2018 19:02:06 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r337054 - head/usr.sbin/pciconf X-SVN-Group: head X-SVN-Commit-Author: kib X-SVN-Commit-Paths: head/usr.sbin/pciconf X-SVN-Commit-Revision: 337054 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.27 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 01 Aug 2018 19:02:07 -0000 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 #include +#include +#include +#include +#include + +#include + #include #include #include @@ -44,11 +51,7 @@ static const char rcsid[] = #include #include #include -#include -#include -#include - #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); }