当前位置: 首页 > news >正文

PCIE操作基础原理

根据百度百科的解释,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-X中断允许网卡固件向BAR空间的一片RINGBUF写入16个字节的数据,触发MSI中断,通知HOST端进行响应,是一种设备端和主机端高效的通知机制。

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

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

手写代码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.func
	snprintf(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函数。

参考资料

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


结束

相关文章:

  • Windows系统SVG图片预览插件
  • 2022.10.1模拟赛
  • 西瓜书研读——第三章 线性模型: 线性判别分析 LDA
  • 云计算概论 --云安全机制
  • java计算机毕业设计企业公开招聘系统源程序+mysql+系统+lw文档+远程调试
  • 谷粒学院16万字笔记+1600张配图(十五)——微信扫码登录
  • 详述进程概念【Linux】
  • VVC系列(一)VTM下载编译
  • LeetCode50天刷题计划第二季(Day 7 — 验证二叉搜索树(15.00-16.00
  • 在 IDEA 中用 Nacos2.1.0 源码启动集群模式并调试
  • 前端毕业设计:Nodejs+Vue菜鸟驿站仓库管理系统的设计与实现
  • 服务器的基本概念与初识Ajax,jQuery当中的ajax,get(),post()接口,postman测试接口
  • Java基于SpringBoot+Vue+nodejs的企业公司人事管理系统 Element
  • webpack5构建基于Vue3+ElementPlus项目搭建(开发和生产)
  • 6. 测度论-期望及其性质
  • 【跃迁之路】【463天】刻意练习系列222(2018.05.14)
  • Android路由框架AnnoRouter:使用Java接口来定义路由跳转
  • const let
  • es6(二):字符串的扩展
  • iOS高仿微信项目、阴影圆角渐变色效果、卡片动画、波浪动画、路由框架等源码...
  • IOS评论框不贴底(ios12新bug)
  • LintCode 31. partitionArray 数组划分
  • October CMS - 快速入门 9 Images And Galleries
  • Python_网络编程
  • SpiderData 2019年2月23日 DApp数据排行榜
  • 浮动相关
  • - 概述 - 《设计模式(极简c++版)》
  • 如何设计一个微型分布式架构?
  • 译有关态射的一切
  • 用 Swift 编写面向协议的视图
  • 终端用户监控:真实用户监控还是模拟监控?
  • 如何通过报表单元格右键控制报表跳转到不同链接地址 ...
  • ​Java并发新构件之Exchanger
  • #我与Java虚拟机的故事#连载06:收获颇多的经典之作
  • $.extend({},旧的,新的);合并对象,后面的覆盖前面的
  • (arch)linux 转换文件编码格式
  • (学习日记)2024.03.25:UCOSIII第二十二节:系统启动流程详解
  • (转)GCC在C语言中内嵌汇编 asm __volatile__
  • (转)mysql使用Navicat 导出和导入数据库
  • (转)Sql Server 保留几位小数的两种做法
  • (转载)从 Java 代码到 Java 堆
  • (轉貼) VS2005 快捷键 (初級) (.NET) (Visual Studio)
  • .chm格式文件如何阅读
  • .Net IE10 _doPostBack 未定义
  • .NET MAUI学习笔记——2.构建第一个程序_初级篇
  • .net wcf memory gates checking failed
  • .NET/C# 中设置当发生某个特定异常时进入断点(不借助 Visual Studio 的纯代码实现)
  • .Net7 环境安装配置
  • .NET高级面试指南专题十一【 设计模式介绍,为什么要用设计模式】
  • .Net语言中的StringBuilder:入门到精通
  • .sh 的运行
  • @JoinTable会自动删除关联表的数据
  • @Transient注解
  • @vue/cli脚手架
  • [Android Pro] android 混淆文件project.properties和proguard-project.txt