]> mj.ucw.cz Git - pciutils.git/commitdiff
lspci: Do not access config space when it is emulated
authorPali Rohár <pali@kernel.org>
Tue, 28 Dec 2021 19:29:21 +0000 (20:29 +0100)
committerMartin Mareš <mj@ucw.cz>
Fri, 15 Apr 2022 21:47:37 +0000 (23:47 +0200)
Emulated config space contains only few information so it could look like
some valid config space. libpci compose emulated config space either from
struct pci_dev or put some fake information (when struct pci_dev does not
have them).

To prevent showing to user fake/bogus information about PCI devices, show
only information which are directly stored in struct pci_dev when emulated
config space is used.

Do it via setting lspci's header type to invalid value (byte)-1, so lspci
code will handle device as unknown without trying to interpret values
config space. This header type is set only in lspci, not in libpci, so
other libpci applications would see valid config space.

lspci users are probably not interested in fake information provided by
libpci just for purpose to export syntactically valid config space.
Information stored in struct pci_dev are the correct one (or rather what OS
things that is correct).

ls-tree.c
lspci.c
lspci.h

index f8154a2b034a67a3b22dd4eb2e5da82d542256d2..e845f662d71c46924d2fc8fe5a5166cfb78ec2b5 100644 (file)
--- a/ls-tree.c
+++ b/ls-tree.c
@@ -107,7 +107,7 @@ grow_tree(void)
     {
       struct pci_dev *dd = d->dev;
       word class = dd->device_class;
-      byte ht = get_conf_byte(d, PCI_HEADER_TYPE) & 0x7f;
+      byte ht = d->no_config_access ? -1 : (get_conf_byte(d, PCI_HEADER_TYPE) & 0x7f);
       if ((class >> 8) == PCI_BASE_CLASS_BRIDGE &&
          (ht == PCI_HEADER_TYPE_BRIDGE || ht == PCI_HEADER_TYPE_CARDBUS))
        {
diff --git a/lspci.c b/lspci.c
index 95a1318e5e80eceb0b5272645545d971ff0bddd4..ed8c864acb93db1d5853aae5cd1d14392bb4b5ed 100644 (file)
--- a/lspci.c
+++ b/lspci.c
@@ -124,18 +124,18 @@ scan_device(struct pci_dev *p)
   d = xmalloc(sizeof(struct device));
   memset(d, 0, sizeof(*d));
   d->dev = p;
+  d->no_config_access = p->no_config_access;
   d->config_cached = d->config_bufsize = 64;
   d->config = xmalloc(64);
   d->present = xmalloc(64);
   memset(d->present, 1, 64);
-  if (!pci_read_block(p, 0, d->config, 64))
+  if (!d->no_config_access && !pci_read_block(p, 0, d->config, 64))
     {
-      fprintf(stderr, "lspci: Unable to read the standard configuration space header of device %04x:%02x:%02x.%d\n",
-             p->domain, p->bus, p->dev, p->func);
-      seen_errors++;
-      return NULL;
+      d->no_config_access = 1;
+      d->config_cached = d->config_bufsize = 0;
+      memset(d->present, 0, 64);
     }
-  if ((d->config[PCI_HEADER_TYPE] & 0x7f) == PCI_HEADER_TYPE_CARDBUS)
+  if (!d->no_config_access && (d->config[PCI_HEADER_TYPE] & 0x7f) == PCI_HEADER_TYPE_CARDBUS)
     {
       /* For cardbus bridges, we need to fetch 64 bytes more to get the
        * full standard header... */
@@ -799,7 +799,7 @@ show_verbose(struct device *d)
   struct pci_dev *p = d->dev;
   int unknown_config_data = 0;
   word class = p->device_class;
-  byte htype = get_conf_byte(d, PCI_HEADER_TYPE) & 0x7f;
+  byte htype = d->no_config_access ? -1 : (get_conf_byte(d, PCI_HEADER_TYPE) & 0x7f);
   byte bist;
   byte max_lat, min_gnt;
   char *dt_node, *iommu_group;
@@ -832,6 +832,7 @@ show_verbose(struct device *d)
       min_gnt = max_lat = 0;
       break;
     default:
+      if (!d->no_config_access)
       printf("\t!!! Unknown header type %02x\n", htype);
       bist = 0;
       min_gnt = max_lat = 0;
@@ -973,6 +974,12 @@ show_hex_dump(struct device *d)
 {
   unsigned int i, cnt;
 
+  if (d->no_config_access)
+    {
+      printf("WARNING: Cannot show hex-dump of the config space\n");
+      return;
+    }
+
   cnt = d->config_cached;
   if (opt_hex >= 3 && config_fetch(d, cnt, 256-cnt))
     {
diff --git a/lspci.h b/lspci.h
index 6e0bb2492fd532d11b4235a93982229b7c3ef5e1..62d8e927adb1ac06fa804ba7bfed5b4a92abff6b 100644 (file)
--- a/lspci.h
+++ b/lspci.h
@@ -39,6 +39,7 @@ struct device {
   struct bus *parent_bus;
   struct bridge *bridge;
   /* Cache */
+  int no_config_access;
   unsigned int config_cached, config_bufsize;
   byte *config;                                /* Cached configuration space data */
   byte *present;                       /* Maps which configuration bytes are present */