赞
踩
最近在看王齐老师编写的PCI Express体系结构导读,受益颇深,因此打算编程实现写小程序,加深对PCIE知识的理解。动手实践理解更深刻。
本文章参考此博客: linux环境下遍历PCI设备,在此基础上实现了对PCIE 0x00~0x3f配置空间中的读取,打印输出基本和linux 自带lspci -x 命令形式一致。
wimdow7系统,Intel 64位处理器
VMware虚拟机 ubuntu14.04
HOST桥通过bus号,device号,和function号访问到PCIE设备的信息,register号是PCIE设备配置空间(PCIe设备配置空间4096KB)中寄存器的偏移。X86处理器这些信息存放在CONFIG_ADDR寄存器中,CONFIG_DATA寄存器保存该地址中的数据。因此可以通过读写这两个寄存器获取到PCIE设备配置空间中的信息,在X86处理器中这两个寄存器的地址为:
ONFIG_ADDRESS地址是0xcf8,也就是说通过访问0xcf8就可以访问CONFIG_ADDRESS寄存器,
CONFIG_DATA地址是0xcfc,CONFIG_DATA用来存放进行配置读写的数据。
注意 X86处理器下CNFIG_ADDRESS的基地址0x80000000
bit31是使能对PCI Bus CONFIG_DATA的访问;
bit 30~24为保留,为只读,访问时返回值为0;
bit 23~16是Bus号;
bit 15~10是设备号;
bit 10~8是功能号;
bit 7~2是配置空间中的寄存器,单位为DWORD。
bit 1~0为只读,读取时放回为0。
PCIE设备配置空间
PCIe 设备配置空间(0x00~0x03F)
注意 i386处理器 I/O 空间和内存空间的进程的 I/O 空间写入数据方式不同。Port I/O方式只能访问PCI配置空间,而不能访问PCI-E扩展配置空间(257~4096字节),此时只能通过MMIO方式。
#include <sys/io.h> #include <stdio.h> #include <unistd.h> #include <stdlib.h> //define pcie device info limit #define MAX_BUS 256 #define MAX_DEVICE 32 #define MAX_FUNCTION 8 //define CONFIG_ADDRESS and CONFIG_DATA #define CONFIG_ADDRESS 0xCF8 #define CONFIG_DATA 0xCFC #define BASE_ADDR 0x80000000 typedef unsigned int WORD;//4byte int main() { WORD bus,device,func,reg; WORD data,address;//read info from CONFIG_DATA,address set to CONFIG_ADDRESS int ret=0; //unsigned char tmpc; ret = iopl(3); if(ret<0) { perror("iopl set to high level error\n"); return -1; } //printf("bus\tdev\func\n"); for(bus=0;bus<MAX_BUS;bus++) for(device=0;device<MAX_DEVICE;device++) for(func=0;func<MAX_FUNCTION;func++) { for(reg=0;reg<16;reg++) address = BASE_ADDR|(bus<<16)|(device<<11)|(func<<8); outl(address,CONFIG_ADDRESS);//put addr to config_address data = inl(CONFIG_DATA);//read data from config data; if((data!=0xffffffff) && (data!=0)) { printf("\n%02x:%02x:%02x\n",bus,device,func); for(reg=0;reg<16;reg++) { if(reg%4==0) { printf("%02x:",reg*4); } address = BASE_ADDR|(bus<<16)|(device<<11)|(func<<8)|(reg<<2); outl(address,CONFIG_ADDRESS);//put addr to config_address data = inl(CONFIG_DATA);//read data from config data; printf("%02x ",(unsigned char)(data>>0)); printf("%02x ",(unsigned char)(data>>0)); printf("%02x ",(unsigned char)(data>>0)); printf("%02x ",(unsigned char)(data>>0)); if(reg%4==3) printf("\n"); } } } iopl(0); if(ret<0) { perror("iopl set to low level error\n"); return -1; } return 0; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。