PCIE的mmio内存映射访问机制

PCIe概述

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

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

PCIE的mmio内存映射访问机制_第1张图片


现在来说明什么是mmio 

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

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

mmap(linux环境) 

头文件

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物理内存地址!

PCIE的mmio内存映射访问机制_第2张图片

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

PCIE的mmio内存映射访问机制_第3张图片

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

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

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

PCIE的mmio内存映射访问机制_第4张图片

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,根据这个位置,将基地址偏移即可!

PCIE的mmio内存映射访问机制_第5张图片

PCIE的mmio内存映射访问机制_第6张图片



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

PCIE的mmio内存映射访问机制_第7张图片

PCIE的mmio内存映射访问机制_第8张图片



3.Link Speed:0x0ch0~3bit 

PCIE的mmio内存映射访问机制_第9张图片

PCIE的mmio内存映射访问机制_第10张图片



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

PCIE的mmio内存映射访问机制_第11张图片

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

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

 

你可能感兴趣的:(BIOS)