Ah ok, good to know. Thanks anyway.
2017-03-27 14:57 GMT+02:00, Mark Kettenis <[email protected]>: >> From: Simon Mages <[email protected]> >> Date: Mon, 27 Mar 2017 13:57:54 +0200 >> >> Hi, >> >> right now i use the following diff to poke around in the PCIe config >> space. This diff enables >> pcidump to read and write to a register. So far i used this mainly to >> play with the Advanced >> Error Reporting Capability some devices have. >> >> $ pcidump 4:0:0:104 >> 4:0:0: Broadcom BCM5754 >> 0x0104: 0x00100000 >> This bit indicates an "Unsupported Request Error", the register >> queried here is the >> "Uncorrectable Error Status Register". >> >> # pcidump 4:0:0:104:0x00100000 >> 4:0:0: Broadcom BCM5754 >> 0x0104: 0x00000000 >> pcidump shows the new value of the register after writing. By writing >> a 1 to a status bit it >> gets reset. >> >> I implemented a check for the current securelevel because writing to >> /dev/pci is only possible >> for a securelevel smaller than 1. >> >> I think this functionality can come in handy for people >> writing/modifying device drivers. > > Sorry, but no. This is not going to happen. The kernel interface to > write to pci config space is only there to support X. And even that > support is likely to disappear at some point. > >> Index: pcidump.8 >> =================================================================== >> --- pcidump.8 16 Jul 2013 11:13:34 -0000 1.12 >> +++ pcidump.8 27 Mar 2017 11:27:35 -0000 >> @@ -26,7 +26,7 @@ >> .Op Fl x | xx | xxx >> .Op Fl d Ar pcidev >> .Sm off >> -.Op Ar bus : dev : func >> +.Op Ar bus : dev : func [ : reg [ : val ] ] >> .Sm on >> .Nm pcidump >> .Fl r Ar file >> @@ -69,16 +69,29 @@ Shows a hexadecimal dump of the full PCI >> Shows a hexadecimal dump of the PCIe extended config space. >> .It Xo >> .Sm off >> -.Ar bus : dev : func >> +.Ar bus : dev : func [ : reg [ : val ] ] >> .Sm on >> .Xc >> Show information about the PCI device specified by the tuple given on >> -the command line. >> +the command line. If >> +.Pa reg >> +is used, the value of this register in the configuration space of >> +.Pa func >> +gets printed. If >> +.Pa val >> +is used, the register specified by >> +.Pa reg >> +will be loaded with the value specified by >> +.Pa val . >> If the >> .Fl d >> option is not given, >> .Pa /dev/pci >> is used. >> +.It Xo >> +.Xc >> +The configuration space can only be written in a securelevel(7) lower >> +than 1. >> .El >> .Sh FILES >> .Bl -tag -width /dev/pci* -compact >> @@ -86,7 +99,8 @@ is used. >> Device files for accessing PCI domains. >> .El >> .Sh SEE ALSO >> -.Xr pci 4 >> +.Xr pci 4 , >> +.Xr securelevel 7 >> .Sh HISTORY >> The >> .Nm >> Index: pcidump.c >> =================================================================== >> --- pcidump.c 25 Mar 2017 07:33:46 -0000 1.43 >> +++ pcidump.c 27 Mar 2017 11:24:10 -0000 >> @@ -19,6 +19,8 @@ >> #include <sys/types.h> >> #include <sys/ioctl.h> >> #include <sys/pciio.h> >> +#include <sys/param.h> >> +#include <sys/sysctl.h> >> >> #include <stdio.h> /* need NULL for <dev/pci/*.h> */ >> >> @@ -37,19 +39,27 @@ >> >> #define PCIDEV "/dev/pci" >> >> +#define PCI_CONFIG_SPACE_BEGIN 0x0 >> +#define PCIE_CONFIG_SPACE_END (PCIE_CONFIG_SPACE_SIZE - 1) >> +#define PCI_CONFIG_ALIGNMENT 0x4 >> +#define REG_ALIGNMENT_OK(x) ((x) % PCI_CONFIG_ALIGNMENT ? 0 : 1) >> + >> #ifndef nitems >> #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) >> #endif >> >> __dead void usage(void); >> +int get_securelevel(void); >> void scanpcidomain(void); >> -int probe(int, int, int); >> +int probe(int, int, int, int, int); >> +void chreg(int, int, int, int, int); >> void dump(int, int, int); >> void hexdump(int, int, int, int); >> -const char *str2busdevfunc(const char *, int *, int *, int *); >> +const char *str2busdevfunc(const char *, int *, int *, int *, int *, int >> *); >> int pci_nfuncs(int, int); >> int pci_read(int, int, int, u_int32_t, u_int32_t *); >> int pci_readmask(int, int, int, u_int32_t, u_int32_t *); >> +int pci_write(int, int, int, u_int32_t, u_int32_t); >> void dump_caplist(int, int, int, u_int8_t); >> void dump_pci_powerstate(int, int, int, uint8_t); >> void dump_pcie_linkspeed(int, int, int, uint8_t); >> @@ -67,7 +77,8 @@ usage(void) >> extern char *__progname; >> >> fprintf(stderr, >> - "usage: %s [-v] [-x | -xx | -xxx] [-d pcidev] [bus:dev:func]\n" >> + "usage: %s [-v] [-x | -xx | -xxx] [-d pcidev]" >> + " [bus:dev:func[:reg[:val]]]\n" >> " %s -r file [-d pcidev] bus:dev:func\n", >> __progname, __progname); >> exit(1); >> @@ -139,7 +150,7 @@ int >> main(int argc, char *argv[]) >> { >> int nfuncs; >> - int bus, dev, func; >> + int bus, dev, func, reg = -1, val = -1; >> char pcidev[PATH_MAX] = PCIDEV; >> char *romfile = NULL; >> const char *errstr; >> @@ -186,7 +197,10 @@ main(int argc, char *argv[]) >> dumpall = 0; >> >> if (dumpall == 0) { >> - pcifd = open(pcidev, O_RDONLY, 0777); >> + if (get_securelevel() < 1) >> + pcifd = open(pcidev, O_RDWR, 0777); >> + else >> + pcifd = open(pcidev, O_RDONLY, 0777); >> if (pcifd == -1) >> err(1, "%s", pcidev); >> } else { >> @@ -207,7 +221,7 @@ main(int argc, char *argv[]) >> } >> >> if (argc == 1) { >> - errstr = str2busdevfunc(argv[0], &bus, &dev, &func); >> + errstr = str2busdevfunc(argv[0], &bus, &dev, &func, ®, &val); >> if (errstr != NULL) >> errx(1, "\"%s\": %s", argv[0], errstr); >> >> @@ -217,7 +231,7 @@ main(int argc, char *argv[]) >> else if (romfile) >> error = dump_rom(bus, dev, func); >> else >> - error = probe(bus, dev, func); >> + error = probe(bus, dev, func, reg, val); >> >> if (error != 0) >> errc(1, error, "\"%s\"", argv[0]); >> @@ -229,6 +243,25 @@ main(int argc, char *argv[]) >> return (0); >> } >> >> +int >> +get_securelevel(void) >> +{ >> + int name[2], seclvl; >> + size_t len; >> + >> + name[0] = CTL_KERN; >> + name[1] = KERN_SECURELVL; >> + >> + len = sizeof(seclvl); >> + >> + if (sysctl(name, 2, &seclvl, &len, NULL, 0) == -1) { >> + errx(1, "sysctl securelevel: %s", strerror(errno)); >> + return (-1); >> + } >> + >> + return seclvl; >> +} >> + >> void >> scanpcidomain(void) >> { >> @@ -239,17 +272,18 @@ scanpcidomain(void) >> for (dev = 0; dev < 32; dev++) { >> nfuncs = pci_nfuncs(bus, dev); >> for (func = 0; func < nfuncs; func++) { >> - probe(bus, dev, func); >> + probe(bus, dev, func, -1, -1); >> } >> } >> } >> } >> >> const char * >> -str2busdevfunc(const char *string, int *bus, int *dev, int *func) >> +str2busdevfunc(const char *string, int *bus, int *dev, int *func, int >> *reg, >> + int *val) >> { >> const char *errstr; >> - char b[80], *d, *f; >> + char b[80], *d, *f, *r, *v; >> >> strlcpy(b, string, sizeof(b)); >> >> @@ -263,6 +297,15 @@ str2busdevfunc(const char *string, int * >> return("function not specified"); >> *f++ = '\0'; >> >> + r = strchr(f, ':'); >> + if (r != NULL) { >> + *r++ = '\0'; >> + >> + v = strchr(r, ':'); >> + if (v != NULL) >> + *v++ = '\0'; >> + } >> + >> *bus = strtonum(b, 0, 255, &errstr); >> if (errstr != NULL) >> return (errstr); >> @@ -273,11 +316,24 @@ str2busdevfunc(const char *string, int * >> if (errstr != NULL) >> return (errstr); >> >> + if (r != NULL) { >> + /* a non-PCIe function will return (u_int)-1 on a >> + * read above 0xfff */ >> + if (sscanf(r, "%x", reg) == EOF >> + || *reg < PCI_CONFIG_SPACE_BEGIN >> + || *reg > PCIE_CONFIG_SPACE_END >> + || !REG_ALIGNMENT_OK(*reg)) >> + return("invalid register"); >> + >> + if ((v != NULL) && (sscanf(v, "%x", val) == EOF)) >> + return("invalid value"); >> + } >> + >> return (NULL); >> } >> >> int >> -probe(int bus, int dev, int func) >> +probe(int bus, int dev, int func, int reg, int val) >> { >> u_int32_t id_reg; >> const struct pci_known_vendor *pkv; >> @@ -311,6 +367,8 @@ probe(int bus, int dev, int func) >> (vendor == NULL) ? "unknown" : vendor, >> (product == NULL) ? "unknown" : product); >> >> + if (reg > -1) >> + chreg(bus, dev, func, reg, val); >> if (verbose) >> dump(bus, dev, func); >> if (hex > 0) >> @@ -320,6 +378,25 @@ probe(int bus, int dev, int func) >> } >> >> void >> +chreg(int bus, int dev, int func, int reg, int val) >> +{ >> + u_int32_t regval; >> + int tmp; >> + >> + if (val > -1) { >> + if ((tmp = pci_write(bus, dev, func, reg, val)) != 0) { >> + err(1, "pci_write"); >> + return; >> + } >> + } >> + >> + if (pci_read(bus, dev, func, reg, ®val) != 0) >> + return; >> + >> + printf("\t0x%04x: 0x%08x\n", reg, regval); >> +} >> + >> +void >> dump_pci_powerstate(int bus, int dev, int func, uint8_t ptr) >> { >> u_int32_t pmcsr; >> @@ -800,6 +877,27 @@ pci_readmask(int bus, int dev, int func, >> return (rv); >> >> *val = io.pi_data; >> + >> + return (0); >> +} >> + >> +int >> +pci_write(int bus, int dev, int func, u_int32_t reg, u_int32_t val) >> +{ >> + struct pci_io io; >> + int rv; >> + >> + bzero(&io, sizeof(io)); >> + io.pi_sel.pc_bus = bus; >> + io.pi_sel.pc_dev = dev; >> + io.pi_sel.pc_func = func; >> + io.pi_reg = reg; >> + io.pi_width = 4; >> + io.pi_data = val; >> + >> + rv = ioctl(pcifd, PCIOCWRITE, &io); >> + if (rv != 0) >> + return (rv); >> >> return (0); >> } >> >> >
