了解 RISC-V IOMMU

news2024/10/7 14:29:35

了解 RISC-V IOMMU

个人作为 IOMMU 初学者,从初学者的角度介绍我眼中 RISCV 的 IOMMU

如果有些描述不够专业,还请谅解,也欢迎讨论

部分内容来自 https://zhuanlan.zhihu.com/p/679957276(对于 RISCV IOMMU 规范手册的翻译,推荐前往此链接查找更详细的内容),同时增加了部分自己的理解

如侵删

一、IOMMU 的背景

输入输出内存管理单元 (IOMMU),有时也称为系统 MMU (SMMU),是一个系统级内存管理单元 (MMU),用于将具有直接内存访问(DMA)功能的输入/输出 (I/O) 设备连接到系统内存

没有 IOMMU 时:

  1. 非虚拟化的情况下,IO 设备得到的是物理地址,在进行 DMA 时可能破坏其他的设备或者系统内存

  2. 虚拟化的情况下,Guest OS 不能直接访问 PA,每次 DMA 操作都要陷入到 VMM 为 I/O 设备分配物理内存

有 IOMMU 时:

  1. 使得设备 DMA 更加安全,可以限制设备能够访问的物理内存
  2. 地址转换 IOVA -> PA,可以支持连续的 IOVA,非连续的 PA,可以利用物理内存中分散的页
二、IOMMU 在 SOC 中的位置

以 Spec 中的图5为例,该 SOC 集成了内存控制器和多个 IO 设备,还集成了两个 IOMMU 实例。

设备可以直接连接到 IO Bridge 和系统互连,也可以在需要将 IO 协议事务转换为系统互连事务时通过 Root Port 连接

第一个 IOMMU 实例 IOMMU 0(与 IO Bridge 0 相关联)将一个 Root Port 连接到系统结构/互连(Root Port 是一个 PCIe 端口),一个或多个终端设备通过该 Root Port 与 SoC 连接。

第二个IOMMU 实例 IOMMU 1(与 IO Bridge 1 相关联)说明了在不使用 Root Port 的情况下将设备(IO 设备 A 和 B)连接到系统架构的情况。

IO Bridge 位于设备和系统互连之间,用于处理 DMA 事务,IO 设备可使用 IO 虚拟地址(VA、GVA 或 GPA)执行 DMA 事务,IO Bridge 调用相关的 IOMMU,将 IOVA 转换为监控器物理地址 (SPA)。

在这里插入图片描述

Host interface:它是连接 IOMMU 的接口,供 Harts 访问其内存映射寄存器,并执行全局配置和/或维护操作

Data structure interface:它被 IOMMU 用于隐式访问内存。用于从主内存中获取所需的数据结构

Device Translation Request:从 IO Bridge 接收转换请求。在此接口上,IO Bridge 提供有关请求的信息。

Device Translation Completion:用于提供 IOMMU 对先前请求的地址转换的完成响应。

**ATS **:如果 IOMMU 支持可选的 PCIe ATS 功能,则 ATS 接口用于通过 PCIe Root Port 与具有 ATS 功能的 EP(Endpoint,即 PCIe 设备) 通信。

三、IOMMU 导言

节选出了我认为有助于理解 IOMMU 的部分

对于通过 IOMMU 连接到系统的每个 I/O 设备,软件都可以在 IOMMU 上配置设备上下文,将特定的虚拟地址空间和其他针对设备的参数与设备关联起来。通过在 IOMMU 为每个设备提供独立的设备上下文,可以为每个设备单独配置一个操作系统,这个操作系统可以是 Guest OS,也可以是主(主机)操作系统。在设备发起的每一次内存访问中,IOMMU 都会通过某种形式的唯一设备标识符来识别发起访问的设备,然后IOMMU 会使用该标识符在软件提供的数据结构中找到相应的设备上下文。本规范将这种唯一的设备标识符称为 device_id,并支持多达 24 位宽的标识符。

某些设备可能支持共享虚拟寻址,即与设备共享进程地址空间的功能。为支持此类寻址,软件可将一个或多个进程上下文配置到设备上下文中。此类设备启动的每次内存访问都会伴随一个唯一的进程标识符,IOMMU 将该标识符与唯一的设备标识符结合使用,以定位软件在设备上下文中配置的适当进程上下文。例如,对于 PCIe,进程上下文可由唯一的 20 位进程地址空间标识符 (PASID) 标识。本规范将此类唯一进程标识符称为 process_id,并支持多达 20 位宽的标识符。

IOMMU 采用两阶段地址转换流程,将 IOVA 转换为 SPA,并对 DMA 实施内存保护。为了执行地址转换和内存保护,IOMMU 在第一阶段和第二阶段地址转换中使用与 CPU 的 MMU 相同的页表格式。使用与 CPU MMU 相同的页表格式,可以消除 DMA 在内存管理方面的一些复杂性。使用相同的格式还允许 CPU MMU 和 IOMMU 同时使用相同的页表。

IOMMU 采用的虚拟内存方案可为每个设备单独配置 IOMMU。设备使用 I/O 虚拟地址 (IOVA) 执行 DMA。根据为设备选择的虚拟内存方案,设备使用的 IOVA 可能是 Supervisor 物理地址 (SPA)、Guest 物理地址 (GPA) 或虚拟地址 (VA)

IOMMU 中的 DMA 地址转换对 DMA 访问有一定的性能影响,因为使用软件提供的数据结构确定 SPA 所需的时间可能会延长访问时间。CPU MMU 中的类似开销通常是通过使用转换旁路缓冲器(TLB)来缓存这些地址转换,以便在后续访问中重复使用,从而减少转换开销。IOMMU 可以使用类似的地址转换缓存,即 IOMMU 地址转换缓存(IOATC)。当用于地址转换的内存驻留数据结构被修改时,IOMMU 为软件提供了使IOATC 与之同步的机制。软件可使用软件定义的上下文标识符(称为 Guest 软件上下文标识符 (GSCID))配置设备上下文,以’指示设备集合被分配给同一虚拟机’,从而访问共同的虚拟地址空间。软件可使用称为进程软件上下文标识符(PSCID)的软件定义上下文标识符配置进程上下文,以标识’共享共同虚拟地址空间的进程’集合。IOMMU 可使用 GSCID 和 PSCID 标记 IOATC 中的条目,以避免重复并简化失效操作。

四、IOMMU 的几种使用模式
1、非虚拟化 OS 的情况

对于这种情况,我的理解是:

  1. 用来做保护的,限制 DMA 能访问的物理内存区域
  2. 支持可以使用分散的物理内存区域

IOMMU 为操作系统提供了一种机制,通过限制设备可访问的内存来防止这种意外损坏。如图所示,操作系统可通过页表配置 IOMMU,以转换 IOVA,从而将可访问的地址限制在页表允许的范围内

传统的 32 位设备无法访问超过 4 GiB 的内存。如果没有 IOMMU,操作系统就必须通过分配在 4 GiB 以下内存中的缓冲区来复制数据。

IOMMU 可用于执行分散/聚集(scatter/gather)DMA,它允许为 I/O 分配较大的内存区域,而无需所有内存都是连续的一个连续的虚拟地址范围可以映射到这些零散的物理地址,并用虚拟地址范围对设备进行编程。

IOMMU 可用于支持共享虚拟寻址,即与设备共享进程地址空间。用于 DMA 的虚拟地址由 IOMMU 转换为SPA。

当 IOMMU 被非虚拟化操作系统使用时,第一阶段足以提供所需的地址转换和保护功能,第二阶段可设置为 “Bare”。

在这里插入图片描述

2、Hypervisor 的情况

对于这种情况,我的理解是:

  1. Hypervisor 提供 GPA->SPA 转换,限制 Guest OS 访问的物理内存
  2. 同时也支持仅OS的情况,可以使用分散的物理内存
  3. 对于使用 MSI 中断的设备,可以借助 IOMMU 找到 VM 对应的中断文件

直接控制设备的 Guest OS 将使用 GPA 对设备进行编程。当设备使用这些地址执行内存访问时,IOMMU 就会使用 Hypervisor 提供的地址转换数据结构,负责将这些 GPA 转换为 SPA 。

在这里插入图片描述

为了处理由 Guest OS 控制的设备发出的 MSI,Hypervisor 会配置 IOMMU,将这些 MSI 重定向到 IMSIC 中的 Guest 中断文件(见下图)或内存驻留中断文件。IOMMU 负责使用 Hypervisor 提供的 MSI 地址转换数据结构来执行 MSI 重定向。

在这里插入图片描述

3、Guest OS 的情况

对于这种情况,我的理解是:

以上两种情况的结合,第一阶段地址翻译为了让 Guest OS 感知不到 Hypervisor 的存在,以为自己是一个物理机上的 OS(即第一种情况),第二阶段翻译对应以上的第二种情况

Hypervisor 可以通过硬件仿真或让 Guest OS 使用 Hypervisor 的软件接口来提供虚拟IOMMU 设施。Guest OS 可以使用虚拟 IOMMU 提供的设施,通过使用它所控制的第一阶段页表,获得与非虚拟化操作系统相同的好处。Hypervisor 会建立一个由其控制的第二阶段页表,以虚拟化虚拟机的地址空间,并包含从传递给虚拟机的设备到与虚拟机相关的内存的内存访问。

启用两阶段地址转换后,IOVA 首先使用 Guest OS 管理的第一阶段页表转换为 GPA,然后使用 Hypervisor 管理的第二阶段页表将 GPA 转换为 SPA

IOMMU 配置为使用设备 D1 的第一阶段和第二阶段页表执行地址转换。第二阶段通常由 Hypervisor 用于将 GPA 转换为 SPA,并将设备 D1 限制为与 VM-1 相关的内存第一阶段通常由 Guest OS 配置,将 VA 转换为 GPA,并将设备 D1 的访问限制在 VM-1 内存的子集上

对于设备 D2,只有第二阶段处于激活状态,第一阶段设置为 “Bare”,我认为可以看作没有 OS 配置页表的情况,即看作使用没有使用虚拟地址的 RTOS 或者裸机程序。

Hypervisor 也可以保留一个设备(如 D3)供自己使用。第一阶段足以为设备 D3 提供所需的地址转换和保护功能,第二阶段设置为 “Bare”,这种情况和在没有虚拟化的 OS 类似。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1589644.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

这是雷军的简历,落魄时卡里只有冰冷的40亿

互联网新词儿 周五了,来点放松的(嗯?周五?不是上了五天班了吗,为什么不是周六 如果说哪一种炫富秀优越并不伤人,那一定是富含"幽默感"的脱口秀式的吹牛。 我印象中,江湖上还是有这么个…

UDP网络程序

上一章中&#xff0c;我们介绍了socket&#xff0c;以及TCP/UDP协议。这一章带大家实现几个UDP协议的网络服务。我们需要一个 服务端和一个客户端。 1.服务端实现 1.1socket函数 #include <sys/types.h> #include <sys/socket.h>int socket(int domain, in…

Vue结合el-table实现合并单元格(以及高亮单元表头和指定行)

实现效果如下&#xff1a; 思路&#xff1a; 1.首先使用动态表头表格。 2.其次实现动态计算合并单元格。&#xff08;计算规则 传递需要合并的字段&#xff09; 3.然后封装公共的计算单元格方法 export导出供多个页面使用。 4.同时需要封装成公共的组件供多个页面使用。 5…

Hi3861 OpenHarmony嵌入式应用入门--鸿蒙开发环境搭建

目录 简介 准备材料 安装开发环境 配置开发工具和sdk 新建工程 代码编译 简介 本篇将进行hi3861开发环境的搭建&#xff0c;并能够编译默认工程。 准备材料 华为集成开发环境工具DevEco Device Tool 华为集成开发环境IDE DevEco Device Tool下载 | HarmonyOS设备开发 …

书生潽语趣味 demo

创建开发机 使用 InternLM2-Chat-1.8B 模型生成 300 字的小故事 运行猪八戒模型试一下

linux使用docker实现redis主从复制和哨兵模式

目录 1. 拉取redis镜像 2.使用可视化redis工具 3. 设置从redis 4.设置哨兵模式 5. 使用docker-compose快速创建 1. 拉取redis镜像 docker pull redis 默认拉取最新的镜像。 然后pull结束后使用docker images检查镜像&#xff1a; 然后docker run创建container容器 首先…

统计 | Levene检验

Levene检验是方差齐性检验的一种&#xff0c;即检验各组样本方差是否相等的一种统计方法.它通常用于方差分析&#xff08;ANOVA&#xff09;前的一个步骤。Levene检验的零假设是各组的方差相等。 Levene检验的数学步骤如下&#xff1a; 1. 数据准备&#xff1a; 假设我们有个…

Scikit-learn 快速入门篇

Sklearn 简介 scikit-learn (sklearn) 是 Python 中用于机器学习的最流行的库之一。它提供了一系列有效的算法和工具&#xff0c;涵盖各种机器学习任务&#xff0c;包括&#xff1a; 分类回归聚类降维模型选择数据预处理 Sklearn 六大模块 分类&#xff1a;预测离散类别 算…

腾讯云向量数据库-RAG介绍

1.说明 RAG结合LLM(通用大预言模型)构件基于私有文档、专业领域知识、实时信息的charbot。 2.RAG的主要步骤 知识切片成chunk向量化chunk入库query检索知识chunk构件prompts调用llm生成回答 3.优势 快速构件demo快速理解rag社区支持 4.痛点 投入大效果差调优难 5.RAG应…

激光slam论文汇总

文章目录 2014LOAM: Lidar Odometry and Mapping in Real-time 2018LeGO-LOAM: Lightweight and Ground-Optimized Lidar Odometry and Mapping on Variable Terrain 2020LIO-SAM: Tightly-coupled Lidar Inertial Odometry via Smoothing and Mapping 2021LVI-SAM: Tightly-co…

多 线 程

1&#xff0e;什么是多线程? 有了多线程&#xff0c;我们就可以让程序同时做多件事情 2.多线程的作用? 提高效率 3&#xff0e;多线程的应用场景? 只要你想让多个事情同时运行就需要用到多线程 比如:软件中的耗时操作、所有的聊天软件、所有的服务器 1.进程和线程【理解】 …

PHP01——php快速入门 之 使用phpstudy快速搭建PHP环境

PHP01——php快速入门 之 使用phpstudy快速搭建PHP环境 0. 前言1. 下载小皮面板1.1 下载phpstudy&#xff08;小皮面板&#xff09;1.2 启动、简单访问1.2.1 启动Apache1.2.2 访问1.2.3 访问自定义文件或页面 2. 创建网站2.1 创建网站2.2 可能遇到的问题2.2.1 hosts权限问题&am…

靠谱的香港服务器有哪些(看过才后悔)_避坑血泪史

最受欢迎的外贸建站服务器就是香港服务器&#xff0c;可是很多人还不知道如何辨别香港服务器商家是否靠谱。 小编曾经也是建站新手&#xff0c;以前也碰到过很多不靠谱的服务器商家&#xff0c;各种踩坑&#xff0c;可以说都是用钱堆出来的经验。在这里小编给大家总结下&#…

ADG数据库迁移方案

一、环境说明 源库 目标库 IP 192.168.37.201 192.168.37.202 系统版本 RedHat 7.9 RedHat 7.9 数据库版本 19.3.0.0.0 19.3.0.0.0 SID pri std hostname primary standby 数据量 整个库 说明:源库已经创建数据库实例&#xff0c;目标库只有数据库软件。…

蓝桥杯— —小明的背包问题

小明的背包问题 小明的背包1 — — &#xff08;01背包&#xff09; 友情链接&#xff1a;小明的背包1 题目&#xff1a; 输入样例: 5 20 1 6 2 5 3 8 5 15 3 3 输出样例&#xff1a; 37思路&#xff1a; 对于01背包问题&#xff0c;其中一个重要的条件是每一种物品只有一个…

git查看单独某一个文件的历史修改记录

git查看单独某一个文件的历史修改记录 git log -p 文件具体路径 注意&#xff0c;Windows下默认文件路径分隔符是 \&#xff0c;在git bash 里面需要改成 /。 git基于change代码修改与提交_git change-CSDN博客文章浏览阅读361次。git cherry-pick&#xff1a;复制多个提交comm…

2023全国青少年信息素养大赛总决赛C++小学组真题

2023 全国青少年信息素养大赛总决赛C小学组真题 第一题 给定一个五位数x&#xff0c;你需要重复做以下操作: 把数的各个数位进行由大到小排序和由小到大排序&#xff0c;得到的最大值和最小值&#xff0c;进行求差后作为新的x。 可以证明&#xff0c;在经过有限次操作后&…

代码随想录算法训练营33期 第三十一天(补29) | 491. 非递减子序列、46. 全排列、47. 全排列 II

491. 非递减子序列 class Solution { public:vector<int> path;vector<vector<int>> result;void BackTracking(vector<int>& nums, int index){if(path.size()>2){result.push_back(path);}unordered_set<int> usedSet;for (int iindex…

爬取日本常用汉字秘籍

前言 昨天投简历时遇到了这样的一个笔试。本以为会是数据结构算法之类的没想到直接发了一个word直接提需求&#xff0c;感觉挺有意思就写了这篇文章&#xff0c;感兴趣的朋友可以看看。 1. 网页内容解析 首先&#xff0c;我们通过请求网页获取到日本常用汉字的链接列表。然后…

多线程java

多线程的创建 前两种方法无法返回直接结果,而有的线程执行完毕后需要返回结果 方式一:java是通过java.lang.Thread类的对象来代表线程的 启动线程必须调用strat方法,不是调用run方法不要把主线程任务放在启动子线程之前 //1.让子类继承Thread线程类 public class MyThread …