根据百度百科的解释,PCIE(peripheral component interconnect express)是一种高速串行计算机扩展总线标准,它原来的名称为“3GIO”,是由英特尔在2001年提出的,旨在替代旧的PCI,PCI-X和AGP总线标准。PCIe属于高速串行点对点双通道高带宽传输,所连接的设备分配独享通道带宽,不共享总线带宽,主要支持主动电源管理,错误报告,端对端的可靠性传输,热插拔以及服务质量(QOS)等功能。PCIe闪存卡的供应商包括:INTEL、IBM、LSI、OCZ、三星(计划中)、SanDisk、STEC、SuperTalent和东芝(计划中)等,而针对海量的数据增长使得用户对规模更大、可扩展性更强的系统所应用,PCIe 3.0技术的加入最新的LSI MegaRAID控制器及HBA产品的出色性能,就可以实现更大的系统设计灵活性。

查看系统中的PCIE设备

执行命令lspci命令,查看系统中的PCIE设备信息

可以看到,系统中有PCIE USB EHCI控制器,以及PCIE网卡,现在我们进一步用命令分析他们。命令格式是: sudo lspci -vvv -s #bdf,其中bdf是BUS,DEVICE,FUNCTION 的缩写,要了解它需要具备一些PCIE的基础知识,简单来说,挂载在PCIE总线上的PCIE设备尽管拓扑结构非常复杂,但是可以唯一的通过bus:device.function去定位,BUS很好理解,它代表的设备挂载的那条PCIE 总线ID,而一条BUS上可以挂载多个设备,通过device区分,对于每个device来说,可以具备多个function,默认的function 0都支持,可以类比一个USB设备可以支持多个配置,而默认的端点0的配置都是支持的。

话说回来,我们可以通过上述命令来针对某个设备DUMP更多的信息出来。

根据LSPCI的输出可以知道,网卡的BDF为02:00.0,我们通过截图中的命令,分析得到网卡设备的中断号为19,支持三个地址空间REGION,HOST端(CPU端)可以通过主机的MMAP函数将REGION中的存储区域映射到系统中进行访问,这样可以直接操纵版卡上的存储资源。另外根据输出信息,网卡支持MSI-X中断,MSI/MSI-X是基于消息传递的中断机制MSI-X中断允许网卡固件向BAR空间的一片RINGBUF写入16个字节的数据,触发MSI中断,通知HOST端进行响应,是一种设备端和主机端高效的通知机制。

在看一下PCIE USB控制器,它的BDF为00:14.0

USB控制器支持1个REGION,大小64K(很可能是EHCI寄存器空间,有待证实),中断号为127,同样支持MSI/MSI-X中断机制。

基本可以确定PCI USB Controller的EHCI寄存器空间既是对PCI USB Controller BAR0的映射。 如下图所示:

dmesg print

you can see the EHCI length 64k is exactly identical with the output,and so does the base address 0xa4100000,.

modify the code and print the iomapped EHCI registers. according the iommap funcdtion.

the iomapped address and its content is:

use the user space mmap bar0 to display the content

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <errno.h>// bdf:bus, device, function,bus number take 8bits, device number take 5bits, function number
// take 3bits,so, pcie RC support max 256 child buses,support 32 devices each buses, 8 functions each
// device. BUS0 is RC(root complex).void dump_memory(unsigned char *buf, int len)
{int i;for(i = 0; i < len; i ++){if(i % 16 == 0 )printf("%p:", buf + i);printf("0x%02x ", buf[i]);if(i % 16 == 15)printf("\n");}return;
}int main(int argc, char **argv)
{char *filename;struct stat statbuf;int bar=0;// bdf address, domain:bus:slot.funcfilename = "/sys/bus/pci/devices/0000:00:14.0/resource0";printf("open file %s.\n", filename);int fd =  open(filename, O_RDWR | O_SYNC);if(fd < 0){printf("%s line %d, fatal error, open file failure.\n", __func__, __LINE__);return -1;}int status = fstat(fd, &statbuf);if(status < 0){printf("%s line %d, status file failure.\n", __func__, __LINE__);close(fd);return -1;}printf("%s line %d, bar zone size %ld bytes, %ld Kbytes, %ld Mbytes, %ld Gbytes.\n", \__func__, __LINE__, statbuf.st_size, statbuf.st_size/1024, statbuf.st_size/1024/1024, statbuf.st_size/1024/1024/1024);unsigned char* maddr = (unsigned char *)mmap(NULL,(size_t)(statbuf.st_size),PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);if(maddr == (unsigned char *)MAP_FAILED){printf("%s line %d, failure for mmap bar err %s.\n", __func__, __LINE__, strerror(errno));close(fd);return -1;}printf("%s line %d, fw 0x%p.\n", __func__, __LINE__, maddr);filename = "/sys/bus/pci/devices/0000:00:14.0/config";int fdcfg = open(filename, O_RDWR | O_SYNC);if(fdcfg < 0){printf("%s line %d, fatal error, open file failure.\n", __func__, __LINE__);close(fd);return -1;}status = lseek(fdcfg, 0x10 + 4*bar, SEEK_SET);if(status < 0){printf("%s line %d, status file failure.\n", __func__, __LINE__);close(fd);close(fdcfg);return -1;}unsigned int phys;status = read(fdcfg, &phys, 4);if(status < 0){printf("%s line %d, status file failure.\n", __func__, __LINE__);close(fd);close(fdcfg);return -1;}printf("%s line %d phys 0x%x.\n", __func__, __LINE__, phys);int offset = ((phys & 0xFFFFFFF0) % 0x1000);unsigned char* addr = maddr + offset;printf("%s line %d, addr = %p.\n", __func__, __LINE__, addr);dump_memory(addr, 256);close(fd);close(fdcfg);return 0;
}

以上代码依据的是PCIE的配置空间分布

user space print, you can find it is very same with the upper kernel printk output.

compare allwinner sunxi usb ECHI controller register, you can sure that we above really get the acdtual EHCI Base address from bar space.

the hcd->regs value origin from usb_vbase.

the usb_vbase are initialize from the DEVICE TREE.

which define the EHCI Base

up is the pci driver register flow,but we know device and driver are couples in linux driver, so where is the device register?

in pci driver, the devie register function is pci_device_add.

the device register flow is;

pci_device_add

acpi_init

写代码MAP BAR空间:

下面代码将网卡设备的BAR4空间映射到系统,并且打印部分数据.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <errno.h>// bdf:bus, device, function,bus number take 8bits, device number take 5bits, function number
// take 3bits,so, pcie RC support max 256 child buses,support 32 devices each buses, 8 functions each
// device. BUS0 is RC(root complex).void dump_memory(unsigned char *buf, int len)
{int i;for(i = 0; i < len; i ++){if(i % 16 == 0 )printf("%p:", buf + i);printf("0x%02x ", buf[i]);if(i % 16 == 15)printf("\n");}return;
}int main(int argc, char **argv)
{char filename[256];struct stat statbuf;int domain = 0;if(argc != 5){printf("%s line %d, the command use like this: ./program bus slot function bar.\n", __func__, __LINE__);return -1;}int bus  = atoi(argv[1]);int slot = atoi(argv[2]);int func = atoi(argv[3]);int bar  = atoi(argv[4]);memset(filename, 0x00, 256);// bdf address, domain:bus:slot.funcsnprintf(filename, 99, "/sys/bus/pci/devices/%04x:%02x:%02x.%1x/resource%d", domain, bus, slot, func, bar);printf("open file %s.\n", filename);int fd =  open(filename, O_RDWR | O_SYNC);if(fd < 0){printf("%s line %d, fatal error, open file failure.\n", __func__, __LINE__);return -1;}int status = fstat(fd, &statbuf);if(status < 0){printf("%s line %d, status file failure.\n", __func__, __LINE__);close(fd);return -1;}printf("%s line %d, bar zone size %ld bytes, %ld Kbytes, %ld Mbytes, %ld Gbytes.\n", \__func__, __LINE__, statbuf.st_size, statbuf.st_size/1024, statbuf.st_size/1024/1024, statbuf.st_size/1024/1024/1024);unsigned char* maddr = (unsigned char *)mmap(NULL,(size_t)(statbuf.st_size),PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);if(maddr == (unsigned char *)MAP_FAILED){printf("%s line %d, failure for mmap bar err %s.\n", __func__, __LINE__, strerror(errno));close(fd);return -1;}printf("%s line %d, fw 0x%p.\n", __func__, __LINE__, maddr);memset(filename, 0x00, 256);snprintf(filename, 99, "/sys/bus/pci/devices/%04x:%02x:%02x.%1x/config", domain, bus, slot, func);int fdcfg = open(filename, O_RDWR | O_SYNC);if(fdcfg < 0){printf("%s line %d, fatal error, open file failure.\n", __func__, __LINE__);close(fd);return -1;}status = lseek(fdcfg, 0x10 + 4*bar, SEEK_SET);if(status < 0){printf("%s line %d, status file failure.\n", __func__, __LINE__);close(fd);close(fdcfg);return -1;}unsigned int phys;status = read(fdcfg, &phys, 4);if(status < 0){printf("%s line %d, status file failure.\n", __func__, __LINE__);close(fd);close(fdcfg);return -1;}printf("%s line %d phys 0x%x.\n", __func__, __LINE__, phys);int offset = ((phys & 0xFFFFFFF0) % 0x1000);unsigned char* addr = maddr + offset;printf("%s line %d, addr = %p.\n", __func__, __LINE__, addr);dump_memory(addr, 256);close(fd);close(fdcfg);return 0;
}

执行结果,可以看到正确的读出了BAR4空间的内存。

关于BAR空间映射:

代码中对BAR的映射基于resource节点

/sys/bus/pci/devices/%04x:%02x:%02x.%1x/resource%

resource节点在内核代码中的创建是在如下位置pci_create_attr:

发起调用的地方在sysfs_kf_bin_mmap:

map调用路径为pci_mmap_resource:

可以看到,对BAR空间的映射也是基于通用的IOMAP函数。

configuration

in pci device system directory including many different files:

config is a binary files, you can read the orignal configuration from this file. vendor, device, subsystem_device, subsystem_vendor, and class are all represents the specify value of pci device.

you also can get he IRQ NO from the the irq file.

install PCIE工具

sudo apt install pciutils-dev

PCIE的复位等级


参考资料

usb控制器和usb port之间有什么联系-usbview工具的使用?_papaofdoudou的博客-CSDN博客

带你了解PCIE通信原理_迪捷软件的博客-CSDN博客_pcie通信


结束

PCIE操作基础原理相关推荐

  1. datagrid出现相同两组数据_stata 数据操作基础知识:以一篇论文数据操作为例

    stata 数据操作基础知识:以一篇论文数据操作为例 上节回顾及问题 统计学学习大图景 数据描述 分位数回归 存在的问题: 1.学了就要多使用,哪怕生搬硬套也要多用 2.时间序列的方法,大家可以操作, ...

  2. java 编程原理_Java网络编程 -- 网络编程基础原理

    Hello,今天记录下 Java网络编程 --> 网络编程基础原理. 一起学习,一起进步.继续沉淀,慢慢强大.希望这文章对您有帮助.若有写的不好的地方,欢迎评论给建议哈! 初写博客不久,我是杨展 ...

  3. 嵌入式操作系统内核原理和开发

    嵌入式操作系统内核原理和开发(开篇) 操作系统是很多人每天必须打交道的东西,因为在你打开电脑的一刹那,随着bios自检结束,你的windows系统已经开始运行了.如果问大家操作系统是什么?可能有的人会 ...

  4. Macaca基础原理解析

    导语 前面几篇文章介绍了在Macaca实践中的一些实用技巧与解决方案,今天简单分析一下Macaca的基础原理.这篇文章将以前面所分享的UI自动化Macaca-Java版实践心得中的demo为基础,进行 ...

  5. 云小课|MRS基础原理之ClickHouse组件介绍

    阅识风云是华为云信息大咖,擅长将复杂信息多元化呈现,其出品的一张图(云图说).深入浅出的博文(云小课)或短视频(云视厅)总有一款能让您快速上手华为云.更多精彩内容请单击此处. 摘要:在2016年开源的 ...

  6. 嵌入式操作系统内核原理和开发(总结篇)

    [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 很多朋友都喜欢嵌入式操作系统的内容,但是如何实现和仿真这样一个系统一直是困扰我们的难题.现在郑 ...

  7. LabVIEW FPGA PCIe开发讲解-7.1节:FPGA PCIe/PXIe基础知识和概念概述

    1.提到PCIe总线通信,相信很多接触过PCIe或PXIe板卡的用户估计都有所了解过,相对于传统的串口.USB和千兆以太网通信协议,PCIe协议本身可以实现更高数量级的总线通信带宽,比如目前Xilin ...

  8. SQL注入基础原理与案例(详细总结)

    SQL注入基础原理与案例 一.前言 二.漏洞概述及危害 1.漏洞概述 2.漏洞危害 3.漏洞防范 三.SQL注入 1.SQL注入方式 (1)信息收集 (2)数据注入 (3)高权限注入 2.判断是否存在 ...

  9. python3网络爬虫笔记-爬虫基础原理

    本笔记是学习崔庆才老师的网络爬虫课程的总结 一.HTTP基础原理 1. URI.URL.URN URI: Uniform Resource Identifier,即统一资源标志符 URL:Univer ...

最新文章

  1. 2021年春季学期-信号与系统-第七次作业参考答案-第五小题
  2. C++_pthread read-write lock_读写锁_visual studio 2015下配置
  3. Asp.Net Core中的静态文件-12
  4. centos php 显示错误提示,Centos下编译php的典型错误及解决
  5. SVN 提交操作缩写(A D M R)
  6. 静态内容负载均衡的具体实现-续《几百元搞定大型网站》
  7. c语言宏代码大全,C语言宏
  8. php使用ffmpeg转录网络直播流,使用FFmpeg转录网络直播流
  9. Roller的安装步骤
  10. 转:MediaCoder H.264格式编码参数设置及详解
  11. java 二维向量_二维向量的叉积是标量还是向量?
  12. 小程序 自定义气泡框
  13. ZK锦集:Zookeeper的下载和安装 | 真/伪集群的快速搭建| 总结的很详细
  14. iOS和Android的APP启动图标和应用商店截图尺寸
  15. 《流浪地球》反响强烈,车联网现状又该如何发展?
  16. Ubuntu(debian)问题解决方案合集
  17. javaweb简化的医院管理系统
  18. 产品经理的思维模型大全(建议收藏)
  19. BP神经网络学习笔记
  20. Task01:数据载入及初步观察

热门文章

  1. 无线射频专题《射频信号,链路预算与衰落容限》
  2. CSS3 3D转换和旋转木马案例
  3. WPS2017 电子表格/Excel文件保护密码忘记了?
  4. devops包括什么_名字叫什么? DevOps版。
  5. Windows 10 IDM 下载play.kth.se上面的网课视频
  6. EVE:[globbing] unmatched close brace/bracket in column 6
  7. shell脚本运行报错: syntax error: unmatched ‘while‘
  8. 清理win10不常用服务
  9. 心理正常与异常的区分_正常心理与异常心理的判别标准
  10. 【渝粤题库】陕西师范大学900013 心身疾病防治与心理健康