《ARM SMMU原理与IOMMU技术(“VT-d” DMA、I/O虚拟化、内存虚拟化)》

《提升KVM异构虚拟机启动效率:透传(pass-through)、DMA映射(VFIO、PCI、IOMMU)、virtio-balloon、异步DMA映射、预处理》

《内核引导参数IOMMU与INTEL_IOMMU有何不同?》

《DMAR(DMA remapping)与 IOMMU》


前文(《DMAR(DMA remapping)与 IOMMU》)介绍过IOMMU是提供DMA Remapping功能的硬件模块,可以把DMA地址从虚拟地址翻译成物理地址。Linux kernel有两个引导参数(boot parameter)与iommu有关:iommu=[on/off] 和 intel_iommu=[on/off],它们有什么区别呢?答案是:参数iommu控制的是GART iommu(AMD)功能,参数intel_iommu控制的是基于Intel VT-d的iommu(Intel)功能。  

下面的代码表明:CONFIG_IOMMU控制的是GART iommu(AMD),CONFIG_DMAR控制的是intel_iommu(Intel)。(CONFIG_IOMMU对应的是引导参数iommu,CONFIG_DMAR对应的是引导参数intel_iommu,注意:CONFIG_DMAR名称中没有Intel字样,这里比较容易误导,但你看它下面对应的函数intel_iommu_init就很明显了):

负责DMA remapping操作的硬件称为IOMMU。做个类比:大家都知道MMU是支持内存地址虚拟化的硬件,MMU是为CPU服务的;而IOMMU是为I/O设备服务的,是将DMA地址进行虚拟化的硬件。

arch/x86_64/kernel/pci-dma.c:0331 static int __init pci_iommu_init(void)
0332 {
0333 #ifdef CONFIG_CALGARY_IOMMU
0334         calgary_iommu_init();
0335 #endif
0336
0337 #ifdef CONFIG_DMAR
0338         intel_iommu_init();
0339 #endif
0340
0341 #ifdef CONFIG_AMD_IOMMU
0342         amd_iommu_init();
0343 #endif
0344
0345 #ifdef CONFIG_IOMMU
0346         gart_iommu_init();
0347 #endif
0348
0349         no_iommu_init();
0350         return 0;
0351 }

引导参数iommu控制的是GART iommu,前文(《DMAR(DMA remapping)与 IOMMU》)介绍过GART (Graphics Address Remapping Table),最初是为了方便图形芯片直接读取内存而设计的:使用地址转译功能将收集到内存中的数据映射到一个图形芯片可以“看”到的地址。这个地址转译功能自然也可以充当IOMMU,于是GART被Linux kernel用来帮助传统的32位PCI设备访问可寻址范围之外的内存区域。GART iommu有局限性(比如仅限于显存范围内),不具备Intel IOMMU的完整功能。

附注: 过去的AMD64芯片也提供一个功能有限的地址转译模块——GART (Graphics Address Remapping Table),有时候它也可以充当IOMMU,这导致了人们对GART和新的IOMMU的混淆。最初设计GART是为了方便图形芯片直接读取内存:使用地址转译功能将收集到内存中的数据映射到一个图形芯片可以“看”到的地址。后来GART被Linux kernel用来帮助传统的32位PCI设备访问可寻址范围之外的内存区域。这件事新的IOMMU当然也可以做到,而且没有GART的局限性(它仅限于显存的范围之内),IOMMU可以将I/O设备的任何DMA地址转换为物理内存地址。https://rtoax.blog.csdn.net/article/details/109607590

“iommu”参数默认是打开的,以2.6.18 kernel为例,

configs/kernel-2.6.18-x86_64.config:
...
0187 CONFIG_IOMMU=y
...

注:GART iommu功能是按需激活的,并有前提条件,比如系统内存必须在3GB以上、而且只对有限的设备,参见:

arch/x86_64/Kconfig:
...
0481 config IOMMU
0482         bool "IOMMU support" if EMBEDDED
0483         default y
0484         select SWIOTLB
0485         select AGP
0486         depends on PCI && !X86_64_XEN
0487         help
0488           Support for full DMA access of devices with 32bit memory access only
0489           on systems with more than 3GB. This is usually needed for USB,
0490           sound, many IDE/SATA chipsets and some other devices.
0491           Provides a driver for the AMD Athlon64/Opteron/Turion/Sempron GART
0492           based IOMMU and a software bounce buffer based IOMMU used on Intel
0493           systems and as fallback.
0494           The code is only active when needed (enough memory and limited
0495           device) unless CONFIG_IOMMU_DEBUG or iommu=force is specified
0496           too.
...

引导参数intel_iommu控制的是基于Intel VT-d的iommu,该参数默认是关闭的,在config文件中对应的配置如下(注意:名称中用的是DMAR而不是iommu,不留意的话容易错过):

configs/kernel-2.6.18-x86_64.config
...
0303 # CONFIG_DMAR_DEFAULT_ON is not set
...

从以下的代码中我们看到:[默认情况]与[显式设置intel_iommu=off]的效果是一样的,结果都是”dmar_disabled=1″,所以 intel_iommu=off 设不设置其实都一样:

drivers/pci/intel-iommu.c:0330 #ifdef CONFIG_DMAR_DEFAULT_ON
0331 int dmar_disabled = 0;
0332 #else
0333 int dmar_disabled = 1;
0334 #endif /*CONFIG_DMAR_DEFAULT_ON*/0346 static int __init intel_iommu_setup(char *str)
0347 {
0348         if (!str)
0349                 return -EINVAL;
0350         while (*str) {
0351                 if (!strncmp(str, "on", 2)) {
0352                         dmar_disabled = 0;
0353                         printk(KERN_INFO "Intel-IOMMU: enabled\n");
0354                 } else if (!strncmp(str, "off", 3)) {
0355                         dmar_disabled = 1;
0356                         printk(KERN_INFO "Intel-IOMMU: disabled\n");
0357                 } else if (!strncmp(str, "igfx_off", 8)) {
...

注:启动参数intel_iommu有点复杂的是:存在两个与DMAR有关的配置,除了上面看到的CONFIG_DMAR_DEFAULT_ON之外,另外还有一个是CONFIG_DMAR,默认是打开的:

configs/kernel-2.6.18-x86_64.config
...
0302 CONFIG_DMAR=y
0303 # CONFIG_DMAR_DEFAULT_ON is not set
...

CONFIG_DMAR告诉内核在编译时要准备好支持DMA Remapping设备(见注一);而CONFIG_DMAR_DEFAULT_ON 是告诉内核在引导时是否激活DMAR设备。也就是说,默认情况下(CONFIG_DMAR=y)内核已经具备了支持DMAR的功能,设置内核引导参数intel_iommu=off(等效于缺省情况:即CONFIG_DMAR_DEFAULT_ON未设置)并不是关闭内核的DMAR功能,仅仅是告诉内核在引导过程中不要把DMAR设备激活而已。这两个配置参数的详细解释参见以下文件。

arch/x86_64/Kconfig:
...
0703 config DMAR
0704         bool "Support for DMA Remapping Devices (EXPERIMENTAL)"
0705         depends on X86_64 && PCI_MSI && ACPI && EXPERIMENTAL && !XEN
0706         help
0707           DMA remapping (DMAR) devices support enables independent address
0708           translations for Direct Memory Access (DMA) from devices.
0709           These DMA remapping devices are reported via ACPI tables
0710           and include PCI device scope covered by these DMA
0711           remapping devices.
0712
0713 config DMAR_DEFAULT_ON
0714         def_bool n
0715         prompt "Enable DMA Remapping Devices by default"
0716         depends on DMAR
0717         help
0718           Selecting this option will enable a DMAR device at boot time if
0719           one is found. If this option is not selected, DMAR support can
0720           be enabled by passing intel_iommu=on to the kernel. It is
0721           recommended you say N here while the DMAR code remains
0722           experimental.
...

(注一)事实上更准确地说,内核不仅仅是在编译时具备了支持DMAR设备的功能,而且在引导过程中始终会根据ACPI table把DMAR设备有关的数据结构都初始化好–无论是否加了引导参数intel_iommu=off。

内核怎么知道哪些设备需要DMA Remapping呢?是通过ACPI table知道的,因为需要DMA Remapping的设备必须在firmware/BIOS中登记。以下是内核初始化DMAR的代码,可以看到无论是否dmar_disabled,都会调用dmar_table_initdmar_dev_scope_init

drivers/pci/intel-iommu.c:3317 int __init intel_iommu_init(void)
3318 {
3319         int ret = 0;
3320
3321         if (dmar_table_init())
3322                 return  -ENODEV;
3323
3324         if (dmar_dev_scope_init())
3325                 return  -ENODEV;
3326
3327         /*
3328          * Check the need for DMA-remapping initialization now.
3329          * Above initialization will also be used by Interrupt-remapping.
3330          */
3331         if (no_iommu || swiotlb || dmar_disabled)
3332                 return -ENODEV;
3333
...

这就是为什么只要BIOS中打开了Intel VT-d,我们就总会在kernel messages中看到类似下面的初始化DMAR table的信息,无论intel_iommu参数是on还是off。

...
DMAR:Host address width 46
DMAR:DRHD base: 0x000000efefe000 flags: 0x0
IOMMU efefe000: Number of IOMMU domains reduced from 64K to 4K
IOMMU efefe000: ver 1:0 cap d2078c106f0464 ecap f020de
DMAR:DRHD base: 0x000000dcffe000 flags: 0x1
IOMMU dcffe000: Number of IOMMU domains reduced from 64K to 4K
IOMMU dcffe000: ver 1:0 cap d2078c106f0464 ecap f020de
DMAR:RMRR base: 0x000000bdffd000 end: 0x000000bdffffff
DMAR:RMRR base: 0x000000bdff6000 end: 0x000000bdffcfff
DMAR:RMRR base: 0x000000bdf83000 end: 0x000000bdf84fff
...

如果你想让kernel中与Intel VT-d有关的软件模块完全关闭,仅仅使用启动参数intel_iommu=off是不够的,而必须重新编译内核–在config中配置CONFIG_DMAR=n,或者用另一种方法:在BIOS中关闭Intel VT-d

内核引导参数IOMMU与INTEL_IOMMU有何不同?相关推荐

  1. Linux 内核引导参数简介

    概述 内核引导参数大体上可以分为两类:一类与设备无关.另一类与设备有关.与设备有关的引导参数多如牛毛,需要你自己阅读内核中的相应驱动程序源码以获取其能够接受的引导参数.比如,如果你想知道可以向 AHA ...

  2. centos内核引导参数

    绝大部分的内核引导参数的格式如下(每个参数的值列表中最多只能有十项): name[=value_1][,value_2]...[,value_10] 如果"name"不能被识别并且 ...

  3. 内核引导参数精选【zz鸿飞无痕】

    http://hi.baidu.com/smilewwh/blog/item/fcdff8f93384c75a242df2e7.html 内核引导参数精选 2007年11月14日 星期三 15:55 ...

  4. Linux启动引导参数grub

    内核引导参数大体上可以分为两类:一类与设备无关.另一类与设备有关.与设备有关的引导参数多如牛毛,需要你自己阅读内核中的相应驱动程序源码以获取其能够接受的引导参数.比如,如果你想知道可以向 AHA154 ...

  5. Linux 内核引导选项简介 *********很多常用的受益匪浅

    内核引导选项大体上可以分为两类:一类与设备无关.另一类与设备有关.与设备有关的引导选项多如牛毛,需要你自己阅读内核中的相应驱动程序源码以获取其能够接受的引导选项.比如,如果你想知道可以向 AHA154 ...

  6. Linux内核引导选项

    概述 内核引导选项大体上可以分为两类:一类与设备无关.另一类与设备有关.与设备有关的引导选项多如牛毛,需要你自己阅读内核中的相应驱动程序源码以获取其能够接受的引导选项.比如,如果你想知道可以向 AHA ...

  7. linux 内核启动参数

    Linux 内核引导选项简介 作者:金步国 版权声明 本文作者是一位开源理念的坚定支持者,所以本文虽然不是软件,但是遵照开源的精神发布. 无担保:本文作者不保证作品内容准确无误,亦不承担任何由于使用此 ...

  8. centos8使用grubby修改内核启动参数

    grubby是一个用于更新和显示有关各种体系结构特定的引导程序的配置文件信息的命令行工具. 它主要设计用于安装新内核并需要查找有关当前引导环境的信息的脚本,同时也可以对启动内核的各项信息参数进行修改. ...

  9. Linux内核引导简析

    bootsect.S.setup.S.head.S分析 收藏 2010-01-14 13:36:34 bootsect.S,系统引导程序,一般不超过512字节. 在PC系统结构中,线性地址0xA000 ...

最新文章

  1. SmartImageView框架的使用
  2. stringstream的用法
  3. CF1404C:Fixed Point Removal(离线)(树状数组二分)
  4. 单元测试原来是这样的呼
  5. 30行python代码设计_30行Python代码实现3D数据可视化
  6. qt html导pdf 页眉,如何使用wkhtmltopdf unpatched qt在每个页面上添加页眉和页脚?
  7. Typora导出PDF时一直处于正在导出的状态
  8. 数据库高并发解决方案(一)查询优化
  9. 外网资源下载速度过慢的问题
  10. Screaming Frog SEO Spider for Mac进行网页抓取和数据提取的技巧
  11. VB/VBA的浮点数结构
  12. 浏览器主流内核分析,浏览器版本过低升级方法
  13. 2021年机修钳工(中级)考试资料及机修钳工(中级)新版试题
  14. GIF、SVG、PNG、图片格式转换
  15. 一作3篇SCI认定A类博士!享100万安家费+30万科启!三年副教授待遇+2K/月津贴!...
  16. 287. 寻找重复数
  17. 3原色对照表.....
  18. 《大话处理器》简要学习笔记
  19. 【云原生 | Kubernetes 系列】K8s 实战 一文学会如何从 PodSecurityPolicy 迁移到内置的 PodSecurity 准入控制器
  20. android系统recovery模式,Android系统Recovery模式中文详细说明

热门文章

  1. java怎么给框架添加背景图,java里怎么给Container添加背景图片
  2. 剑指 Offer59-I-滑动窗口的最大值
  3. vue-slicksort拖拽组件
  4. mysql 类型及其他
  5. Unity中的单例方法
  6. 【神经网络与深度学习】Caffe使用step by step:使用自己数据对已经训练好的模型进行finetuning...
  7. HDU 3952 Fruit Ninja
  8. Finally it is here - Physbam source code has been released!
  9. Spring的基本应用
  10. 在Intellij idea 中YAML文件出现代码提示