Date: Wed, 24 Jun 2026 20:04:53 +0000 From: John Baldwin <jhb@FreeBSD.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org Cc: Timo =?utf-8?Q?V=C3=B6lker?= <timo.voelker@fh-muenster.de> Subject: git: e63fbcc69402 - main - pciconf: Add option to write into a BAR region Message-ID: <6a3c3865.4694e.799386e4@gitrepo.freebsd.org>
index | next in thread | raw e-mail
The branch main has been updated by jhb: URL: https://cgit.FreeBSD.org/src/commit/?id=e63fbcc69402d4a1e8681a95710f0ec01a6837b4 commit e63fbcc69402d4a1e8681a95710f0ec01a6837b4 Author: Timo Völker <timo.voelker@fh-muenster.de> AuthorDate: 2026-06-24 19:57:34 +0000 Commit: John Baldwin <jhb@FreeBSD.org> CommitDate: 2026-06-24 19:57:34 +0000 pciconf: Add option to write into a BAR region Add option -W that allows to write into a BAR region. Also, add an option -R that allows to read from a BAR region that works similar to -r that reads from the PCI config space. Reviewed by: bcr (manpages), jhb Differential Revision: https://reviews.freebsd.org/D55915 --- usr.sbin/pciconf/pciconf.8 | 31 ++++++-- usr.sbin/pciconf/pciconf.c | 180 ++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 187 insertions(+), 24 deletions(-) diff --git a/usr.sbin/pciconf/pciconf.8 b/usr.sbin/pciconf/pciconf.8 index 7958a538f3d9..acb5fc4d039d 100644 --- a/usr.sbin/pciconf/pciconf.8 +++ b/usr.sbin/pciconf/pciconf.8 @@ -23,7 +23,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd March 10, 2026 +.Dd April 24, 2026 .Dt PCICONF 8 .Os .Sh NAME @@ -42,6 +42,10 @@ .Fl w Oo Fl b | h Oc Ar device addr value .Nm .Fl D Oo Fl b | h | x Oc Ar device bar Op Ar start Op Ns Ar count +.Nm +.Fl R Oo Fl b | h | x Oc Ar device bar start Ns Op : Ns Ar end +.Nm +.Fl W Oo Fl b | h | x Oc Ar device bar offset value .Sh DESCRIPTION The .Nm @@ -341,7 +345,8 @@ of device .Pp The .Fl D -option request a dump of the specified BAR. +option requests a dump of the BAR specified by its offset in config space +.Ar bar . Dump is performed to the standard output, raw register values are written. Use @@ -353,9 +358,25 @@ Optionally, the and .Ar count of the registers dumped can be specified, in multiple of the operation width, -see next paragraph. +see below. +.Pp +The +.Fl R +option reads from the BAR specified by its offset in config space +.Ar bar . +It starts reading at byte offset +.Ar start . +The optional last argument +.Ar end +specifies a range to read. +The +.Fl W +option writes the +.Ar value +to the BAR at byte offset +.Ar offset . .Pp -For read, write, and dump operations, the flags +For read, write, BAR dump, BAR read, and BAR write operations, the flags .Fl b , .Fl h , and @@ -369,7 +390,7 @@ indicates a halfword (two-byte) operation. 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. +The quadword mode is only valid for BAR dump, BAR read, and BAR write. .Sh ENVIRONMENT PCI vendor and device information is read from .Pa /usr/local/share/pciids/pci.ids . diff --git a/usr.sbin/pciconf/pciconf.c b/usr.sbin/pciconf/pciconf.c index e2a3beeba6f7..f3c6a413826f 100644 --- a/usr.sbin/pciconf/pciconf.c +++ b/usr.sbin/pciconf/pciconf.c @@ -91,6 +91,10 @@ 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 void read_bar(const char *name, const char *bar, const char *start_end, + int width); +static void write_bar(const char *name, const char *bar, const char *offset_str, + const char *value_str, int width); static int exitstatus = 0; @@ -104,7 +108,9 @@ usage(void) " 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]]" + " pciconf -D [-b | -h | -x] device bar [start [count]]\n" + " pciconf -R [-b | -h | -x] device bar start[:end]\n" + " pciconf -W [-b | -h | -x] device bar offset value" "\n"); exit(1); } @@ -113,14 +119,15 @@ int main(int argc, char **argv) { int c, width; - enum { NONE, LIST, TREE, READ, WRITE, ATTACHED, DUMPBAR } mode; + enum { NONE, LIST, TREE, READ, WRITE, ATTACHED, DUMPBAR, READBAR, + WRITEBAR } mode; int compact, bars, bridge, caps, errors, verbose, vpd; mode = NONE; compact = bars = bridge = caps = errors = verbose = vpd = 0; width = 4; - while ((c = getopt(argc, argv, "aBbcDehlrtwVvx")) != -1) { + while ((c = getopt(argc, argv, "aBbcDehlRrtWwVvx")) != -1) { switch(c) { case 'a': mode = ATTACHED; @@ -157,6 +164,10 @@ main(int argc, char **argv) mode = LIST; break; + case 'R': + mode = READBAR; + break; + case 'r': mode = READ; break; @@ -164,6 +175,11 @@ main(int argc, char **argv) case 't': mode = TREE; break; + + case 'W': + mode = WRITEBAR; + break; + case 'w': mode = WRITE; break; @@ -221,6 +237,18 @@ main(int argc, char **argv) optind + 3 < argc ? argv[optind + 3] : NULL, width, verbose); break; + case READBAR: + if (optind + 3 != argc) + usage(); + read_bar(argv[optind], argv[optind + 1], argv[optind + 2], + width); + break; + case WRITEBAR: + if (optind + 4 != argc) + usage(); + write_bar(argv[optind], argv[optind + 1], argv[optind + 2], + argv[optind + 3], width); + break; default: usage(); } @@ -1365,6 +1393,36 @@ chkattached(const char *name) close(fd); } +static void +map_bar(const char *name, const char *reg, int flags, struct pci_bar_mmap *pbm) +{ + int fd; + char *el; + + memset(pbm, 0, sizeof(struct pci_bar_mmap)); + 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_memattr = VM_MEMATTR_DEVICE; + pbm->pbm_flags = flags; + + fd = open(_PATH_DEVPCI, O_RDWR, 0); + if (fd < 0) + err(1, "%s", _PATH_DEVPCI); + + if (ioctl(fd, PCIOCBARMMAP, pbm) < 0) + err(1, "ioctl(PCIOCBARMMAP)"); + + close(fd); +} + +static void +unmap_bar(struct pci_bar_mmap *pbm) +{ + munmap(pbm->pbm_map_base, pbm->pbm_map_length); +} + static void dump_bar(const char *name, const char *reg, const char *bar_start, const char *bar_count, int width, int verbose) @@ -1376,7 +1434,6 @@ dump_bar(const char *name, const char *reg, const char *bar_start, uint64_t *dx, a, start, count; char *el; size_t res; - int fd; start = 0; if (bar_start != NULL) { @@ -1393,19 +1450,7 @@ dump_bar(const char *name, const char *reg, const char *bar_start, 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_DEVICE; - - fd = open(_PATH_DEVPCI, O_RDWR, 0); - if (fd < 0) - err(1, "%s", _PATH_DEVPCI); - - if (ioctl(fd, PCIOCBARMMAP, &pbm) < 0) - err(1, "ioctl(PCIOCBARMMAP)"); + map_bar(name, reg, 0, &pbm); if (count == 0) count = pbm.pbm_bar_length / width; @@ -1475,6 +1520,103 @@ dump_bar(const char *name, const char *reg, const char *bar_start, errx(1, "invalid access width"); } - munmap((void *)pbm.pbm_map_base, pbm.pbm_map_length); - close(fd); + unmap_bar(&pbm); +} + +union tunion { + uint8_t one; + uint16_t two; + uint32_t four; + uint64_t eight; + uint8_t bytes[8]; +}; + +static void +read_bar(const char *name, const char *bar, const char *start_end, int width) +{ + struct pci_bar_mmap pbm; + long rstart, rend, r; + char *end; + int items_per_line, i; + + rend = rstart = strtol(start_end, &end, 0); + if (*end == ':') { + end++; + rend = strtol(end, NULL, 0); + } + + map_bar(name, bar, 0, &pbm); + + items_per_line = 16 / width; + for (i = 1, r = rstart; r <= rend; i++, r += width) { + uintptr_t addr; + union tunion t; + int j; + + addr = (uintptr_t)pbm.pbm_map_base + pbm.pbm_bar_off + r; + switch (width) { + case 1: + t.one = *((uint8_t *)addr); + break; + case 2: + t.two = *((uint16_t *)addr); + break; + case 4: + t.four = *((uint32_t *)addr); + break; + case 8: + t.eight = *((uint64_t *)addr); + break; + default: + errx(1, "invalid read width"); + } + for (j = 0; j < width; j++) { + printf("%02x", t.bytes[j]); + } + /* Use a double space in the middle when outputting bytes. */ + if (width == 1 && (i % 16) == 8) + putchar(' '); + putchar(i % items_per_line == 0 ? '\n' : ' '); + } + if (i % items_per_line != 1) + putchar('\n'); + + unmap_bar(&pbm); +} + +static void +write_bar(const char *name, const char *bar, const char *offset_str, + const char *value_str, int width) +{ + struct pci_bar_mmap pbm; + uint64_t offset, value; + uintptr_t addr; + char *el; + + offset = strtoul(offset_str, &el, 0); + if (*el != '\0') + errx(1, "Invalid bar offset specification %s", offset_str); + value = strtoul(value_str, (char **)0, 0); /* XXX error check */ + + map_bar(name, bar, PCIIO_BAR_MMAP_RW, &pbm); + + addr = (uintptr_t)pbm.pbm_map_base + pbm.pbm_bar_off + offset; + switch (width) { + case 1: + *((uint8_t *)addr) = value; + break; + case 2: + *((uint16_t *)addr) = value; + break; + case 4: + *((uint32_t *)addr) = value; + break; + case 8: + *((uint64_t *)addr) = value; + break; + default: + errx(1, "invalid write width"); + } + + unmap_bar(&pbm); }home | help
Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?6a3c3865.4694e.799386e4>
