【RDMA】RDMA 学习资料总目录_bandaoyu的博客-CSDN博客SavirRDMA 分享1. RDMA概述https://blog.csdn.net/bandaoyu/article/details/112859853https://zhuanlan.zhihu.com/p/1388747382. 比较基于Socket与RDMA的通信https://blog.csdn.net/bandaoyu/article/details/1128613993. RDMA基本元素和编程基础https://blog.csdn.net/bandaoyu/article/de.

https://blog.csdn.net/bandaoyu/article/details/120485737

转自:https://zhuanlan.zhihu.com/p/463199854作者:Savir

本文欢迎非商业转载,转载请注明出处。

RDMA技术实现的是对远程内存的直接读写,整个体系都是围绕着内存访问和管理所搭建的。以前有一些读者在评论区留言或者私信问我一些关于内存的问题,相信很多刚入行的朋友也跟曾经的我一样被各种地址概念搞的焦头烂额。所以我就在这篇文章中讲解和澄清一些关于内存地址的基础知识,作为RDMA内存管理系列文章的“开胃菜”,扫除大家阅读后续文章的障碍。

本文是“Memory Region”和“Memory Window”等的前置文章,不需要任何RDMA背景,主要目的是科普基础知识,不做比较深入的探讨。内容如有错误之处欢迎大家在评论区指出。

硬件架构

我们先来看一下常见的服务器架构中几个硬件组件之间的关系,下图中的CPU通过总线和内存、以及PCIe RC(Root Complex)相连接,PCIe RC通过PCIe总线直接连接了GPU和PCIe Switch,Switch又连接了多个外设:

一种典型的服务器架构

简单介绍下各个组件:

CPU

CPU不用解释,需要注意图中的CPU内部集成了内存控制器Memory Controller,内存控制器主要负责处理CPU核发出的内存访问请求,对内存进行读写。

PCIe RC

全称为Root Complex,它是PCIe总线树状结构的“根”节点,主要负责处理CPU对PCIe设备的控制请求、完成地址转换等工作。

系统总线

CPU、内存控制器和PCIe RC是由高速总线连接到一起的,一般称这个总线为系统总线。

请注意它们三者的关系也不一定跟上图完全一样。PCIe规范没有对RC具体怎么实现做出规定,因此RC的概念比较模糊。有的芯片架构中,PCIe RC被集成到了CPU内部,而且内存控制器也可以被划分到PCIe RC中。

PCIe Switch

虽然PCIe RC上面可以直接连接终端设备(PCIe中称为EP,End Point),但是数量是有限的。所以一般情况下只有GPU直接连接到PCIe RC上,其他的外设通过PCIe Switch进行连接。PCIe Switch跟网络中的交换机的作用差不多,下面也可以增加更多层级,从而连接更多的PCIe EP到CPU上。

NIC

Network Interface Controller,网络接口控制器,也就是我们常说的网卡,插上网线并进行配置之后就可以接入网络了。

HCA(RNIC)

它就是我们关注的重点,即支持RDMA技术的网卡。在Infiniband/RoCE规范中,将RDMA网卡称为HCA,全称为Host Channel Adapter,即主机通道适配器;而在iWARP协议族中,将RDMA网卡称为RNIC,全称为RDMA enabled Network Interface Controller,即支持RDMA的网络接口控制器。

PCIe总线上可能会连接可种各样的设备,这里我们只列出了NIC和HCA。

地址

既然RDMA技术的核心是内存,自然离不开如何对内存进行寻址、也就是如何访问的问题。RDMA技术中的内存既要供软件(或者说CPU)访问,也要供网卡访问(HCA/RNIC),这其中涉及多种地址,我们将在本节中讲解。

物理地址

内存中的数据是按照字节连续排布的,每个字节都可以有一个索引,这个索引就是内存的地址。

内存地址

如果我们的CPU想要访问内存,最朴素的想法就是CPU直接指定一个内存的地址就可以了,这个地址就是物理地址,即Physical Address,简称PA。

CPU通过物理地址访问内存

虚拟地址

直接使用物理地址虽然方便,但是在操作系统上直接用物理地址访问内存产生了一些问题,比如:

  1. 地址之间不隔离:难以避免一个程序恶意写入另一个程序所使用的内存。
  2. 内存容易不够用:当同时运行的程序比较多时,内存很容易就不够用了。
  3. 内存使用效率低:即使当一个程序执行完毕后释放了自己的内存,它留下的“内存空洞”不太可能完全匹配另一个程序所需要的内存大小,可能会产生一些难以利用的“内存碎片”

后来,人们设计出了虚拟地址来解决这些问题。虚拟地址和物理地址之间经过了一层转换,软件或者说CPU通过虚拟地址来访问内存,并不能看到真实的地址,而在中间起到转换作用的是一个专用的模块——MMU(Memory Management Unit)。

当CPU发起对一个虚拟地址的访问时,MMU会去查询页表,将虚拟地址转换为物理地址,这个过程如下图所示:

CPU通过虚拟地址访问内存

一般情况下MMU都是被集成在CPU内部的,所以以后的图中我们会把MMU放到CPU中。

页表本身也储存在内存当中,每个进程都有一份,也就是每个进程都有一份虚拟-物理地址的映射关系。当不同的进程访问相同的地址时,最终对应的内存的物理地址是不同的。

进程初始化的时候,页表的基地址会被储存在特殊的寄存器中,这个基地址是物理地址还是虚拟地址?——自然是物理地址,要不然CPU怎么在没有页表的情况下找到页表的基地址呢?

逻辑地址与线性地址

在Linux操作系统中,它们与虚拟地址相等。这两个概念属于历史产物,目前已经很少涉及。我们就不介绍了,如果读者感兴趣的话可以阅读参考链接[2]。

现在我们介绍完了CPU访问内存的方式,在上述模型中加入RDMA网卡等外设之前,我们先来介绍一下地址空间的概念。

地址空间

所有能够被索引的地址,就构成了一个地址空间。所以我们可以说,所有CPU能够访问的虚拟地址构成了虚拟地址空间,所有物理地址构成了物理地址空间。对于一个64位的操作系统来说,理论上CPU最大能够访问0~2^64 Bytes的地址空间,但是目前一般是只实现48位,也就是能够访问2^48=256TB的空间。

需要注意的是,地址空间里并不是所有地址都会映射到内存。比如物理地址空间中,有一部分地址会映射给BIOS,有一部分会映射给PCIe设备。BIOS大家应该都知道,就是硬件上电之后先执行的一小段程序,负责对包括内存在内的一些硬件进行初始化,之后会引导操作系统启动;而映射给PCIe设备指的是什么呢?

MMIO

Memory mapping Input/Output,是PCIe规范设计的一种机制。前文中说的把一部分物理地址映射给PCIe设备,指的就是当CPU发起对MMIO地址的读写操作时,会被PCIe控制器接管,然后转化为对PCIe总线上连接的设备的访问请求。而最终转化对设备寄存器的读写,还是对设备内部存储空间的读写,是由设备注册时的配置决定的。

总线地址

CPU访问MMIO空间之后经过PCIe RC转化的地址,就是(PCIe)总线地址。外设也可以通过PCIe总线地址访问其他挂在PCIe总线上的设备,所有这些总线地址构成了总线地址空间。

CPU要访问总线地址空间中的地址,是需要PCIe RC将物理地址转换为总线地址的,画图来表示就是:

CPU通过虚拟地址访问寄存器的总线地址


CPU访问总线地址空间的问题介绍完了,那么外设如何访问内存呢?

有些设备不具备直接访问内存的能力,这个时候就需要CPU来帮助实现。下图中的例子中,如果想要把内存中的数据写入硬件内部的存储空间,需要CPU先把内存中的数据读入寄存器,再写入硬件。

在没有DMA的情况下外设访问内存

但是毕竟CPU的主要功能是计算,不能总让它做这种搬运数据的苦力活。所以后来诞生了DMA(Direct Memory Access),即直接存储器访问。DMA是一个数据搬运工,硬件可以通过它读写内存,DMA一般会被集成到设备当中。

在有DMA的情况下外设访问内存

外设发出DMA访存请求时,会在PCIe总线上发出总线地址,而一般情况下这个总线地址的值等于物理地址,我们可以认为外设发出的就是物理地址。这个请求被PCIe RC收到之后,它会通过系统总线来访问内存。

外设通过物理地址访问内存

IO虚拟地址

外设虽然可以通过物理地址直接访问内存,但是也产生了跟CPU通过物理地址访存类似的问题,其中对于外设最重要的一点便是:有些设备可能会需要大量地址连续的物理内存,比如HCA/RNIC就会耗费许多内存来放置软硬件进行交互的队列,以及队列的属性等等。

虽然可以通过自己设计多级寻址的方式来解决这个问题,但是这大大增加了软硬件的复杂度。那么能不能把MMU的设计思想也用在外设上呢?当然可以,于是就产生了IOMMU(x86平台)/SMMU(ARM平台)这种专门用于给外设进行地址翻译的设备。

有了IOMMU/SMMU之后,外设跟使用MMU的CPU一样,看到的是一整片连续的虚拟地址。区别于CPU的VA,我们称这些地址为IO虚拟地址,即IOVA(Input/Output Virtual Address)。

IOMMU/SMMU记录着地址的转换关系,外设发出的IOVA,会被它翻译为PA,根据SMMU/IOMMU的位置不同,可能有两种情况:它有可能在设备内,也有可能挂在PCIe总线上,为多个EP提供地址翻译功能,这两种情况分别如下:

外设通过IOVA访问内存(1)

外设通过IOVA访问内存(2)

大家可能对IOVA和Bus Address的关系表示困惑,这两个地址可以认为是相等的。概念的差别在于,当我们强调SMMU/IOMMU的输入时,也就是被转换前的地址时,一般将地址称为IOVA;而当我们强调在总线上的地址时,比如PCIe,我们一般将使用的地址称为Bus Address。不必纠结它们的关系,我们RDMA领域更常使用IOVA的概念。

DMA地址

外设(PCIe EP)通过DMA访问内存时,发出的地址就是DMA地址。结合上面的描述我们可以知道,当设备使用了IOMMU/SMMU时,DMA地址是IO虚拟地址IOVA。当未使用IOMMU/SMMU时,DMA地址是物理地址PA。

总结

我们结合Linux系统中DMA API HOWTO[3]文档中的图以及实际流程来总结一下本文的内容。请注意如果外设使用PCIe总线的话,图中的B转为A时的host bridge是PCIe RC的一部分;而在相反的方向上,无论是否使用IOMMU,Z到Y之间的转换都需要经过PCIe RC,只不过一般情况下PCIe是不对外设访问的物理地址做地址转换的。

地址空间之间的关系

现在假设我们的RDMA网卡需要一片IOVA连续的内存用于记录某个连接的状态,运行在CPU侧的驱动程序是如何申请内存,并且将内存的DMA地址告知网卡的呢?

一般情况下,网卡会使用下面的接口申请DMA Buffer:

cpu_virt_addr = dma_alloc_coherent(dev, size, &dma_addr, gfp);

其中dev是设备的指针,size是申请内存的大小。dma_addr是硬件访问这片内存所需要提供的DMA地址,gfp用于属性控制,我们目前不关心。而返回值cpu_virt_addr则是CPU访问这片内存所需要使用的虚拟地址。

调用接口之后我们获得的dma_addr就是上图中总线地址空间上的IO虚拟地址Z,返回的cpu_virt_addr对应上图中CPU虚拟地址空间中的虚拟地址X,这两个地址分别会在使用时由IOMMU/SMMU和MMU进行转换,转换的结果都是物理地址空间中的物理地址Y。

但是到目前为止,硬件还没有拿到这个dma_addr,所以还是要以某种方式告知硬件,这就用到了我们上面提到的MMIO。

外设在PCIe总线上注册时,会将一些寄存器配置到MMIO空间,然后驱动程序在初始化时,会将物理地址空间中的MMIO映射到虚拟地址空闲中。这样当驱动程序申请到表项的DMA地址之后,就可以把这个地址写入到初始化时映射的对应的寄存器上了,此外也会把内存区域的大小也通过寄存器告知硬件。如此一来,硬件就拿到了表项的地址信息,可以在需要的时候自行通过DMA访问这些内存了。

对应上图,某个总线地址是A的用于储存表项基地址的寄存器被配置到了MMIO空间,对应的物理地址是B,然后驱动将MMIO空间映射到CPU虚拟地址空间后,B对应的虚拟地址是C。CPU想把表项基地址告知硬件的时候,只需要将DMA地址写入虚拟地址C中就可以了,后面的工作将由MMU和PCIe RC完成。

好了,关于地址的基础知识我们就介绍到这里,大家如果有疑问欢迎在评论区提出。

下期预告:计划介绍下RDMA软件栈中关于MR的更多内容。

参考链接

[1] 地址空间的故事 - 知乎 (zhihu.com)

[2] 关于逻辑地址、线性地址、虚拟地址、物理地址的理解 - 广漠飘羽 - 博客园 (cnblogs.com)

[3] DMA API HOWTO. Linux Kernel. https://www.kernel.org/doc/Documentation/DMA-API-HOWTO.txt

[4] PCIE总线的地址问题 - 知乎 (zhihu.com)

[5] Dynamic DMA mapping Guide (wowotech.net)

【RDMA】21. RDMA之内存地址基础知识相关推荐

  1. 操作系统之内存管理:1、内存管理基础知识(指令工作原理、地址转化、程序运行过程)

    1.内存管理基础知识(指令工作原理.地址转化.程序运行过程) 思维导图 什么是内存? 指令的工作原理 装入模块的三种实现 绝对装入 可重定位装入 动态重定位 程序的运行过程 链接的三种方式 思维导图 ...

  2. mysql 访问寄存器_汇编寄存器(内存访问)基础知识之三---mov指令

    1 内存中字的存储 一个字型数据占2个内存单元,内存里面一个内存单元一个字节(8位),高地址单位放高8位,低地址单元放低8位. 注意:0号是地址单元,1是高地址单元(上是低地址,下面是高地址) (1) ...

  3. 3.1_ 1_ 内存的基础知识

    3.1_ 1_ 内存的基础知识 文章目录 1.知识总览 2.什么是内存,有什么作用 进程的运行原理-指令 逻辑地址vs物理地址 从写程序到程序运行 装入模块装入内存 装入的三种方式--绝对装入 装入的 ...

  4. 计算机知识有什么用处,电脑内存作用是什么?一文带你了解电脑内存的基础知识...

    电脑内存是电脑中至关重要的硬件之一,是不可或缺的硬件.电脑内存作用是什么?下面装机之家一文带你了解电脑内存的基础知识,来看看吧! 电脑内存作用是什么? 内存是其他设备与CPU进行沟通的桥梁,计算机中所 ...

  5. c语言相邻地址相差多少,C语言内存地址基础

    从计算机内存的角度思考C语言中的一切东东,是挺有帮助的.我们可以把计算机内存想象成一个字节数组,内存中每一个地址表示 1 字节.比方说我们的电脑有 4K 内存,那这个内存数组将会有 4096 个元素. ...

  6. 195、IP地址基础知识+冲突故障的解决方法

    IP基础知识 IP地址是互联网协议地址,使用统一地址格式,为网络中每个单元主机分配一个地址,供网络中其他设备来精确访问. IP地址类型分为公有地址和私有地址,公有地址就是分配给公共网络可以直接访问互联 ...

  7. 五、操作系统——内存相关基础知识 和 进程运行的基本原理(详解)

    一.概述 二.什么是内存?有何作用? 内存是用于存放数据的硬件.程序在执行之前,需要先放到内存中才能被CPU处理. 平时,我们各种各样的软件都是存储在外存(辅存)里.电脑的话,一般是存储在硬盘里,但是 ...

  8. 内存的基础知识(常用数量单位、进程运行原理、存储单元、内存地址、绝对装入、静态重定位、动态重定位、静态链接、动态链接等)

    文章目录 前言 知识总览 什么是内存?有何作用? 几个常用的数量单位 进程的运行原理--指令 逻辑地址vs物理地址 进程运行的基本原理 装入模块装入内存 装入的三种方式 1.绝对装入 2.静态重定位 ...

  9. 汇编寄存器(内存访问)基础知识之三---mov指令

     1 内存中字的存储 一个字型数据占2个内存单元,内存里面一个内存单元一个字节(8位),高地址单位放高8位,低地址单元放低8位. 注意:0号是地址单元,1是高地址单元(上是低地址,下面是高地址) (1 ...

最新文章

  1. 安装nginx+ngx_lua支持WAF防护功能
  2. 数据结构与算法 总结
  3. spring in action 读书笔记
  4. Who Gets the Most Candies? POJ - 2886 (线段树)
  5. tf.parse_single_example
  6. cad设计院常用字体_趣谈 | 那些年我们看过的电气图纸(附CAD/EPLAN区别)
  7. 学习学习SpringSecurity
  8. python对列求和_对单个列求和的最快方法
  9. 开课吧里的python学习是真的吗-做客李晨nic淘宝直播 胡海泉胡彦斌带货开课吧Python...
  10. VSTO:无法安装此应用程序,因为已安装具有相同标识的应用程序(亲测有效)
  11. 本特利1900/65A-00-00-01-00-00监视器
  12. Python数据可视化:5段代码搞定散点图绘制与使用,值得收藏
  13. 中国shopify们的来处与归途
  14. 使用ResponseEntity统一返回数据
  15. Java Web入门之JSTL标签的解析及使用(超详细必看)
  16. Unity3d 帧率设置 及在游戏运行时显示帧率
  17. java爬虫教程 百度云_java视频教程java爬虫实战项目httpclient hbase springmvc solr
  18. 8086 微型计算机原理和应用,微型计算机原理与应用.ppt
  19. 四种常见的浏览器内核简介----JS城市选择控件
  20. 山东专升本计算机基础知识(三)

热门文章

  1. PKIX path 异常 - 可以使用 Keytools 将服务端的秘钥库导入本地
  2. 工业控制系统安全解决方案
  3. 计算着色器(Compute Shader)
  4. 【Axure高保真原型】中继器版PDF阅读卡片
  5. 多媒体微型计算机必不可少的硬件,微型计算机有哪些组成部分,每个部分各有什么作用,哪些部分是微机运行必需的?...
  6. 数据结构 | 随机存取、顺序存取、随机存储和顺序存储
  7. PLL(锁相环)电路原理
  8. 免费的PDF转Word工具(简单易用)
  9. 易观CTO郭炜:如何构建企业级大数据Ad-hoc查询引擎
  10. Windows下使用bat批处理文件实现进程守护