概述
《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: enabledn");
0354 } else if (!strncmp(str, "off", 3)) {
0355 dmar_disabled = 1;
0356 printk(KERN_INFO "Intel-IOMMU: disabledn");
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_init和dmar_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有何不同?的全部内容,希望文章能够帮你解决内核引导参数IOMMU与INTEL_IOMMU有何不同?所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复