PCIE的mmio内存映射访问机制

PCIe概述

PCI总线使用并行总线结构,采用单端并行信号,同一条总线上的所有设备共享总线带宽 
PCIe
总线使用高速差分总线,采用端到端连接方式,每一条PCIE链路只能连接两个设备

PCIe的端到端连接方式 
发送端和接收端都含有TX(发送逻辑),RX(接受逻辑) 



现在来说明什么是mmio 

mmio,memory map io内存映射访问机制,除了port I/O之外,另外一种访问方式就是mmio 
内存映射,简而言之就是将用户空间的一段内存区域映射到内核空间,映射成功后,用户对这段内存区域的修改可以直接反映到内核空间,同样,内核空间对这段区域的修改也直接反映用户空间。那么对于内核空间<—->用户空间两者之间需要大量数据传输等操作的话效率是非常高的。

这里就自然地提到一个函数,

mmap(linux环境) 

头文件 <sys/mman.h>

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 

“/dev/mem”物理內存全映像,可以用來訪問物理內存,一般是open("/dev/mem",O_RD_WR),然后mmap,接著就可以用mmap地址訪問物理內存(root权限)


这是PCIe物理内存地址!

遍历时只需要根据相应的offset偏移即可PCIe设备的配置空间!


关于PCIe设备配置空间的0x34位置的Capabilites Pointer,需要说一说

这是0x34h位置即Capability Pointer所代表的空间,也就是说Capability Pointer虽然听起来像一个指针,但是他只是一个8bit的数据,这里面存放了一个地址,而这个地址,就是我们要找的,

意义上Capability Pointer所指向的东西,我们来看看他究竟要指向哪里,就是这里喽!


capbility pointer里面存放的地址就是上图00h的地址喽,也就是上表的基地址,那么问题来了我们为什么要找这个表呢?在这个表中,00h位置0~7bitcapbility ID,如果他的值是10h,就表明这是个PCIe设备的cap structure,也就是说我们已经找到了PCIe设备啦,如果他不是10h怎么办?没关系,因为在00h7~15bit的地方还有next Cap pointer,跟Capbility structure原理类似,他也是个看起来像指针的字节,里面存放的就是下一个capbility structure的地址了,我们只需要根据这里的地址把基地址偏移过去就好了,直到我们找到next cap pointer0的时候,就代表他后面已经没有了,这时候我们就要跳出当前循环了



下面说明一下我们需要找到并打印出来的东西(Capbility structure)

1.Type02h4~7bit,根据这个位置,将基地址偏移即可!





2.Speed:0x2ch1~7bit,注意是1~7而不是0~7 





3.Link Speed:0x0ch0~3bit 





4.Link Width:0x0ch4~9bit,寄存器图同上0x0ch


<span style="font-family:Microsoft YaHei;font-size:14px;">#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<sys/mman.h> //mmap
#include<fcntl.h>   //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<MAX_BUS;++bus)
    {
        for(dev=0;dev<MAX_DEV;++dev)
        {
            for(fun=0;fun<MAX_FUN;++fun)
            {
                //addr=0;
               addr=BASE_ADDR|(bus<<20)|(dev<<15)|(fun<<12);//要寻找的偏移地址,根据PCIe的物理内存偏移
               ptrdata=mmap(NULL,LEN_SIZE,PROT_READ|PROT_WRITE,MAP_SHARED,fd,addr);//映射后返回的首地址
                //void*mmap(void* start,size_t length,int prot,int flags,int fd,off_t offset);
                //start映射區開始地址,設置為NULL時表示由系統決定
                //length映射區長度單位,地址自然是sizeof(unsigned long)
                //prot設置為PORT_READ|PORT_WRITE表示頁可以被讀寫
                //flag指定映射對象類型,MAP_SHARED表示與其他所有映射這個對象的所有進程共享映射空間
                //fd文件描述符
                //offset被映射對象內容的起點
 
                if(ptrdata==(void *)-1)
                {
                   munmap(ptrdata,LEN_SIZE);
                   break;
                }
                if(*ptrdata != 0xffffffff)
                {
                   nextpoint=(BYTE)(*(ptrdata+0x34/4));//capability pointer
                   ptrsearch=ptrdata + nextpoint/4;//the base address of capability structure
 
                   printf("next point:%x\n",nextpoint);
                   printf("ptrdata:%x\n",*ptrdata);
                   printf("search:%x\n",*ptrsearch);
 
                   while(1)//search for the pcie device
                   {
                       if((BYTE)(*ptrsearch)==0x10)//capability id of 10h indicating pcie capabilitystructure
                       {
                            printf("PCIE:");
                            printf("busnumber=%x,dev number=%x,function number=%x\n",bus,dev,fun);
                           printf("vender id:%x\t",(*ptrdata)&0x0000ffff);
                            printf("deviceid:%x\n",((*ptrdata)>>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;
}</span>

回想题目其实挺简单,不过我当时真的做了好久……

 

  • 12
    点赞
  • 58
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值