예제 #1
0
파일: pci.c 프로젝트: cbm-fles/pda
static inline
PdaDebugReturnCode
PciDevice_invoke_libpci
(
    PciDevice  *device,
    const char *bus_id
)
{
    DEBUG_PRINTF(PDADEBUG_ENTER, "");

    if(device == NULL)
    { RETURN( ERROR( EINVAL, "Invalid pointer!\n") ); }

    if(bus_id == NULL)
    { RETURN( ERROR( EINVAL, "Invalid pointer!\n") ); }

    if
    (
        (strlen(bus_id) != 12) ||
        (bus_id[4]  != ':')    ||
        (bus_id[7]  != ':')    ||
        (bus_id[10] != '.')
    )
    { RETURN( ERROR( EINVAL, "Invalid bus ID string!\n") ); }

    struct pci_access *pci_access_handler = pci_alloc();
    pci_init(pci_access_handler);
    pci_scan_bus(pci_access_handler);
    for
    (
        struct pci_dev *pci_device = pci_access_handler->devices;
        pci_device;
        pci_device = pci_device->next
    )
    {
        pci_fill_info(pci_device,
                      PCI_FILL_IDENT      |
                      PCI_FILL_IRQ        |
                      PCI_FILL_BASES      |
                      PCI_FILL_ROM_BASE   |
                      PCI_FILL_SIZES      |
                      PCI_FILL_CLASS      |
                      PCI_FILL_CAPS       |
                      PCI_FILL_EXT_CAPS   |
                      PCI_FILL_PHYS_SLOT
                      );

        char device_bus_id[] = "0000:00:00.0";
        snprintf(device_bus_id, 13,"%04x:%02x:%02x.%d", pci_device->domain, pci_device->bus,
                pci_device->dev, pci_device->func);

        if(strcmp(device_bus_id, bus_id) == 0)
        {
            device->domain_id   = pci_device->domain;
            device->bus_id      = pci_device->bus;
            device->device_id   = pci_device->dev;
            device->function_id = pci_device->func;

            for(uint32_t i = 0; i < PDA_MAX_PCI_32_BARS; i++)
            {
                uint32_t bar       = pci_device->base_addr[i];

                DEBUG_PRINTF(PDADEBUG_VALUE, "bar%d : 0x%x\n", i, bar);

                uint8_t  config[64];
                pci_read_block(pci_device, 0, config, 64);
                uint64_t addr      = PCI_BASE_ADDRESS_0 + (4*i);
                uint32_t virt_flag =
                    (config[addr+0]       ) |
                    (config[addr+1] << 8  ) |
                    (config[addr+2] << 16 ) |
                    (config[addr+3] << 24 ) ;

                if(bar && !virt_flag)
                {
                    device->bar_types[i] = PCIBARTYPES_NOT_MAPPED;
                    DEBUG_PRINTF(PDADEBUG_CONTROL_FLOW, "bar%u is virtual\n", i);
                    continue;
                }

                if(bar == 0x0)
                {
                    if(device->bar_types[i] != PCIBARTYPES_NOT_MAPPED)
                    {
                        DEBUG_PRINTF(PDADEBUG_CONTROL_FLOW,
                                     "Inconsistency detected -> bar%u not classified correctly\n", i);
                        device->bar_types[i] = PCIBARTYPES_NOT_MAPPED;
                    }
                    PciDevice_invoke_libpci_set_barsize(device, i, pci_device->size[i]);
                    continue;
                }

                if( (bar & 0x00000001) == 0x1)
                {
                    if(device->bar_types[i] != PCIBARTYPES_IO)
                    {
                        DEBUG_PRINTF(PDADEBUG_CONTROL_FLOW,
                                     "Inconsistency detected -> bar%u not classified correctly\n", i);
                        device->bar_types[i] = PCIBARTYPES_IO;
                    }
                    PciDevice_invoke_libpci_set_barsize(device, i, pci_device->size[i]);
                    continue;
                }

                uint32_t width_bit = bar & 0x00000006;
                if(width_bit == 0x00000000)
                {
                    if(device->bar_types[i] != PCIBARTYPES_BAR32)
                    {
                        DEBUG_PRINTF(PDADEBUG_CONTROL_FLOW,
                                     "Inconsistency detected -> bar%u not classified correctly\n", i);
                        device->bar_types[i] = PCIBARTYPES_BAR32;
                    }
                    PciDevice_invoke_libpci_set_barsize(device, i, pci_device->size[i]);
                    continue;
                }

                if(width_bit == 0x00000004)
                {
                    if(device->bar_types[i] != PCIBARTYPES_BAR64)
                    {
                        DEBUG_PRINTF(PDADEBUG_CONTROL_FLOW,
                                     "Inconsistency detected -> bar%u not classified correctly\n", i);
                        device->bar_types[i] = PCIBARTYPES_BAR64;
                        device->bar_types[i + 1] = PCIBARTYPES_NOT_MAPPED;
                    }
                    PciDevice_invoke_libpci_set_barsize(device, i, pci_device->size[i]);
                    continue;
                }
            }

            /** Older versions of libpci leak memory when this function is called. **/
#if PCI_LIB_VERSION >= 0x030301
            pci_lookup_name(pci_access_handler, device->description, PDA_STRING_LIMIT,
                            PCI_LOOKUP_DEVICE, pci_device->vendor_id,
                            pci_device->device_id);
#else
            #warning "At least version 3.3.1 of libpci is needed. Otherwise the device description can't be returned."
            strcpy(device->description, "");
#endif

            DEBUG_PRINTF(PDADEBUG_VALUE, " (%s) %s\n", device->description, device_bus_id);
        }
    }
    pci_cleanup(pci_access_handler);

    RETURN(PDA_SUCCESS);
}
예제 #2
0
static int
hwloc_look_pci(struct hwloc_backend *backend)
{
  struct hwloc_topology *topology = backend->topology;
  struct hwloc_obj *first_obj = NULL, *last_obj = NULL;
#ifdef HWLOC_HAVE_LIBPCIACCESS
  int ret;
  struct pci_device_iterator *iter;
  struct pci_device *pcidev;
#else /* HWLOC_HAVE_PCIUTILS */
  struct pci_access *pciaccess;
  struct pci_dev *pcidev;
#endif

  if (!(hwloc_topology_get_flags(topology) & (HWLOC_TOPOLOGY_FLAG_IO_DEVICES|HWLOC_TOPOLOGY_FLAG_WHOLE_IO)))
    return 0;

  if (hwloc_get_next_pcidev(topology, NULL)) {
    hwloc_debug("%s", "PCI objects already added, ignoring pci backend.\n");
    return 0;
  }

  if (!hwloc_topology_is_thissystem(topology)) {
    hwloc_debug("%s", "\nno PCI detection (not thissystem)\n");
    return 0;
  }

  hwloc_debug("%s", "\nScanning PCI buses...\n");

  /* initialize PCI scanning */
#ifdef HWLOC_HAVE_LIBPCIACCESS
  ret = pci_system_init();
  if (ret) {
    hwloc_debug("%s", "Can not initialize libpciaccess\n");
    return -1;
  }

  iter = pci_slot_match_iterator_create(NULL);
#else /* HWLOC_HAVE_PCIUTILS */
  pciaccess = pci_alloc();
  pciaccess->error = hwloc_pci_error;
  pciaccess->warning = hwloc_pci_warning;

  if (setjmp(err_buf)) {
    pci_cleanup(pciaccess);
    return -1;
  }

  pci_init(pciaccess);
  pci_scan_bus(pciaccess);
#endif

  /* iterate over devices */
#ifdef HWLOC_HAVE_LIBPCIACCESS
  for (pcidev = pci_device_next(iter);
       pcidev;
       pcidev = pci_device_next(iter))
#else /* HWLOC_HAVE_PCIUTILS */
  for (pcidev = pciaccess->devices;
       pcidev;
       pcidev = pcidev->next)
#endif
  {
    const char *vendorname, *devicename, *fullname;
    unsigned char config_space_cache[CONFIG_SPACE_CACHESIZE];
    struct hwloc_obj *obj;
    unsigned os_index;
    unsigned domain;
    unsigned device_class;
    unsigned short tmp16;
    char name[128];
    unsigned offset;
#ifdef HWLOC_HAVE_PCI_FIND_CAP
    struct pci_cap *cap;
#endif

    /* initialize the config space in case we fail to read it (missing permissions, etc). */
    memset(config_space_cache, 0xff, CONFIG_SPACE_CACHESIZE);
#ifdef HWLOC_HAVE_LIBPCIACCESS
    pci_device_probe(pcidev);
    pci_device_cfg_read(pcidev, config_space_cache, 0, CONFIG_SPACE_CACHESIZE, NULL);
#else /* HWLOC_HAVE_PCIUTILS */
    pci_read_block(pcidev, 0, config_space_cache, CONFIG_SPACE_CACHESIZE); /* doesn't even tell how much it actually reads */
#endif

    /* try to read the domain */
#if (defined HWLOC_HAVE_LIBPCIACCESS) || (defined HWLOC_HAVE_PCIDEV_DOMAIN)
    domain = pcidev->domain;
#else
    domain = 0; /* default domain number */
#endif

    /* try to read the device_class */
#ifdef HWLOC_HAVE_LIBPCIACCESS
    device_class = pcidev->device_class >> 8;
#else /* HWLOC_HAVE_PCIUTILS */
#ifdef HWLOC_HAVE_PCIDEV_DEVICE_CLASS
    device_class = pcidev->device_class;
#else
    device_class = config_space_cache[PCI_CLASS_DEVICE] | (config_space_cache[PCI_CLASS_DEVICE+1] << 8);
#endif
#endif

    /* might be useful for debugging (note that domain might be truncated) */
    os_index = (domain << 20) + (pcidev->bus << 12) + (pcidev->dev << 4) + pcidev->func;

    obj = hwloc_alloc_setup_object(HWLOC_OBJ_PCI_DEVICE, os_index);
    obj->attr->pcidev.domain = domain;
    obj->attr->pcidev.bus = pcidev->bus;
    obj->attr->pcidev.dev = pcidev->dev;
    obj->attr->pcidev.func = pcidev->func;
    obj->attr->pcidev.vendor_id = pcidev->vendor_id;
    obj->attr->pcidev.device_id = pcidev->device_id;
    obj->attr->pcidev.class_id = device_class;
    obj->attr->pcidev.revision = config_space_cache[PCI_REVISION_ID];

    obj->attr->pcidev.linkspeed = 0; /* unknown */
#ifdef HWLOC_HAVE_PCI_FIND_CAP
    cap = pci_find_cap(pcidev, PCI_CAP_ID_EXP, PCI_CAP_NORMAL);
    offset = cap ? cap->addr : 0;
#else
    offset = hwloc_pci_find_cap(config_space_cache, PCI_CAP_ID_EXP);
#endif /* HWLOC_HAVE_PCI_FIND_CAP */

    if (0xffff == pcidev->vendor_id && 0xffff == pcidev->device_id) {
      /* SR-IOV puts ffff:ffff in Virtual Function config space.
       * The actual VF device ID is stored at a special (dynamic) location in the Physical Function config space.
       * VF and PF have the same vendor ID.
       *
       * libpciaccess just returns ffff:ffff, needs to be fixed.
       * linuxpci is OK because sysfs files are already fixed the kernel.
       * pciutils is OK when it uses those Linux sysfs files.
       *
       * Reading these files is an easy way to work around the libpciaccess issue on Linux,
       * but we have no way to know if this is caused by SR-IOV or not.
       *
       * TODO:
       *  If PF has CAP_ID_PCIX or CAP_ID_EXP (offset>0),
       *  look for extended capability PCI_EXT_CAP_ID_SRIOV (need extended config space (more than 256 bytes)),
       *  then read the VF device ID after it (PCI_IOV_DID bytes later).
       *  Needs access to extended config space (needs root on Linux).
       * TODO:
       *  Add string info attributes in VF and PF objects?
       */
#ifdef HWLOC_LINUX_SYS
      /* Workaround for Linux (the kernel returns the VF device/vendor IDs). */
      char path[64];
      char value[16];
      FILE *file;
      snprintf(path, sizeof(path), "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/vendor",
	       domain, pcidev->bus, pcidev->dev, pcidev->func);
      file = fopen(path, "r");
      if (file) {
	fread(value, sizeof(value), 1, file);
	fclose(file);
	obj->attr->pcidev.vendor_id = strtoul(value, NULL, 16);
      }
      snprintf(path, sizeof(path), "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/device",
	       domain, pcidev->bus, pcidev->dev, pcidev->func);
      file = fopen(path, "r");
      if (file) {
	fread(value, sizeof(value), 1, file);
	fclose(file);
	obj->attr->pcidev.device_id = strtoul(value, NULL, 16);
      }
#endif
    }

    if (offset > 0 && offset + 20 /* size of PCI express block up to link status */ <= CONFIG_SPACE_CACHESIZE)
      hwloc_pci_find_linkspeed(config_space_cache, offset, &obj->attr->pcidev.linkspeed);

    hwloc_pci_prepare_bridge(obj, config_space_cache);

    if (obj->type == HWLOC_OBJ_PCI_DEVICE) {
      memcpy(&tmp16, &config_space_cache[PCI_SUBSYSTEM_VENDOR_ID], sizeof(tmp16));
      obj->attr->pcidev.subvendor_id = tmp16;
      memcpy(&tmp16, &config_space_cache[PCI_SUBSYSTEM_ID], sizeof(tmp16));
      obj->attr->pcidev.subdevice_id = tmp16;
    } else {
      /* TODO:
       * bridge must lookup PCI_CAP_ID_SSVID and then look at offset+PCI_SSVID_VENDOR/DEVICE_ID
       * cardbus must look at PCI_CB_SUBSYSTEM_VENDOR_ID and PCI_CB_SUBSYSTEM_ID
       */
    }

    /* starting from pciutils 2.2, pci_lookup_name() takes a variable number
     * of arguments, and supports the PCI_LOOKUP_NO_NUMBERS flag.
     */

    /* get the vendor name */
#ifdef HWLOC_HAVE_LIBPCIACCESS
    vendorname = pci_device_get_vendor_name(pcidev);
#else /* HWLOC_HAVE_PCIUTILS */
    vendorname = pci_lookup_name(pciaccess, name, sizeof(name),
#if HAVE_DECL_PCI_LOOKUP_NO_NUMBERS
			      PCI_LOOKUP_VENDOR|PCI_LOOKUP_NO_NUMBERS,
			      pcidev->vendor_id
#else
			      PCI_LOOKUP_VENDOR,
			      pcidev->vendor_id, 0, 0, 0
#endif
			      );
#endif /* HWLOC_HAVE_PCIUTILS */
    if (vendorname && *vendorname)
      hwloc_obj_add_info(obj, "PCIVendor", vendorname);

    /* get the device name */
#ifdef HWLOC_HAVE_LIBPCIACCESS
    devicename = pci_device_get_device_name(pcidev);
#else /* HWLOC_HAVE_PCIUTILS */
    devicename = pci_lookup_name(pciaccess, name, sizeof(name),
#if HAVE_DECL_PCI_LOOKUP_NO_NUMBERS
			      PCI_LOOKUP_DEVICE|PCI_LOOKUP_NO_NUMBERS,
			      pcidev->vendor_id, pcidev->device_id
#else
			      PCI_LOOKUP_DEVICE,
			      pcidev->vendor_id, pcidev->device_id, 0, 0
#endif
			      );
#endif /* HWLOC_HAVE_PCIUTILS */
    if (devicename && *devicename)
      hwloc_obj_add_info(obj, "PCIDevice", devicename);

    /* generate or get the fullname */
#ifdef HWLOC_HAVE_LIBPCIACCESS
    snprintf(name, sizeof(name), "%s%s%s",
	     vendorname ? vendorname : "",
	     vendorname && devicename ? " " : "",
	     devicename ? devicename : "");
    fullname = name;
    if (*name)
      obj->name = strdup(name);
#else /* HWLOC_HAVE_PCIUTILS */
    fullname = pci_lookup_name(pciaccess, name, sizeof(name),
#if HAVE_DECL_PCI_LOOKUP_NO_NUMBERS
			      PCI_LOOKUP_VENDOR|PCI_LOOKUP_DEVICE|PCI_LOOKUP_NO_NUMBERS,
			      pcidev->vendor_id, pcidev->device_id
#else
			      PCI_LOOKUP_VENDOR|PCI_LOOKUP_DEVICE,
			      pcidev->vendor_id, pcidev->device_id, 0, 0
#endif
			      );
    if (fullname && *fullname)
      obj->name = strdup(fullname);
#endif /* HWLOC_HAVE_PCIUTILS */
    hwloc_debug("  %04x:%02x:%02x.%01x %04x %04x:%04x %s\n",
		domain, pcidev->bus, pcidev->dev, pcidev->func,
		device_class, pcidev->vendor_id, pcidev->device_id,
		fullname && *fullname ? fullname : "??");

    /* queue the object for now */
    if (first_obj)
      last_obj->next_sibling = obj;
    else
      first_obj = obj;
    last_obj = obj;
  }

  /* finalize device scanning */
#ifdef HWLOC_HAVE_LIBPCIACCESS
  pci_iterator_destroy(iter);
  pci_system_cleanup();
#else /* HWLOC_HAVE_PCIUTILS */
  pci_cleanup(pciaccess);
#endif

  return hwloc_insert_pci_device_list(backend, first_obj);
}
예제 #3
0
파일: pci.cpp 프로젝트: DrakXtools/ldetect
void pci::probe(void) {
    pci_scan_bus(_pacc);

    uint8_t buf[CONFIG_SPACE_SIZE] = {0};
    char classbuf[128] = {0}, vendorbuf[128] {0}, devbuf[128] = {0};

    for (struct pci_dev *dev = _pacc->devices; dev && _entries.size() < MAX_DEVICES; dev = dev->next) {
	_entries.push_back(pciEntry());
	pciEntry &e = _entries.back();
	memset(buf, 0, sizeof(buf));
	memset(classbuf, 0, sizeof(classbuf));
	memset(vendorbuf, 0, sizeof(vendorbuf));
	memset(devbuf, 0, sizeof(devbuf));

	pci_setup_cache(dev, buf, CONFIG_SPACE_SIZE);
	pci_read_block(dev, 0, buf, CONFIG_SPACE_SIZE);
	pci_fill_info(dev, PCI_FILL_IDENT | PCI_FILL_CLASS | PCI_FILL_CAPS);

	pci_lookup_name(_pacc, vendorbuf, sizeof(vendorbuf), PCI_LOOKUP_VENDOR, dev->vendor_id, dev->device_id);
	pci_lookup_name(_pacc, devbuf,    sizeof(devbuf),    PCI_LOOKUP_DEVICE, dev->vendor_id, dev->device_id);
	e.text.append(vendorbuf).append("|").append(devbuf);
	e.class_type += classbuf;
	e.vendor =     dev->vendor_id;
	e.device =     dev->device_id;
	e.pci_domain = dev->domain;
	e.bus =        dev->bus;
	e.pciusb_device = dev->dev;
	e.pci_function = dev->func;

	e.class_id = dev->device_class;
	e.subvendor = pci_read_word(dev, PCI_SUBSYSTEM_VENDOR_ID);
	e.subdevice = pci_read_word(dev, PCI_SUBSYSTEM_ID);
	e.pci_revision = pci_read_byte(dev, PCI_REVISION_ID);

	if ((e.subvendor == 0 && e.subdevice == 0) ||
		(e.subvendor == e.vendor && e.subdevice == e.device)) {
	    e.subvendor = 0xffff;
	    e.subdevice = 0xffff;
	}

	if (pci_find_cap(dev,PCI_CAP_ID_EXP, PCI_CAP_NORMAL))
	    e.is_pciexpress = true;

	/* special case for realtek 8139 that has two drivers */
	if (e.vendor == 0x10ec && e.device == 0x8139) {
	    if (e.pci_revision < 0x20)
		e.module = "8139too";
	    else
		e.module = "8139cp";
	}
    }

    // fake two PCI controllers for xen
    struct stat sb;
    if (!stat("/sys/bus/xen", &sb)) {
	// FIXME: use C++ streams..
	FILE *f;
	if ((f = fopen("/sys/hypervisor/uuid", "r"))) {
	    char buf[38];
	    fgets(buf, sizeof(buf) - 1, f);
	    fclose(f);
	    if (strncmp(buf, "00000000-0000-0000-0000-000000000000", sizeof(buf))) {
		// We're now sure to be in a Xen guest:
		{
		    _entries.push_back(pciEntry());
		    pciEntry &e = _entries.back();
		    e.text.append("XenSource, Inc.|Block Frontend");
		    e.class_id = 0x0106; // STORAGE_SATA

		    e.vendor =  0x1a71; // XenSource
		    e.device =  0xfffa; // fake
		    e.subvendor = 0;
		    e.subdevice = 0;
		    e.class_id = 0x0106;
		    e.module = "xen_blkfront";
		}
		{
		    _entries.push_back(pciEntry());
		    pciEntry &e = _entries.back();
		    e.text.append("XenSource, Inc.|Network Frontend");
		    e.class_id = 0x0200; // NETWORK_ETHERNET

		    e.vendor =  0x1a71; // XenSource
		    e.device =  0xfffb; // fake
		    e.subvendor = 0;
		    e.subdevice = 0;
		    e.class_id = 0x0200;
		    e.module = "xen_netfront";
		}
	    }
	}
    }
    findModules("pcitable", false);
}