PCI总线使用并行总线结构,采用单端并行信号,同一条总线上的所有设备共享总线带宽
PCIe总线使用高速差分总线,采用端到端连接方式,每一条PCIE链路只能连接两个设备
PCIe的端到端连接方式
发送端和接收端都含有TX(发送逻辑),RX(接受逻辑)
这里就自然地提到一个函数,
头文件
void* mmap(void* start,size_t length,int prot,int flags,int fd,off_toffset);
int munmap(void* start,size_t length);
mmap函数用来将内存空间映射到内核空间
munmap用来解除这个映射关系
函数参数:start映射区開始地址,設置為NULL時表示由系統決定
length映射区長度單位,地址自然是sizeof(unsigned long)
prot設置為PORT_READ|PORT_WRITE表示頁可以被读写
flag指定映射对象类型,MAP_SHARED表示與其他所有映射這個对象的所有进程共享映射空间
fd,/dev/mem文件描述符
offset被映射對象內容的起點
“/dev/mem”物理內存全映像,可以用來訪問物理內存,一般是open("/dev/mem",O_RD_WR),然后mmap,接著就可以用mmap地址訪問物理內存(root权限)
遍历时只需要根据相应的offset偏移即可PCIe设备的配置空间!
这是0x34h位置即Capability Pointer所代表的空间,也就是说Capability Pointer虽然听起来像一个指针,但是他只是一个8bit的数据,这里面存放了一个地址,而这个地址,就是我们要找的,
意义上Capability Pointer所指向的东西,我们来看看他究竟要指向哪里,就是这里喽!
capbility pointer里面存放的地址就是上图00h的地址喽,也就是上表的基地址,那么问题来了我们为什么要找这个表呢?在这个表中,00h位置0~7bit是capbility ID,如果他的值是10h,就表明这是个PCIe设备的cap structure,也就是说我们已经找到了PCIe设备啦,如果他不是10h怎么办?没关系,因为在00h的7~15bit的地方还有next Cap pointer,跟Capbility structure原理类似,他也是个看起来像指针的字节,里面存放的就是下一个capbility structure的地址了,我们只需要根据这里的地址把基地址偏移过去就好了,直到我们找到next cap pointer为0的时候,就代表他后面已经没有了,这时候我们就要跳出当前循环了
#include
#include
#include
#include
#include
#include //mmap
#include //open filel
#define MAX_BUS 5 //一般来说到4就够了
#define MAX_DEV 32
#define MAX_FUN 8
#define BASE_ADDR 0xf8000000 //我的电脑的基地址,你的可能不一样哦
#define LEN_SIZE sizeof(unsigned long)
typedef unsigned int WORD;
typedef unsigned char BYTE;//8bit
void typeshow(BYTE data) //
{
printf("%x\n",data);
switch(data)
{
case 0x00:printf("PCIExpress Endpoint device\n");
break;
case 0x01:printf("LegacyPCI Express Endpoint device\n");
break;
case 0x04:printf("RootPort of PCI Express Root Complex\n");
break;
case 0x05:printf("Upstream Port of PCI Express Switch\n");
break;
case 0x06:printf("DownstreamPort of PCI Express Switch\n");
break;
case 0x07:printf("PCiExpress-to-PCI/PCI-x Bridge\n");
break;
case 0x08:printf("PCI/PCI-xto PCi Express Bridge\n");
break;
case 0x09:printf("RootComplex Integrated Endpoint Device\n");
break;
case 0x0a:printf("RootComplex Event Collector\n");
break;
default:printf("reserved\n");
break;
}
printf("\n");
}
void speedshow(BYTE speed)
{
printf("%x\n",speed);
switch(speed)
{
case 0x00:printf("2.5GT/S");
break;
case 0x02:printf("5GT/S");
break;
case 0x04:printf("8GT/S");
break;
default:printf("reserved");
break;
}
printf("\n\n");
}
void linkspeedshow(BYTE speed)
{
printf("%x\n",speed);
switch(speed)
{
case 0x01:printf("SupportedLink Speeds Vector filed bit 0");
break;
case 0x02:printf("SupportedLink Speeds Vector filed bit 1");
break;
case 0x03:printf("SupportedLink Speeds Vector filed bit 2");
break;
case 0x04:printf("SupportedLink Speeds Vector filed bit 3");
break;
case 0x05:printf("SupportedLink Speeds Vector filed bit 4");
break;
case 0x06:printf("SupportedLink Speeds Vector filed bit 5");
break;
case 0x07:printf("SupportedLink Speeds Vector filed bit 6");
break;
default:printf("reserved");
break;
}
printf("\n\n");
}
void linkwidthshow(BYTE width)
{
printf("%x\n",width);
switch(width)
{
case 0x01:printf("x1");
break;
case 0x02:printf("x2");
break;
case 0x04:printf("x4");
break;
case 0x08:printf("x8");
break;
case 0x0c:printf("x12");
break;
case 0x10:printf("x16");
break;
case 0x20:printf("x32");
break;
default:printf("reserved");
break;
}
printf("\n\n");
}
int main()
{
WORD addr=0;
WORDbus,dev,fun;
WORD *ptrdata;
WORD*ptrsearch;
BYTE nextpoint;//8bit
int fd;
int i;
fd=open("/dev/mem",O_RDWR);
//“/dev/mem”物理內存全映像,可以用來訪問物理內存,一般是open("/dev/mem",O_RD_WR),然後mmap,接著就可以用mmap地址訪問物理內存
if(fd<0)
{
printf("openmemory failed!\n");
return -1;
}
printf("fd=%d\n",fd);
for(bus=0;bus>8)&0x0000ffff);
printf("ptrsearch:%x\n",*ptrsearch);
printf("type:");
typeshow((BYTE)(((*ptrsearch)>>20)&0x0f));
printf("speed:");
speedshow((BYTE)(((*(ptrsearch+0x2c/4))>>1)&0x7f));
printf("linkspeed:");
linkspeedshow((BYTE)(*(ptrsearch+0x0c/4)&0x0f));
printf("linkwidth:");
linkwidthshow((BYTE)(((*(ptrsearch+0x0c/4))>>4)&0x3f));
printf("***************************");
break;//havefound the pcie device and printed all the message,break the while
}
if((BYTE)((*ptrsearch)>>8)==0x00)//no pcie device exsist
break;
ptrsearch=ptrdata+((BYTE)(((*ptrsearch)>>8)&0x00ff))/4;//next cap pointer
printf("next pointer:%x\n",*ptrsearch);
}
}
munmap(ptrdata,LEN_SIZE);
}
}
}
close(fd);
return 0;
}
回想题目其实挺简单,不过我当时真的做了好久……