> From: Simon Mages <mages.si...@googlemail.com>
> 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, &reg, &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, &regval) != 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);
>  }
> 
> 

Reply via email to