转载地址:http://blog.csdn.net/jiangwei0512/article/details/51603525

PCI/PCIe设备有自己的独立地址空间,这部分空间会映射到整个系统的地址空间。

映射地址在BIOS/UEFI下指定(如果有的话,对于使用非BIOS启动的OS,不清楚),它有两种类型,一种是MMIO,一种是IO。对于MMIO的访问,跟访问内存的方式一样,它从称为PCIEXBAR的基地址开始,有很大的一段空间,这个PCIEXBAR的值根据不同的平台可能不同,大致可能值有0xC0000000、0xE0000000等,关于这个值是怎么使用的后面的章节会讲到;对于IO,它是一种比较老的访问PCI/PCIe设备的方式,而且占有的空间相比MMIO非常小,好像只有64K的空间。

PCI/PCIe设备使用的空间也有两个部分,一部分称为配置空间(通过MMIO);另一部分通过配置空间的BAR寄存器指定,是设备实现功能所需要用到的地址空间(有MMIO也有IO, 不过IO用的比较少了)。

PCI/PCIe配置空间的访问方式

PCI/PCIe设备的配置空间通过PCIEXBAR加上设备的Bus、Device、Fun号的转换来得到,BDF到地址的转换关系如下:

/**
Macro that converts PCI Bus, PCI Device, PCI Function and PCI Register to an
address that can be passed to the PCI Library functions. @param Bus PCI Bus number. Range 0..255.
@param Device PCI Device number. Range 0..31.
@param Function PCI Function number. Range 0..7.
@param Register PCI Register number. Range 0..255 for PCI. Range 0..4095
for PCI Express. @return The encoded PCI address. **/
#define PCI_LIB_ADDRESS(Bus,Device,Function,Register) \
(((Register) & 0xfff) | (((Function) & 0x07) << ) | (((Device) & 0x1f) << ) | (((Bus) & 0xff) << ))

其中的Register是具体要访问的寄存器。

这是最常用的一种方式,通过将B/D/F转换成MMIO的地址,之后就可以通过MMIO的方式来访问,下面是一个例子:

UINT8
EFIAPI
PciExpressRead8 (
IN UINTN Address
)
{
ASSERT_INVALID_PCI_ADDRESS (Address);
return MmioRead8 ((UINTN) GetPciExpressBaseAddress () + Address);
}

个问题,通过PCI_LIB_ADDRESS得到的并不是实际的系统地址空间,它算是一个偏移,还需要加上一个基地址(就是这个通过函数GetPciExpressBaseAddress()得到的)。在UEFI中这个基地址被设置成一个PCD变量:PcdPciExpressBaseAddress。它的值根据不同平台可能会不同。

不过重点不是它的值,重点是如何设置这个值,因为只有设置了这个值才能使用上面说的方式来读写PCI/PCIe配置空间。

而PCIEXBAR也是要写到PCI设备的配置空间中的,它会被写到B0/D0/F0/R060h这个寄存器(不同平台可能不同)。

这里就遇到了一个问题,该通过什么方式来写这个值呢?

实际上,需要注意几点:

1. 上述提供的访问PCI/PCIe配置空间的方式是PCIe的方式;

2. 早期在没有PCIe的时候,要访问配置空间时,使用的是两个IO端口,CFCh和CF8h,通过往一个端口指定寄存器,另一个端口写值的方式为指定寄存器赋值。

所以我们要注意,有两个配置空间的方式:

1. 传统方式,写IO端口CFCh和CF8h。只能访问PCI/PCIe设备的开始256个字节(因为PCI设备的配置空间本来就只有256个字节);

2. PCIe的方式,就是上面提到的方式,它可以方位4K个字节的配置空间。

PCI配置空间

由于PCI/PCIe设备分为Bridge和Agent两种,所以配置空间也有两种类型:

其中Agent的配置空间类型称为Type 00h:

简单介绍其中的几个寄存器的意义:

Vendor ID,Device ID:标记了一个设备的生产厂商和具体的设备,比如Intel的设备Vendor ID通常是0x8086,Device ID就需要厂家自定义了,总之能够识别到具体是哪个设备就可以了。

Status:设备状态字,具体每个BIT的意义见下图:

Command:设备状态字:

Base Address Registers:决定PCI/PCIe设备空间映射到系统空间具体位置的寄存器,映射方式有两种,分别是IO和Memory映射:

处理器系统资源分为IO资源和MMIO资源两种,因此PCI/PCIe空间地址对应也有两种。

下面是Bridge的配置空间,它的类型被称为Type 01h:

Type 01h中也有Vendor ID,Device ID,Status,Command等寄存器。

另外需要注意的是这里的BAR计算得到的系统空间是该桥下挂的所有设备的系统空间的总和。

另外Subordinate Bus Number、Secondary Bus Number和Primary Bus Number,这些寄存器共同确定了该桥上行和下行的所有Bus号。

PCIe配置空间

PCIe是在PCI基础上发展的协议,PCIe也有上述的PCI配置空间,并且在此基础之上进行了扩展,其扩展形式是通过一种称为Capability的寄存器块来完成的。

PCI配置空间的大小是256个字节,即0x00~0xFF,而PCIe的配置空间扩大到了0x00~0xFFF,下图是具体的布局。

在原来的配置空间中,有一个寄存器指定了第一个Capability的位置,而第一个Capability又指定下一个Capability,构成了一串Capability。

具体的Capability表示什么,需要根据不同的设备来确定,再次不多做介绍。

其它说明

处理器系统中会为所有的PCI/PCIe设备留足足够的空间,但是几乎没有系统会满配,所以很多的配置空间实际上是空的,此时如果去访问,就会得到全FF,表示设备不存在。

下面是Linux下访问PCI/PCIe配置空间的一个例子:

注:以上是一个Intel网卡的PCI/PCIe配置空间,这是虚拟机下的结果,真实机器上可能有所不同。

[转载]PCI/PCIe基础——配置空间的更多相关文章

  1. 2.3 PCI桥与PCI设备的配置空间

    PCI设备都有独立的配置空间,HOST主桥通过配置读写总线事务访问这段空间.PCI总线规定了三种类型的PCI配置空间,分别是PCI Agent设备使用的配置空间,PCI桥使用的配置空间和Cardbus ...

  2. 如何访问pcie整个4k的配置空间

    目前用于访问PCIe配置空间寄存器的方法需要追溯到原始的PCI规范.为了发起PCI总线配置周期,Intel实现的PCI规范使用IO空间的CF8h和CFCh来分别作为索引和数据寄存器,这种方法可以访问所 ...

  3. 怎样訪问pcie整个4k的配置空间

    眼下用于訪问PCIe配置空间寄存器的方法须要追溯到原始的PCI规范. 为了发起PCI总线配置周期,Intel实现的PCI规范使用IO空间的CF8h和CFCh来分别作为索引和数据寄存器,这样的方法能够訪 ...

  4. PCIe设备的配置空间

    关于PCI设备的配置空间网上已经有很多资料了,如下图就是PCI设备必须支持的64个字节的配置空间,范围为0x00-0x3f. 很多PCI设备仅仅支持者64字节的配置空间.PCI和PCIe配置空间的区别 ...

  5. 【PCIE-2】---PCIE配置空间及访问方式简介

    对新手来说,第一步了解PCIE的相关基本概念,第二步了解PCIE配置空间,第三步深入研究PCIE设备枚举方式.本章主要总结第二步的PCIE配置空间 按照国际惯例,先提问题: 1. 什么是PCIE的配置 ...

  6. 2.4 PCI总线的配置

    PCI总线定义了两类配置请求,一个是Type 00h配置请求,另一个是Type 01h配置请求.PCI总线使用这些配置请求访问PCI总线树上的设备配置空间,包括PCI桥和PCI Agent设备的配置空 ...

  7. PCI、PCIE配置空间的訪问(MCFG,Bus,Device,Funtion)

    一般来说,在x86平台上,有两大类方式能够訪问这一区间的寄存器,   1,配置机制1#或者配置机制2#   訪问时借助in/out指令.请注意,这样的方式有别于一般的in/out指令訪问PCI的IO空 ...

  8. Linux PCI/PCI-E设备配置空间读取与修改

    Linux PCI/PCI-E设备配置空间读取与修改 1 前言 PCI和PCI Express,是计算机常使用的一种高速总线.操作系统中的PCI/PCI-E设备驱动以及操作系统内核,都需要访问PCI及 ...

  9. PCI配置空间简介

    一.PCI配置空间简介 PCI有三个相互独立的物理地址空间:设备存储器地址空间.I/O地址空间和配置空间.配置空间是PCI所特有的一个物理空间.由于PCI支持设备即插即用,所以PCI设备不占用固定的内 ...

随机推荐

  1. body-parser小解

    body-parser用来解析http请求体,对不同的content-type有不同的处理方式, 首先介绍一下常见的四种Content-Type: 1.application/x-www-form-u ...

  2. 恢复性训练day1

    DP: 0/1背包一个常见的错误是没有cmax(f[i][j],f[i-1][j]) 0/1背包的拓展中有转移式的变形,以及无限数量背包,分组背包等. 可化为背包问题的一般不会太难. 数组开小,出现大 ...

  3. 用nodejs实现读取文件操作

    //如果不是全局就得引入fs成员 const fs = require("fs"); //fs 核心模块中提供了一个 fs.readFile方法,来读取指定目录下的文件 //fs. ...

  4. Bootstrap3全局CSS样式

    目录 1. 概览 2. 栅栏系统 3. 文本 4. 列表 5. 代码 6. 表格 7. 表单 7.1 基本实例 7.2 内联表单 7.3 水平排列的表单 8. 按钮 9. 图片 10. 辅助类 10. ...

  5. mongod无法启动

    今天遇到了一个奇葩问题,我在Linux系统里备份了数据库,结果不知道为什么,系统用不了了,后来经过同事的检查,发现原来是我的硬盘快满了,导致mongod数据无法启动,真是.......

  6. 考勤助手——基于CS三层结构的子系统设计

    因为小组比较倾向于cs分层结构的风格,所以基于对考勤助手最初的体系架构的设计进行了子系统的分层设计,如下图: 1.教务老师安排课程子系统 2.教务老师查询相关信息的子系统 3.任课教师管理考勤子系统 ...

  7. DataX-HDFS(读写)

    DataX操作HDFS 读取HDFS 1 快速介绍 HdfsReader提供了读取分布式文件系统数据存储的能力.在底层实现上,HdfsReader获取分布式文件系统上文件的数据,并转换为DataX传输 ...

  8. CodeForces 266E More Queries to Array...(线段树+式子展开)

    开始觉得是规律题的,自以为是的推了一个规律,结果测试数据都没过....看了love神的博客才发现只是把式子展开就找到规律了.不过挺6的是我虽然想错了,但是维护的的东西没有错,只是改改(改了进两个小时好 ...

  9. QT中phonon的安装和使用

    http://write.blog.csdn.net/postedit Phonon严格来说其实非为Qt的library,Phonon原本就是KDE 4的开放原始码多媒体API,後来与Qt合并与开发, ...

  10. ZC_知识点

    1. 在创建一个JNI动态库的工程时应该将工程的输出目标设置为动态连接库(Windows下为.dll,Unix-like系统下为.so,OS X下为.dylib) 2.类型对应关系 (Java与C/C ...