From 098174370094ba8c31f86bd9faed3796dcaeb1db Mon Sep 17 00:00:00 2001 From: Martin Mares Date: Sun, 27 Jun 2004 11:20:31 +0000 Subject: [PATCH] Added support for 4096-byte extended configuration space. git-archimport-id: mj@ucw.cz--public/pciutils--main--2.2--patch-50 --- ChangeLog | 17 +++++++++++++++++ lib/aix-device.c | 12 ++++++++++-- lib/dump.c | 48 ++++++++++++++++++++++++++++++++++++----------- lib/fbsd-device.c | 6 ++++++ lib/i386-ports.c | 14 ++++++++++++++ lib/nbsd-libpci.c | 6 ++++++ lib/proc.c | 7 ++----- lib/sysfs.c | 7 ++----- lspci.c | 42 ++++++++++++++++------------------------- setpci.c | 4 ++-- 10 files changed, 112 insertions(+), 51 deletions(-) diff --git a/ChangeLog b/ChangeLog index ea59871..7812665 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,20 @@ +2004-06-27 Martin Mares + + * lspci.c (check_root): Gone. No explicit checks for root are needed, + report correct errors reported by the libpci instead. + + * lspci.c: Added dumping of the extended config space on "-xxxx". + Better caching of config registers. + + * setpci.c (main): Allow access to whole 4096 bytes of the config space. + + * lib/sysfs.c, lib/proc.c: Don't print error messages on short reads, + just return the appropriate error code. + + * lib: Added support for extended (4096-byte) configuration space, + currently implemented only in Linux proc and sysfs access methods + and of course in the dump reader. + 2004-05-29 Martin Mares * Released as 2.1.99-test5. diff --git a/lib/aix-device.c b/lib/aix-device.c index 55b2f30..93a8e4e 100644 --- a/lib/aix-device.c +++ b/lib/aix-device.c @@ -222,8 +222,12 @@ static int aix_read(struct pci_dev *d, int pos, byte *buf, int len) { struct mdio mdio; - int fd = aix_bus_open(d->access, d->bus); + int fd; + if (pos + len > 256) + return 0; + + fd = aix_bus_open(d->access, d->bus); mdio.md_addr = (ulong) pos; mdio.md_size = len; mdio.md_incr = MV_BYTE; @@ -240,8 +244,12 @@ static int aix_write(struct pci_dev *d, int pos, byte *buf, int len) { struct mdio mdio; - int fd = aix_bus_open(d->access, d->bus); + int fd; + + if (pos + len > 256) + return 0; + fd = aix_bus_open(d->access, d->bus); mdio.md_addr = (ulong) pos; mdio.md_size = len; mdio.md_incr = MV_BYTE; diff --git a/lib/dump.c b/lib/dump.c index 4baeae4..02b2ce4 100644 --- a/lib/dump.c +++ b/lib/dump.c @@ -1,7 +1,7 @@ /* * The PCI Library -- Reading of Bus Dumps * - * Copyright (c) 1997--2003 Martin Mares + * Copyright (c) 1997--2004 Martin Mares * * Can be freely distributed and used under the terms of the GNU GPL. */ @@ -13,12 +13,26 @@ #include "internal.h" +struct dump_data { + int len; + byte data[1]; +}; + static int dump_detect(struct pci_access *a) { return !!a->method_params[PCI_ACCESS_DUMP]; } +static void +dump_alloc_data(struct pci_dev *dev, int len) +{ + struct dump_data *dd = pci_malloc(dev->access, sizeof(struct dump_data) + len - 1); + dd->len = len; + memset(dd->data, 0xff, len); + dev->aux = dd; +} + static void dump_init(struct pci_access *a) { @@ -48,22 +62,32 @@ dump_init(struct pci_access *a) sscanf(buf, "%x:%x:%x.%d", &mn, &bn, &dn, &fn) == 4)) { dev = pci_get_dev(a, mn, bn, dn, fn); - dev->aux = pci_malloc(a, 256); - memset(dev->aux, 0xff, 256); + dump_alloc_data(dev, 256); pci_link_dev(a, dev); } else if (!len) dev = NULL; - else if (dev && len >= 51 && buf[2] == ':' && buf[3] == ' ' && + else if (dev && + (len >= 51 && buf[2] == ':' && buf[3] == ' ' || len >= 52 && buf[3] == ':' && buf[4] == ' ') && sscanf(buf, "%x: ", &i) == 1) { - z = buf+3; + struct dump_data *dd = dev->aux; + z = strchr(buf, ' ') + 1; while (isspace(z[0]) && isxdigit(z[1]) && isxdigit(z[2])) { z++; if (sscanf(z, "%x", &j) != 1 || i >= 256) a->error("dump: Malformed line"); - ((byte *) dev->aux)[i++] = j; + if (i >= 4096) + break; + if (i > dd->len) /* Need to re-allocate the buffer */ + { + dump_alloc_data(dev, 4096); + memcpy(((struct dump_data *) dev->aux)->data, dd->data, 256); + pci_mfree(dd); + dd = dev->aux; + } + dd->data[i++] = j; z += 2; } } @@ -83,17 +107,19 @@ dump_scan(struct pci_access *a UNUSED) static int dump_read(struct pci_dev *d, int pos, byte *buf, int len) { - if (!d->aux) + struct dump_data *dd; + if (!(dd = d->aux)) { struct pci_dev *e = d->access->devices; while (e && (e->bus != d->bus || e->dev != d->dev || e->func != d->func)) e = e->next; - if (e) - d = e; - else + if (!e) return 0; + dd = e->aux; } - memcpy(buf, (byte *) d->aux + pos, len); + if (pos + len > dd->len) + return 0; + memcpy(buf, dd->data + pos, len); return 1; } diff --git a/lib/fbsd-device.c b/lib/fbsd-device.c index 09041e3..c0af6a1 100644 --- a/lib/fbsd-device.c +++ b/lib/fbsd-device.c @@ -74,6 +74,9 @@ fbsd_read(struct pci_dev *d, int pos, byte *buf, int len) return pci_generic_block_read(d, pos, buf, len); } + if (pos >= 256) + return 0; + pi.pi_sel.pc_bus = d->bus; pi.pi_sel.pc_dev = d->dev; pi.pi_sel.pc_func = d->func; @@ -109,6 +112,9 @@ fbsd_write(struct pci_dev *d, int pos, byte *buf, int len) return pci_generic_block_write(d, pos, buf, len); } + if (pos >= 256) + return 0; + pi.pi_sel.pc_bus = d->bus; pi.pi_sel.pc_dev = d->dev; pi.pi_sel.pc_func = d->func; diff --git a/lib/i386-ports.c b/lib/i386-ports.c index d1088c3..f225d24 100644 --- a/lib/i386-ports.c +++ b/lib/i386-ports.c @@ -102,6 +102,10 @@ static int conf1_read(struct pci_dev *d, int pos, byte *buf, int len) { int addr = 0xcfc + (pos&3); + + if (pos >= 256) + return 0; + outl(0x80000000 | ((d->bus & 0xff) << 16) | (PCI_DEVFN(d->dev, d->func) << 8) | (pos&~3), 0xcf8); switch (len) @@ -125,6 +129,10 @@ static int conf1_write(struct pci_dev *d, int pos, byte *buf, int len) { int addr = 0xcfc + (pos&3); + + if (pos >= 256) + return 0; + outl(0x80000000 | ((d->bus & 0xff) << 16) | (PCI_DEVFN(d->dev, d->func) << 8) | (pos&~3), 0xcf8); switch (len) @@ -173,6 +181,9 @@ conf2_read(struct pci_dev *d, int pos, byte *buf, int len) { int addr = 0xc000 | (d->dev << 8) | pos; + if (pos >= 256) + return 0; + if (d->dev >= 16) /* conf2 supports only 16 devices per bus */ return 0; @@ -202,6 +213,9 @@ conf2_write(struct pci_dev *d, int pos, byte *buf, int len) { int addr = 0xc000 | (d->dev << 8) | pos; + if (pos >= 256) + return 0; + if (d->dev >= 16) d->access->error("conf2_write: only first 16 devices exist."); outb((d->func << 1) | 0xf0, 0xcf8); diff --git a/lib/nbsd-libpci.c b/lib/nbsd-libpci.c index 0b247c0..6507287 100644 --- a/lib/nbsd-libpci.c +++ b/lib/nbsd-libpci.c @@ -67,6 +67,9 @@ nbsd_read(struct pci_dev *d, int pos, byte *buf, int len) if (!(len == 1 || len == 2 || len == 4)) return pci_generic_block_read(d, pos, buf, len); + if (pos >= 256) + return 0; + shift = 8*(pos % 4); pos &= ~3; @@ -97,6 +100,9 @@ nbsd_write(struct pci_dev *d, int pos, byte *buf, int len) if (!(len == 1 || len == 2 || len == 4)) return pci_generic_block_write(d, pos, buf, len); + if (pos >= 256) + return 0; + /* * BEWARE: NetBSD seems to support only 32-bit access, so we have * to emulate byte and word writes by read-modify-write, possibly diff --git a/lib/proc.c b/lib/proc.c index 0262143..9d02b41 100644 --- a/lib/proc.c +++ b/lib/proc.c @@ -153,10 +153,7 @@ proc_read(struct pci_dev *d, int pos, byte *buf, int len) return 0; } else if (res != len) - { - d->access->warning("proc_read: tried to read %d bytes at %d, but got only %d", len, pos, res); - return 0; - } + d->access->warning("proc_read: tried to read %d bytes at %d, but got only %d", len, pos, res); return 1; } @@ -176,7 +173,7 @@ proc_write(struct pci_dev *d, int pos, byte *buf, int len) } else if (res != len) { - d->access->warning("proc_write: tried to write %d bytes at %d, but got only %d", len, pos, res); + d->access->warning("proc_write: tried to write %d bytes at %d, but only %d succeeded", len, pos, res); return 0; } return 1; diff --git a/lib/sysfs.c b/lib/sysfs.c index c0cf5a3..0cdfe9a 100644 --- a/lib/sysfs.c +++ b/lib/sysfs.c @@ -222,10 +222,7 @@ static int sysfs_read(struct pci_dev *d, int pos, byte *buf, int len) return 0; } else if (res != len) - { - d->access->warning("sysfs_read: tried to read %d bytes at %d, but got only %d", len, pos, res); - return 0; - } + return 0; return 1; } @@ -244,7 +241,7 @@ static int sysfs_write(struct pci_dev *d, int pos, byte *buf, int len) } else if (res != len) { - d->access->warning("sysfs_write: tried to write %d bytes at %d, but got only %d", len, pos, res); + d->access->warning("sysfs_write: tried to write %d bytes at %d, but only %d succeeded", len, pos, res); return 0; } return 1; diff --git a/lspci.c b/lspci.c index b65202d..07e9184 100644 --- a/lspci.c +++ b/lspci.c @@ -34,6 +34,7 @@ Usage: lspci []\n\ -b\t\tBus-centric view (PCI addresses and IRQ's instead of those seen by the CPU)\n\ -x\t\tShow hex-dump of the standard portion of config space\n\ -xxx\t\tShow hex-dump of the whole config space (dangerous; root only)\n\ +-xxxx\t\tShow hex-dump of the 4096-byte extended config space (root only)\n\ -s [[[[]:]]:][][.[]]\tShow only devices in selected slots\n\ -d []:[]\tShow only selected devices\n\ -t\t\tShow bus tree\n\ @@ -71,7 +72,6 @@ static struct device *first_dev; static struct device * scan_device(struct pci_dev *p) { - int how_much = (show_hex > 2) ? 256 : 64; struct device *d; if (!pci_filter_match(&filter, p)) @@ -79,16 +79,16 @@ scan_device(struct pci_dev *p) d = xmalloc(sizeof(struct device)); bzero(d, sizeof(*d)); d->dev = p; - if (!pci_read_block(p, 0, d->config, how_much)) - die("Unable to read %d bytes of configuration space.", how_much); - if (how_much < 128 && (d->config[PCI_HEADER_TYPE] & 0x7f) == PCI_HEADER_TYPE_CARDBUS) + d->config_cnt = 64; + if (!pci_read_block(p, 0, d->config, 64)) + die("Unable to read the configuration space header."); + if ((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... */ if (!pci_read_block(p, 64, d->config+64, 64)) die("Unable to read cardbus bridge extension data."); - how_much = 128; + d->config_cnt = 128; } - d->config_cnt = how_much; pci_setup_cache(p, d->config, d->config_cnt); pci_fill_info(p, PCI_FILL_IDENT | PCI_FILL_IRQ | PCI_FILL_BASES | PCI_FILL_ROM_BASE | PCI_FILL_SIZES); return d; @@ -109,27 +109,11 @@ scan_devices(void) } } -static int -check_root(void) -{ -#ifdef OS_WINDOWS - return 1; -#else - static int is_root = -1; - - if (is_root < 0) - is_root = !geteuid(); - return is_root; -#endif -} - static int config_fetch(struct device *d, unsigned int pos, unsigned int len) { if (pos + len < d->config_cnt) return 1; - if (pacc->method != PCI_ACCESS_DUMP && !check_root()) - return 0; return pci_read_block(d->dev, pos, d->config + pos, len); } @@ -1308,9 +1292,17 @@ show_verbose(struct device *d) static void show_hex_dump(struct device *d) { - unsigned int i; + unsigned int i, cnt; - for(i=0; iconfig_cnt; i++) + cnt = d->config_cnt; + if (show_hex >= 3 && config_fetch(d, cnt, 256-cnt)) + { + cnt = 256; + if (show_hex >= 4 && config_fetch(d, 256, 4096-256)) + cnt = 4096; + } + + for(i=0; imethod == PCI_ACCESS_PROC_BUS_PCI || pacc->method == PCI_ACCESS_DUMP) printf("WARNING: Bus mapping can be reliable only with direct hardware access enabled.\n\n"); - else if (!check_root()) - die("Only root can map the bus."); bus_info = xmalloc(sizeof(struct bus_info) * 256); bzero(bus_info, sizeof(struct bus_info) * 256); if (filter.bus >= 0) diff --git a/setpci.c b/setpci.c index 9c78176..4f9953d 100644 --- a/setpci.c +++ b/setpci.c @@ -1,7 +1,7 @@ /* * The PCI Utilities -- Manipulate PCI Configuration Registers * - * Copyright (c) 1998--2003 Martin Mares + * Copyright (c) 1998--2004 Martin Mares * * Can be freely distributed and used under the terms of the GNU GPL. */ @@ -454,7 +454,7 @@ next: ll = r->offset; op->width = r->width; } - if (ll > 0x100 || ll + op->width*((n < 0) ? 1 : n) > 0x100) + if (ll > 0x1000 || ll + op->width*((n < 0) ? 1 : n) > 0x1000) die("Register number out of range!"); if (ll & (op->width - 1)) die("Unaligned register address!"); -- 2.39.2