当前位置: 首页 > 工具软件 > PCI工具包 > 使用案例 >

10.26-pci

曹驰
2023-12-01

10.26

任务目标 // 进度:

  • PCI学习,编写小工具列出系统PCI设备(穷举法&递归法)

工作结果:

学习笔记:

PCI总线:一种高性能32位或者64位的多路复用地址或者数据行的总线。

​ 作用:高度集成外围控制器、外围插件和处理器/内存系统之间的互连机制。

BDF码:总线号,设备号,功能号

​ 作用:描述PCI设备物理连接情况。一个系统可以有256个PCI总线,每个总线上可以有32个设备,每个设备可以具有8个功能(每个功能作为一个PCI设备)。当这三个数据确定的时候,就可以在系统中唯一确定一个PCI 设备。

8~10:功能位:有时候,一个pci设备对应多个功能.将每个功能单元分离出来,对应一个独立的pci device
11~15位:设备号:对应该pci总线上的设备序号
16~23位:总线号:根总线的总线号为0.每遍历到下层总线,总线号+1。(下层总线的资源是它上层总线资源的子集,上层总线资源是下层总线资源的父集。)

busdevfunc
16-23位11-15位8-10位
8位5位3位
256条32个7个
左移8位3位0
最大0xFF0x1F0x7
mask0xFF000xF80x0007

PCI设备有三个空间——内存地址空间、IO地址空间和配置空间。

pci配置空间
PCI配置空间是一块容量为256字节并具有特定记录结构或模型的地址空间,通过配置空间,我们可以了解该PCI设备的一些配置情况,进而控制该设备,除主总线桥以外的所有PCI设备都必须事先配置空间.

配置空间的前64个字节叫头标区,头标区又分成两个部分,第一部分为前16个字节,在各种类型的设备中定义都是一样的,其他字节随各设备支持的功能不同而有所不同,位于偏移0EH的投标类型字段规定了是何种布局,目前有三种头标类型,头标类型1用于PCI-PCI桥,头标类型2用于PCI-CARDBUS桥,头标类型0用于其他PCI设备,下为头标类型0的头标区布局。

头标区中有5个字段涉及设备的识别。

​ 供应商识别字段(Vendor ID)
偏移:00H。该字段用以标明设备的制造者。一个有效的供应商标识由PCI SIG来分配,以保证它的唯一性。0FFFFH是该字段的无效值。

​ 设备识别字段(Device ID)
偏移:02H。用以标明特定的设备,具体代码由供应商来分配。

​ 版本识别字段(Revision ID)
偏移:08H。用来指定一个设备特有的版本识别代码,其值由供应商提供,可以是0。

​ 头标类型字段(Header Type)
偏移:0EH。该字段有两个作用,一是用来表示配置空间头标区第二部分的布局类型;二是用以指定设备是否包含多功能。位7用来标识一个多功能设备,位7为0表明是单功能设备,位7为1表明是多功能设备。位0-位6表明头标区类型。

​ 分类代码字段(Class Code)
偏移:09H。标识设备的总体功能和特定的寄存器级编程接口。该字节分三部分,每部分占一个字节,第一部分是基本分类代码,位于偏移0BH,第二部分叫子分类代码,位于偏移0AH处,第三部分用于标识一个特定的寄存器级编程接口

io口访问pci设备

可通过访问CF8h、CFCh端口来实现:

CF8h: CONFIG_ADDRESS。PCI配置空间地址端口。
CFCh: CONFIG_DATA。PCI配置空间数据端口。

CONFIG_ADDRESS寄存器格式:
  31位:Enabled位。
23:16 位:总线编号。
15:11 位:设备编号。
10: 8 位:功能编号。
7: 2 位:配置空间寄存器编号。
1: 0 位:恒为“00”。这是因为CF8h、CFCh端口是32位端口。

在dos下申请相关的接口就可以得到io口,通过cf8和cfc的模式进行读取遍历pci设备。

#include <stdio.h>
typedef unsigned long DWORD;
typedef unsigned int WORD;
#define MK_PDI(bus,dev,func) (WORD)((bus<<8)|(dev<<3)|(func))     
#define MK_PCIaddr(bus,dev,func) (DWORD)(0xf8000000L|(DWORD)MK_PDI(bus,dev,func)<<8)
#define PCI_CONFIG_ADDRESS 0xCF8 
#define PCI_CONFIG_DATA 0xCFC
DWORD inpd(int inport)
{
DWORD data;
asm mov dx,inport;
asm lea bx,data;
__emit__(
0x66,0x50,
0x66,0xED,
0x66,0x89,0x07,
0x66,0x58);
return data;
}

void outpd(int outport,DWORD addr)
{
asm mov dx,outport;
asm lea bx,addr;
__emit__(
0x66,0x50,
0x66,0x8B,0x07,
0x66,0xEF,
0x66,0x58);
}
DWORD GetData(DWORD addr)
{
DWORD data;
outpd(PCI_CONFIG_ADDRESS,addr);
data = inpd(PCI_CONFIG_DATA);
return data;
}
int main()
{
int bus,dev,func;
DWORD addr,addr1,addr2,addr3;
DWORD data,data1,data2,data3;
printf("Bus#\tDev#\tFunc#");
printf("\n");
for (bus = 0; bus <= 0x63; ++bus)
{
for (dev = 0; dev <= 0x1F; ++dev)
{
for (func = 0; func <= 0x7; ++func)
{
addr = MK_PCIaddr(bus,dev,func);
data = GetData(addr);
if((WORD)data!=0xFFFF)     //FFFFh是一个非法厂商ID,可它来判断PCI设备是否存在。
{
printf("%2.2x\t%2.2x\t%2.2x\t",bus,dev,func);
printf("\n"); 
}
}
}
}
return 0;
}


遍历pci设备

PCI的配置空间

PCI总线—PCI设备扫描过程

枚举PCI设备的讨论

PCIe 2. 深入PCI与PCIe之二:软件篇

【精讲】PCIe基础篇——BDF与配置空间

【精讲】PCIe基础篇——BAR配置过程

【14】PCIe架构下memory空间、IO空间、PCIe配置空间简介

心情感悟:

 类似资料: