Cómo permitir que Linux vuelva a enumerar dispositivos pci
Método 1: este método requiere operación de puerto. En Linux, las aplicaciones normales no tienen permiso para leer y escribir puertos de E/S. Necesitan elevar los permisos a través de iopl o ioperm. .
[cpp]¿Ver Plaincopyprint?
/*
* Enumerar todos los dispositivos PCI a través de registros de configuración PCI (CF8 y CFC).
*/
#include lt;stdio.hgt;
#include lt;stdlib.hgt;
#include lt; unistd.hgt;
#include lt;sys/io.h gt;
#define PCI_MAX_BUS 255 /* 8 bits (0 ~ 255)*/
#define PCI_MAX_DEV 31 /* 5 bits (0 ~ 31) */
#define PCI_MAX_FUN 7 /*3 bits (0 ~ 7) */<
#define CONFIG_ADDRESS 0xCF8
#define CONFIG_DATA 0xCFC
#define PCICFG_REG_VID 0x00 /* ID de proveedor, 2 bytes*/
#define PCICFG_REG_DID 0x02 /* ID de dispositivo, 2 bytes* /
#define PCICFG_REG_CMD 0x04 /* Registro de comando, 2 bytes*/
#define PCICFG_REG_STAT 0x06 /* Registro de estado, 2 bytes*/
#define PCICFG_REG_RID 0x08 /* ID de versión, 1 byte*/
void list_pci_devices()
{
unsigned int bus , dev, fun;
dirección int sin signo, datos;
//printf("BB:DD:FF VID:DID/n");
for (bus = 0; bus lt; = PCI_MAX_BUS; bus) {
para (dev = 0; dev lt; = PCI_MAX_DEV; dev) {
para (diversión = 0; diversión lt; = PCI_MAX_FUN; diversión) {
addr = 0x80000000L | (buslt; lt; 16) | (devlt; lt; 11) | (funlt; lt; 8);
outl(dirección, CONFIG_ADDRESS); p>
data = inl(CONFIG_DATA);
/* Identificar el ID del proveedor */
if ((data ! = 0xFFFFFFFF) amp; (datos! = 0)) {
printf("02X:02X:02X ", bus, dev, diversión
printf("04X); :04X", dataamp;0xFFFF, datagt;gt;16);
addr = 0x80000000L | (buslt;lt;16) | (devlt;lt;11) | (funlt;lt;8) | PCICFG_REG_RID;
outl(addr, CONFIG_ADDRESS);
datos = inl(CONFIG_DATA);
if (datosamp; 0xFF) {
pri
ntf(" (rev 02X)\n", dataamp; 0xFF);
} else {
printf("\n");
}
}
}}
} función final
}// Dispositivo final
}
}// final del bus
}
int main()
{
int ret;
/* Habilitar permiso r/w de todos los 65536 puertos */
ret = iopl(3);
if (ret lt; 0) {
perror("iopl set error");
return 1;
}
list_pci_devices();
/* Deshabilitar todo 65536 permisos de lectura/escritura del puerto*/
ret = iopl(0);
if (ret lt; 0) {
perror("error de configuración de iopl ");
devuelve 1;
}
devuelve 0;
}
Método 2: este El método no requiere manipulación de puertos, pero utiliza procfs de Linux para acceder al espacio de configuración PCI.
[cpp] ¿Ver Plaincopyprint?
/*
* Enumerar todos los dispositivos pci a través de /proc/bus/pci/.
*/
#include lt;stdio.hgt;
#include lt;stdint.hgt;
#include lt; stdlib.hgt;
#include lt;string.hgt;
#include lt;fcntl.hgt;
#include lt;unistd.hgt;
#define PCI_MAX_BUS 255 /* 8 bits (0 ~ 255) */
#define PCI_MAX_DEV 31 /* 5 bits (0 ~ 255) */
#define PCI_MAX_DEV 31 /* 5 bits (0 ~ 255) */
#define PCI_MAX_DEV 31DEV 31 /* 5 bits (0 ~ 31) */
#define PCI_MAX_FUN 7 / * 3 bits (0 ~ 7) */
/*
*
* Desplazamiento del encabezado de configuración PCI
*/ p>
#define PCICFG_REG_VID 0x00 /* ID de proveedor, 2 bytes*/
#define PCICFG_REG_DID 0x02 /* ID de dispositivo, 2 bytes*/
#define PCICFG_REG_CMD 0x04 / * Registro de comando, 2 bytes*/
#define PCICFG_REG_STAT 0x06 /* Registro de estado, 2 bytes*/
#define PCICFG_REG_RID 0x08 / * ID de versión, 1 byte */ p>
#define PCICFG_REG_PROG_INTF 0x09 /* Código de interfaz de programación, 1 byte*/
#define PCICFG_REG_SUBCLASS 0x0A /* Código de subclase, 1 byte*/
#define PCICFG_REG_BASCLASS 0x0B /* Código de clase base, 1 byte*/
#define PCICFG_REG_CACHE_LINESZ 0x0C /* Tamaño de línea de caché, 1 byte*/
#define PCICFG_REG_LATENCY_TIMER 0x0D /* Temporizador de latencia , 1 byte*/
#define PCICFG_REG_HEADER_TYPE 0x0E /* Tipo de encabezado, 1 byte* /
#define PCICFG_REG_BIST 0x0F /* Autoprueba incorporada, 1 byte*/
#define PCICFG_REG_BAR0 0x10 /* Registro de dirección base 0, 4 bytes*/ p>
#define PCICFG_REG_BAR1 0x14 /* Registro de dirección base 1, 4 bytes*/
#define PCICFG_REG_BAR2 0x18 /* Registro de dirección base 2, 4 bytes*/
#define PCICFG_REG_BAR3 0x1C /* Registro de dirección base 3, 4 bytes*/
#define PCICF
G_REG_BAR4 0x20 /* Registro de dirección base 4, 4 bytes*/
#define PCICFG_REG_BAR5 0x24 /* Registro de dirección base 5, 4 bytes*/
#define PCICFG_REG_CIS 0x28 / *Bus CIS pointer*/
#define PCICFG_REG_SVID 0x2C /* ID del proveedor del subsistema, 2 bytes*/
#define PCICFG_REG_SDID 0x2E /* ID del subsistema, 2 bytes Byte*/
#define PCICFG_REG_ROMBAR 0x30 /* Registro básico de ROM, 4
#define PCICFG_REG_INT_PIN 0x3D /* Pin de interrupción, 1 byte*/
#define PCICFG_REG_MIN_GNT 0x3E /* Autorización mínima, 1 byte*/
##define PCICFG_REG_MIN_GNT 0x3E /* Autorización mínima, 1 byte*/
#define PCICFG_REG_MAX_LAT 0x3F /* Lat máxima, 1 byte */
void list_pci_devices()
{
unsigned int bus, dev, fun;
// printf ("BB:DD:FF VID:DID(RID )\n");
para (bus = 0; bus lt; = PCI_MAX_BUS; bus) {
para ( dev = 0; dev lt; = PCI_MAX_DEV; dev ) {
for (diversión = 0; diversión lt; = PCI_MAX_FUN; diversión ) {
char proc_name[64];
p>int cfg_handle;
uint32_t data;
uint16_t vid, did;
uint8 _t rid;
snprintf( proc_name, sizeof(proc_name),
"/proc/bus/pci/02x/02x.x", bus, dev, fun);
cfg_handle = open(proc_ name, O_RDWR);
if (cfg_handle lt; = 0)
continuar;
lseek(cfg_handle, PCICFG_REG_VID, SEEK_SET);
leer(cfg_handle, & data, sizeof(data) );
/* Identificar el ID del proveedor */
if ((data! = 0xFFFFFFFF) amp;amp; (datos!= 0)) {
lseek(cfg_handle, PCICFG_REG_RID, SEEK_SET);
read(cfg_handle, amp;rid, sizeof(rid) );
vid = datosamp;
F;
did = datagt; 16;
printf("02X:02X:02X", bus, desarrollo, diversión
if ( deshacerse de gt; 0) {
printf(" 04X: 04X (rev 02X)\n", vid, hizo, deshacerse
} más {
printf(" 04X: 04X\n", vid, hizo
}
}
}
}// función final
}// dispositivo final
}
}// bus final
}
int main(int argc, char **argv)
{
list_pci_devices();
devuelve 0;
}
Ambos métodos tienen sus ventajas y desventajas. El primero es fácil de migrar a otros sistemas operativos, mientras que el segundo es menos conveniente. El segundo método no es necesario.
Nota: Se requieren permisos de superusuario (root) para ejecutar estos dos fragmentos de código.
Añadido: Hoy descubrí un problema al enumerar el IMC (Controlador de memoria integrado) del procesador Westmere-EP (procesador Intel Xeon serie 5500 (Nehalem-EP)) que lspci no puede enumerar IMC. Westmere-EP es una nueva arquitectura de procesador lanzada por Intel Corporation. A diferencia de las CPU anteriores, Westmere-EP integra el controlador de memoria en la CPU. El controlador IMC está asignado al bus PCI y los números de bus son 0xFE ~ 0xFF, pero no existe tal dispositivo en procfs (/proc/bus/pci/). Sin embargo, estos dispositivos se pueden enumerar a través del puerto CF8/CFC.
3. Este código en el controlador se puede utilizar para encontrar un dispositivo pci específico y devolver la variable de estructura pci_dev. Con dicha variable de estructura, puede conectar directamente las funciones de interfaz proporcionadas por el kernel, como pci_read_config_word(), pci_write_config_word(), etc.
[cpp] ¿Ver copia impresa simple?
void list_pci_device()
{
struct pci_dev *dev;
struct pci_bus *bus, *childbus;
list_for_each_entry(bus, amp; pci_root_buses, nodo) { //globle pci_root_buses en pci.h
list_for_each_entry(dev, amp; bus-gt.devices, bus_list) { // para bus 0
printk("02X: 02X: 02X 04X: 04X\n", dev-gt; bus-gt; número, dev-gt; devfn gt; gt; 3, dev-gt; devfn amp; 0x07 , dev-gt; proveedor, dev-gt; dispositivo);
}
list_for_each_entry(childbus, amp; bus-gt; niños, nodo) { // para el bus 1, 2, 3, .....
list_for_each_entry(dev, amp; childbus-gt; dispositivos, bus_list) {
printk("02X:02X:02X 04X:04X\ n", dev-gt; bus-gt.number, dev-gt; devfn gt; gt; 3, dev-gt; devfn amp; 0x07, dev-gt; proveedor, dev-gt; dispositivo);
}
}
}
}
}
}