Red de conocimiento informático - Conocimiento informático - Cómo permitir que Linux vuelva a enumerar dispositivos pci

Cómo permitir que Linux vuelva a enumerar dispositivos pci

En Linux, lspci puede enumerar todos los dispositivos PCI. Lo hace leyendo la información del espacio de configuración PCI. Aquí simularé la funcionalidad de lspci de dos maneras. Uno es enumerar a través de los puertos CF8 y CFC del bus PCI (consulte la especificación del bus PCI); el otro es utilizar el sistema de archivos proc;

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);

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

*/

#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 */

#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*/

#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);

}

}

}

}

}

}