Changeset View
Changeset View
Standalone View
Standalone View
usr.sbin/pciconf/pciconf.c
Show All 28 Lines | |||||
#ifndef lint | #ifndef lint | ||||
static const char rcsid[] = | static const char rcsid[] = | ||||
"$FreeBSD$"; | "$FreeBSD$"; | ||||
#endif /* not lint */ | #endif /* not lint */ | ||||
#include <sys/types.h> | #include <sys/types.h> | ||||
#include <sys/fcntl.h> | #include <sys/fcntl.h> | ||||
#include <sys/mman.h> | |||||
imp: I'd be tempted to commit these bits separately as well. | |||||
Not Done Inline ActionsSure, after the whole patch is finalized. kib: Sure, after the whole patch is finalized. | |||||
#include <sys/pciio.h> | |||||
#include <sys/queue.h> | |||||
#include <vm/vm.h> | |||||
#include <dev/pci/pcireg.h> | |||||
#include <assert.h> | #include <assert.h> | ||||
#include <ctype.h> | #include <ctype.h> | ||||
#include <err.h> | #include <err.h> | ||||
#include <inttypes.h> | #include <inttypes.h> | ||||
#include <stdbool.h> | #include <stdbool.h> | ||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#include <stdio.h> | #include <stdio.h> | ||||
#include <string.h> | #include <string.h> | ||||
#include <unistd.h> | #include <unistd.h> | ||||
#include <sys/pciio.h> | |||||
#include <sys/queue.h> | |||||
#include <dev/pci/pcireg.h> | |||||
#include "pathnames.h" | #include "pathnames.h" | ||||
#include "pciconf.h" | #include "pciconf.h" | ||||
struct pci_device_info | struct pci_device_info | ||||
{ | { | ||||
TAILQ_ENTRY(pci_device_info) link; | TAILQ_ENTRY(pci_device_info) link; | ||||
int id; | int id; | ||||
char *desc; | char *desc; | ||||
Show All 17 Lines | |||||
static void list_verbose(struct pci_conf *p); | static void list_verbose(struct pci_conf *p); | ||||
static void list_vpd(int fd, struct pci_conf *p); | static void list_vpd(int fd, struct pci_conf *p); | ||||
static const char *guess_class(struct pci_conf *p); | static const char *guess_class(struct pci_conf *p); | ||||
static const char *guess_subclass(struct pci_conf *p); | static const char *guess_subclass(struct pci_conf *p); | ||||
static int load_vendors(void); | static int load_vendors(void); | ||||
static void readit(const char *, const char *, int); | static void readit(const char *, const char *, int); | ||||
static void writeit(const char *, const char *, const char *, int); | static void writeit(const char *, const char *, const char *, int); | ||||
static void chkattached(const char *); | 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 int exitstatus = 0; | ||||
static void | static void | ||||
usage(void) | usage(void) | ||||
{ | { | ||||
fprintf(stderr, "%s\n%s\n%s\n%s\n", | |||||
"usage: pciconf -l [-BbcevV] [device]", | fprintf(stderr, "%s", | ||||
" pciconf -a device", | "usage: pciconf -l [-BbcevV] [device]\n" | ||||
" pciconf -r [-b | -h] device addr[:addr2]", | " pciconf -a device\n" | ||||
" pciconf -w [-b | -h] device addr value"); | " 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); | exit(1); | ||||
} | } | ||||
int | int | ||||
main(int argc, char **argv) | main(int argc, char **argv) | ||||
{ | { | ||||
int c; | int c, width; | ||||
int listmode, readmode, writemode, attachedmode; | int listmode, readmode, writemode, attachedmode, dumpbarmode; | ||||
int bars, bridge, caps, errors, verbose, vpd; | int bars, bridge, caps, errors, verbose, vpd; | ||||
int byte, isshort; | |||||
listmode = readmode = writemode = attachedmode = 0; | listmode = readmode = writemode = attachedmode = dumpbarmode = 0; | ||||
bars = bridge = caps = errors = verbose = vpd = byte = isshort = 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) { | switch(c) { | ||||
case 'a': | case 'a': | ||||
attachedmode = 1; | attachedmode = 1; | ||||
break; | break; | ||||
case 'B': | case 'B': | ||||
bridge = 1; | bridge = 1; | ||||
break; | break; | ||||
case 'b': | case 'b': | ||||
bars = 1; | bars = 1; | ||||
byte = 1; | width = 1; | ||||
break; | break; | ||||
case 'c': | case 'c': | ||||
caps = 1; | caps = 1; | ||||
break; | break; | ||||
case 'D': | |||||
dumpbarmode = 1; | |||||
break; | |||||
case 'e': | case 'e': | ||||
errors = 1; | errors = 1; | ||||
break; | break; | ||||
case 'h': | case 'h': | ||||
isshort = 1; | width = 2; | ||||
break; | break; | ||||
case 'l': | case 'l': | ||||
listmode = 1; | listmode = 1; | ||||
break; | break; | ||||
case 'r': | case 'r': | ||||
readmode = 1; | readmode = 1; | ||||
break; | break; | ||||
case 'w': | case 'w': | ||||
writemode = 1; | writemode = 1; | ||||
break; | break; | ||||
case 'v': | case 'v': | ||||
verbose = 1; | verbose = 1; | ||||
break; | break; | ||||
case 'V': | case 'V': | ||||
vpd = 1; | vpd = 1; | ||||
break; | break; | ||||
case 'x': | |||||
width = 8; | |||||
break; | |||||
default: | default: | ||||
usage(); | usage(); | ||||
} | } | ||||
} | } | ||||
if ((listmode && optind >= argc + 1) | if ((listmode && optind >= argc + 1) | ||||
|| (writemode && optind + 3 != argc) | || (writemode && optind + 3 != argc) | ||||
|| (readmode && optind + 2 != argc) | || (readmode && optind + 2 != argc) | ||||
|| (attachedmode && optind + 1 != argc)) | || (attachedmode && optind + 1 != argc) | ||||
|| (dumpbarmode && (optind + 2 > argc || optind + 4 < argc)) | |||||
|| (width == 8 && !dumpbarmode)) | |||||
usage(); | usage(); | ||||
if (listmode) { | if (listmode) { | ||||
list_devs(optind + 1 == argc ? argv[optind] : NULL, verbose, | list_devs(optind + 1 == argc ? argv[optind] : NULL, verbose, | ||||
bars, bridge, caps, errors, vpd); | bars, bridge, caps, errors, vpd); | ||||
} else if (attachedmode) { | } else if (attachedmode) { | ||||
chkattached(argv[optind]); | chkattached(argv[optind]); | ||||
} else if (readmode) { | } else if (readmode) { | ||||
readit(argv[optind], argv[optind + 1], | readit(argv[optind], argv[optind + 1], width); | ||||
byte ? 1 : isshort ? 2 : 4); | |||||
} else if (writemode) { | } else if (writemode) { | ||||
writeit(argv[optind], argv[optind + 1], argv[optind + 2], | 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 { | } else { | ||||
usage(); | usage(); | ||||
} | } | ||||
return exitstatus; | return (exitstatus); | ||||
} | } | ||||
static void | static void | ||||
list_devs(const char *name, int verbose, int bars, int bridge, int caps, | list_devs(const char *name, int verbose, int bars, int bridge, int caps, | ||||
int errors, int vpd) | int errors, int vpd) | ||||
{ | { | ||||
int fd; | int fd; | ||||
struct pci_conf_io pc; | struct pci_conf_io pc; | ||||
▲ Show 20 Lines • Show All 828 Lines • ▼ Show 20 Lines | chkattached(const char *name) | ||||
if (fd < 0) | if (fd < 0) | ||||
err(1, "%s", _PATH_DEVPCI); | err(1, "%s", _PATH_DEVPCI); | ||||
if (ioctl(fd, PCIOCATTACHED, &pi) < 0) | if (ioctl(fd, PCIOCATTACHED, &pi) < 0) | ||||
err(1, "ioctl(PCIOCATTACHED)"); | err(1, "ioctl(PCIOCATTACHED)"); | ||||
exitstatus = pi.pi_data ? 0 : 2; /* exit(2), if NOT attached */ | exitstatus = pi.pi_data ? 0 : 2; /* exit(2), if NOT attached */ | ||||
printf("%s: %s%s\n", name, pi.pi_data == 0 ? "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); | close(fd); | ||||
} | } |
I'd be tempted to commit these bits separately as well.