From 832b07a87c87f02cf17d748c075a84fc3a9b7afd Mon Sep 17 00:00:00 2001 From: =?utf8?q?Pali=20Roh=C3=A1r?= Date: Tue, 28 Dec 2021 20:29:21 +0100 Subject: [PATCH] lspci: Do not access config space when it is emulated 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 | 2 +- lspci.c | 21 ++++++++++++++------- lspci.h | 1 + 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/ls-tree.c b/ls-tree.c index f8154a2..e845f66 100644 --- 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 95a1318..ed8c864 100644 --- 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 6e0bb24..62d8e92 100644 --- 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 */ -- 2.39.5