zoukankan      html  css  js  c++  java
  • iommu系列之概念解释篇

    本文会对iommu中的一些容易引起疑惑的概念进行阐述,内核版本为4.19.
    先上简写:

    • DMAR - DMA remapping
    • DRHD - DMA Remapping Hardware Unit Definition
    • RMRR - Reserved memory Region Reporting Structure
    • ZLR - Zero length reads from PCI devices
    • IOVA - IO Virtual address.
    • SMMU -System Memory Management Unit,就是arm的iommu

    1、为什么会有一个iommu_group的概念,直接将device和iommu_domain关联不香吗?
    假设我们通过iommu提供设备的DMA能力,当发起dma_map的时候,设备设置了streamid, 但是多个设备的streamid有可能是一样的
    那么这时候修改其中一个设备的页表体系,就影响了相同streamid的其他设备。
    所以,修改页表的最小单位不是设备,而是streamid。这个streamid大家可能觉得比较抽象,先知道这个是用来索引的就行。
    因此,为了避免这种情况,增加了一个iommu_group的概念,iommu_group代表共享同一个streamid的一组device(表述在/sys/kernel/iommu_group中)。
    有了iommu_group, 设备发起dma_map操作时,会定位streamid和iommu_group, group定位了iommu_device和iommu_domain,
    iommu_domain定位了asid。group 里面的设备既然公用一套iova的页表,那么只能透传给一个虚机,不能分开透传。
    一个iommu_group里面既可能只有一个device,也可能有多个device。

    arm smmu-v3中的 iommugroup 类型为2类

    //caq:arm中针对iommu,有两类group,如果是pci的设备,用一个默认group,否则用系统的默认group,注意是两类,不是两个,个数可以建很多个。
    static struct iommu_group *arm_smmu_device_group(struct device *dev)
    {
    	struct iommu_group *group;
    
    	/*
    	 * We don't support devices sharing stream IDs other than PCI RID
    	 * aliases, since the necessary ID-to-device lookup becomes rather
    	 * impractical given a potential sparse 32-bit stream ID space.
    	 */
    	if (dev_is_pci(dev))
    		group = pci_device_group(dev);//caq:pci 的group
    	else
    		group = generic_device_group(dev);//caq:generic  的group
    
    	return group;
    }
    

    2、resv_regions
    有些保留的区域,是不能dma映射的,将这些区域管理起来,避免映射。
    对于arm smmu-v3来说,保存区域为 MSI_IOVA_BASE,长度为 MSI_IOVA_LENGTH,还有保留类型为IOMMU_RESV_MSI,它是硬件的 msi 区域 。
    对于intel 来说,保留区域为 IOMMU_RESV_DIRECT 和 IOMMU_RESV_MSI类型的 IOAPIC_RANGE_START 区域。

    3、iommu_group 和dev 之间的关系

    # for d in /sys/kernel/iommu_groups/*/devices/*; do n=${d#*/iommu_groups/*}; n=${n%%/*}; printf 'IOMMU Group %s ' "$n"; lspci -nns "${d##*/}"; done;
    IOMMU Group 0 00:00.0 Host bridge [0600]: Intel Corporation Sky Lake-E DMI3 Registers [8086:2020] (rev 07)
    IOMMU Group 10 00:05.2 System peripheral [0880]: Intel Corporation Device [8086:2025] (rev 07)
    IOMMU Group 11 00:05.4 PIC [0800]: Intel Corporation Device [8086:2026] (rev 07)
    IOMMU Group 12 00:08.0 System peripheral [0880]: Intel Corporation Sky Lake-E Ubox Registers [8086:2014] (rev 07)
    IOMMU Group 13 00:08.1 Performance counters [1101]: Intel Corporation Sky Lake-E Ubox Registers [8086:2015] (rev 07)
    IOMMU Group 14 00:08.2 System peripheral [0880]: Intel Corporation Sky Lake-E Ubox Registers [8086:2016] (rev 07)
    IOMMU Group 15 00:11.0 Unassigned class [ff00]: Intel Corporation C620 Series Chipset Family MROM 0 [8086:a1ec] (rev 09)
    IOMMU Group 15 00:11.5 SATA controller [0106]: Intel Corporation C620 Series Chipset Family SSATA Controller [AHCI mode] [8086:a1d2] (rev 09)
    IOMMU Group 16 00:14.0 USB controller [0c03]: Intel Corporation C620 Series Chipset Family USB 3.0 xHCI Controller [8086:a1af] (rev 09)
    IOMMU Group 16 00:14.2 Signal processing controller [1180]: Intel Corporation C620 Series Chipset Family Thermal Subsystem [8086:a1b1] (rev 09)
    IOMMU Group 17 00:16.0 Communication controller [0780]: Intel Corporation C620 Series Chipset Family MEI Controller #1 [8086:a1ba] (rev 09)
    IOMMU Group 17 00:16.1 Communication controller [0780]: Intel Corporation C620 Series Chipset Family MEI Controller #2 [8086:a1bb] (rev 09)
    IOMMU Group 17 00:16.4 Communication controller [0780]: Intel Corporation C620 Series Chipset Family MEI Controller #3 [8086:a1be] (rev 09)
    IOMMU Group 18 00:17.0 SATA controller [0106]: Intel Corporation C620 Series Chipset Family SATA Controller [AHCI mode] [8086:a182] (rev 09)
    IOMMU Group 19 00:1c.0 PCI bridge [0604]: Intel Corporation C620 Series Chipset Family PCI Express Root Port #1 [8086:a190] (rev f9)
    IOMMU Group 1 00:04.0 System peripheral [0880]: Intel Corporation Sky Lake-E CBDMA Registers [8086:2021] (rev 07)
    IOMMU Group 20 00:1c.1 PCI bridge [0604]: Intel Corporation C620 Series Chipset Family PCI Express Root Port #2 [8086:a191] (rev f9)
    IOMMU Group 21 00:1c.2 PCI bridge [0604]: Intel Corporation C620 Series Chipset Family PCI Express Root Port #3 [8086:a192] (rev f9)
    IOMMU Group 22 00:1c.3 PCI bridge [0604]: Intel Corporation C620 Series Chipset Family PCI Express Root Port #4 [8086:a193] (rev f9)
    IOMMU Group 23 00:1c.5 PCI bridge [0604]: Intel Corporation C620 Series Chipset Family PCI Express Root Port #6 [8086:a195] (rev f9)
    

    从打印可以看出,/sys/kernel/iommu_groups/ 这个kset 下有所有的iommu_group 信息,然后 对应的某个group下目前暴露两个信息,一个是归属在这个group的设备,一个是他的reserved_regions.

    root@G3:/sys/kernel/iommu_groups# ls
    0  10  12  14  16  18  2   21  23  25  27  29  30  32  34  36  38  4   41  43  45  47  49  50  52  54  56  58  6   61  63  65  67  69  70  72  74  76  78  8   81  83  85  87  89  90  92  94  96
    1  11  13  15  17  19  20  22  24  26  28  3   31  33  35  37  39  40  42  44  46  48  5   51  53  55  57  59  60  62  64  66  68  7   71  73  75  77  79  80  82  84  86  88  9   91  93  95
    root@G3:/sys/kernel/iommu_groups# cd 2
    root@G3:/sys/kernel/iommu_groups/2# ls
    devices  reserved_regions  type
    root@G3:/sys/kernel/iommu_groups/2# ll
    total 0
    drwxr-xr-x  3 root root    0 10月 25 09:23 ./
    drwxr-xr-x 99 root root    0 10月 25 03:40 ../
    drwxr-xr-x  2 root root    0 10月 29 10:43 devices/
    -r--r--r--  1 root root 4096 10月 30 10:15 reserved_regions
    -r--r--r--  1 root root 4096 10月 30 10:15 type
    root@G3:/sys/kernel/iommu_groups/2# ls devices/
    0000:00:04.1
    root@G3:/sys/kernel/iommu_groups/2# pwd
    /sys/kernel/iommu_groups/2
    root@G3:/sys/kernel/iommu_groups/2# ls devices/
    0000:00:04.1
    root@G3:/sys/kernel/iommu_groups/2# ls reserved_regions
    reserved_regions
    root@G3:/sys/kernel/iommu_groups/2# cat reserved_regions
    0x00000000fee00000 0x00000000feefffff msi
    root@G3:/sys/kernel/iommu_groups/2# ls ../3/
    devices/          reserved_regions  type
    root@G3:/sys/kernel/iommu_groups/2# ls ../3/devices/
    0000:00:04.2
    root@G3:/sys/kernel/iommu_groups/2# cat ../3/reserved_regions/
    cat: ../3/reserved_regions/: Not a directory
    root@G3:/sys/kernel/iommu_groups/2# cat ../3/reserved_regions
    0x00000000fee00000 0x00000000feefffff msi
    
    

    4、总线地址是个什么概念
    以pci总线举例,BAR读取到的是PCI地址空间中的地址,不等同于CPU认识的内存地址。虽然在x86上如果没有开启IOMMU时,它们的值一般是相同的,但是对于其他构架的CPU如PowerPC就可以是不一样的。
    所以正确的使用BAR空间的方法:

    pciaddr=pci_resource_start(pdev,1);
    if(pciaddr!=NULL)
    {
    ioremap(pciaddr,xx_SIZE);
    }
    

    而不是下面这样错误的方法:

    pci_read_config_dword(pdev,1,&pciaddr);
    ioremap(pciaddr,xx_SIZE);
    

    对于内核态cpu的地址来说,它只关心内核态 虚拟地址 通过mmu 转为 物理地址,在设备驱动通知设备做dma操作的时候,直接给设备传递没有经过dma_map的地址,是会有问题的。

    5、如何确认iommu的硬件加载情况

    [root@localhost dma]# dmesg -T|grep -i dmar
    [Sat Oct  9 08:56:54 2021] ACPI: DMAR 000000006fffd000 00200 (v01 DELL   PE_SC3   00000001 DELL 00000001)----------linux启动时扫描acpi的table
    [Sat Oct  9 08:57:01 2021] DMAR: Host address width 46
    [Sat Oct  9 08:57:01 2021] DMAR: DRHD base: 0x000000d37fc000 flags: 0x0
    [Sat Oct  9 08:57:01 2021] DMAR: dmar0: reg_base_addr d37fc000 ver 1:0 cap 8d2078c106f0466 ecap f020df
    [Sat Oct  9 08:57:01 2021] DMAR: DRHD base: 0x000000e0ffc000 flags: 0x0
    [Sat Oct  9 08:57:01 2021] DMAR: dmar1: reg_base_addr e0ffc000 ver 1:0 cap 8d2078c106f0466 ecap f020df
    [Sat Oct  9 08:57:01 2021] DMAR: DRHD base: 0x000000ee7fc000 flags: 0x0
    [Sat Oct  9 08:57:01 2021] DMAR: dmar2: reg_base_addr ee7fc000 ver 1:0 cap 8d2078c106f0466 ecap f020df
    [Sat Oct  9 08:57:01 2021] DMAR: DRHD base: 0x000000fbffc000 flags: 0x0
    [Sat Oct  9 08:57:01 2021] DMAR: dmar3: reg_base_addr fbffc000 ver 1:0 cap 8d2078c106f0466 ecap f020df
    [Sat Oct  9 08:57:01 2021] DMAR: DRHD base: 0x000000aaffc000 flags: 0x0
    [Sat Oct  9 08:57:01 2021] DMAR: dmar4: reg_base_addr aaffc000 ver 1:0 cap 8d2078c106f0466 ecap f020df
    [Sat Oct  9 08:57:01 2021] DMAR: DRHD base: 0x000000b87fc000 flags: 0x0
    [Sat Oct  9 08:57:01 2021] DMAR: dmar5: reg_base_addr b87fc000 ver 1:0 cap 8d2078c106f0466 ecap f020df
    [Sat Oct  9 08:57:01 2021] DMAR: DRHD base: 0x000000c5ffc000 flags: 0x0
    [Sat Oct  9 08:57:01 2021] DMAR: dmar6: reg_base_addr c5ffc000 ver 1:0 cap 8d2078c106f0466 ecap f020df
    [Sat Oct  9 08:57:01 2021] DMAR: DRHD base: 0x0000009d7fc000 flags: 0x1
    [Sat Oct  9 08:57:01 2021] DMAR: dmar7: reg_base_addr 9d7fc000 ver 1:0 cap 8d2078c106f0466 ecap f020df
    [Sat Oct  9 08:57:01 2021] DMAR: RMRR base: 0x000000402f8000 end: 0x000000482fffff
    [Sat Oct  9 08:57:01 2021] DMAR: RMRR base: 0x0000006ef60000 end: 0x0000006ef62fff
    [Sat Oct  9 08:57:01 2021] DMAR: ATSR flags: 0x0
    [Sat Oct  9 08:57:01 2021] DMAR: ATSR flags: 0x0
    //caq:下面是ir部分的开始打印,见 ir_parse_one_ioapic_scope 函数:
    [Sat Oct  9 08:57:01 2021] DMAR-IR: IOAPIC id 12 under DRHD base  0xc5ffc000 IOMMU 6//caq:注意,ir是interrupt remapping 的简写,
    [Sat Oct  9 08:57:01 2021] DMAR-IR: IOAPIC id 11 under DRHD base  0xb87fc000 IOMMU 5//caq:最后的数字是 intel_iommu.seq_id
    [Sat Oct  9 08:57:01 2021] DMAR-IR: IOAPIC id 10 under DRHD base  0xaaffc000 IOMMU 4//caq: IOAPIC id是指 enumeration_id
    [Sat Oct  9 08:57:01 2021] DMAR-IR: IOAPIC id 18 under DRHD base  0xfbffc000 IOMMU 3
    [Sat Oct  9 08:57:01 2021] DMAR-IR: IOAPIC id 17 under DRHD base  0xee7fc000 IOMMU 2
    [Sat Oct  9 08:57:01 2021] DMAR-IR: IOAPIC id 16 under DRHD base  0xe0ffc000 IOMMU 1
    [Sat Oct  9 08:57:01 2021] DMAR-IR: IOAPIC id 15 under DRHD base  0xd37fc000 IOMMU 0
    [Sat Oct  9 08:57:01 2021] DMAR-IR: IOAPIC id 8 under DRHD base  0x9d7fc000 IOMMU 7
    [Sat Oct  9 08:57:01 2021] DMAR-IR: IOAPIC id 9 under DRHD base  0x9d7fc000 IOMMU 7
    [Sat Oct  9 08:57:01 2021] DMAR-IR: HPET id 0 under DRHD base 0x9d7fc000
    [Sat Oct  9 08:57:01 2021] DMAR-IR: Queued invalidation will be enabled to support x2apic and Intr-remapping.
    [Sat Oct  9 08:57:01 2021] DMAR-IR: Enabled IRQ remapping in x2apic mode---------------关键打印,表明irq的remapping 的工作模式是 x2apic 还是 xapic
    [Sat Oct  9 08:57:02 2021] DMAR: [Firmware Bug]: RMRR entry for device 1a:00.0 is broken - applying workaround
    
    

    6、iommu_domain 与 iommu 硬件之间的关系:
    以intel 为例,我们先来看 iommu_domain 的数据结构:

    struct dmar_domain {//caq:这个直接继承 iommu_domain
    	int	nid;			/* node id */
    
    	unsigned	iommu_refcnt[DMAR_UNITS_SUPPORTED];//caq:每个domain 在 对应intel_iommu硬件中的引用计数
    					/* Refcount of devices per iommu *///caq:说明一个domain 可以包含多个iommu,特别是vm场景
    
    
    	u16		iommu_did[DMAR_UNITS_SUPPORTED];//这个domain 在 对应intel_iommu 中的id
    					/* Domain ids per IOMMU. Use u16 since
    					 * domain ids are 16 bit wide according
    					 * to VT-d spec, section 9.3 */
    
    	bool has_iotlb_device;//caq:表示这个Domain里是否有具备IO-TLB的设备
    	struct list_head devices;	/* all devices' list */
    	struct iova_domain iovad;	/* iova's that belong to this domain *///caq:属于这个dmar_domain的iova_domain
    
    	struct dma_pte	*pgd;		/* virtual address *///caq:指向了IOMMU页表的基地址是IOMMU页表的入口
    	int		gaw;		/* max guest address width */
    
    	/* adjusted guest address width, 0 is level 2 30-bit */
    	int		agaw;//caq:0代表level 2,
    
    	int		flags;		/* flags to find out type of domain *///caq:dmain 的类型也存放在这
    
    	int		iommu_coherency;/* indicate coherency of iommu access *///caq:一致性
    	int		iommu_snooping; /* indicate snooping control feature*///caq:是否嗅探总线的控制feature
    	int		iommu_count;	/* reference count of iommu */
    	int		iommu_superpage;/* Level of superpages supported:
    					   0 == 4KiB (no superpages), 1 == 2MiB,
    					   2 == 1GiB, 3 == 512GiB, 4 == 1TiB *///caq:各种大页的标志,0就是代表普通4k页
    	u64		max_addr;	/* maximum mapped address *///caq:最大映射的addr
    
    	struct iommu_domain domain;	/* generic domain data structure for
    					   iommu core */
    };
    

    iommu_refcnt 成员的数组形式,对于 DOMAIN_FLAG_VIRTUAL_MACHINE 类型的 ,一个iommu_domain 可以有多个 iommu的硬件,而对于
    其他类型,则一般是一对一的关系。

    7.iommu 设备的 attr,是指该iommu 设备抽象出来的属性,比如是否支持二级转换,pgsize 的值等

    enum iommu_attr {
    	DOMAIN_ATTR_GEOMETRY,
    	DOMAIN_ATTR_PAGING,
    	DOMAIN_ATTR_WINDOWS,
    	DOMAIN_ATTR_FSL_PAMU_STASH,
    	DOMAIN_ATTR_FSL_PAMU_ENABLE,
    	DOMAIN_ATTR_FSL_PAMUV1,
    	DOMAIN_ATTR_NESTING,	/* two stages of translation */
    	DOMAIN_ATTR_MAX,
    };
    
    

    8.iommu的 reserve type,是对dev 保留不需要映射的区域的一个类型划分。

    /* These are the possible reserved region types */
    enum iommu_resv_type {
    	/* Memory regions which must be mapped 1:1 at all times */
    	IOMMU_RESV_DIRECT,//caq:1:1 直接映射
    	/* Arbitrary "never map this or give it to a device" address ranges */
    	IOMMU_RESV_RESERVED,//caq:保留的,不要映射
    	/* Hardware MSI region (untranslated) */
    	IOMMU_RESV_MSI,//caq:硬件的 msi 区域
    	/* Software-managed MSI translation window */
    	IOMMU_RESV_SW_MSI,//caq:软件保留的msi 区域
    };
    

    9.对于iommu设备,虽然抽象出一个iommu_device,但是intel 对这个的实现是 分开的,dmar_rmrr_unit 用来描述一个iommu的硬件部分,而用 intel_iommu 来实现iommu_device,
    当然, intel_iommu 不能是空中楼阁,它会有一个指向 dmar_rmrr_unit 的指针,如下示例:

    struct intel_iommu {
    	void __iomem	*reg; /* Pointer to hardware regs, virtual addr *///caq:这个是寄存器组的虚拟地址,通过ioremap而来
    ......
            struct **iommu_device **iommu;  /* IOMMU core code handle *///caq:intel_iommu首先是一个 iommu_device,核心的是ops
    	struct dmar_drhd_unit *drhd;//caq:也有一个指向 dmar_drhd_unit 的指针,1对1------------------intel对iommu
    };
    
    

    10、如果没有iommu,能透传设备给虚机么?
    一般来说,在没有IOMMU的情况下,设备必须访问真实的物理地址HPA,而虚机可见的是GPA,
    如果让虚机填入真正的HPA,那样的话相当于虚机可以直接访问物理地址,会有安全隐患。
    所以针对没有IOMMU的情况,不能用透传的方式,对于设备的直接访问都会有VMM接管,这样就不会对虚机暴露HPA。

    11、iova_domain 是干嘛的
    iova就是va针对dma领域的一个虚拟地址的抽象,那怎么管理这些地址呢?比如哪些地址被映射过,就需要一个记录的地方,

    /* holds all the iova translations for a domain */
    struct iova_domain {//caq:用一棵红黑树来记录iova->hpa的地址翻译关系
    	spinlock_t	iova_rbtree_lock; /* Lock to protect update of rbtree *///caq:全局锁
    	struct rb_root	rbroot;		/* iova domain rbtree root */
    	struct rb_node	*cached_node;	/* Save last alloced node *///caq:最后申请的一个node
    	struct rb_node	*cached32_node; /* Save last 32-bit alloced node *///caq:最后申请的32bit一个node
    	unsigned long	granule;	/* pfn granularity for this domain *///caq:pfn粒度
    	unsigned long	start_pfn;	/* Lower limit for this domain *///caq:域内起始的pfn
    	unsigned long	dma_32bit_pfn;
    	struct iova	anchor;		/* rbtree lookup anchor */
    	struct iova_rcache rcaches[IOVA_RANGE_CACHE_MAX_SIZE];	/* IOVA range caches *///caq:iova的rang先从这个cache 中申请
    //caq:数组内是2的N次方大小的range
    	iova_flush_cb	flush_cb;	/* Call-Back function to flush IOMMU
    					   TLBs */
    
    	iova_entry_dtor entry_dtor;	/* IOMMU driver specific destructor for
    					   iova entry */
    
    	struct iova_fq __percpu *fq;	/* Flush Queue *///caq:下面这部分都是关于flush相关的
    
    	atomic64_t	fq_flush_start_cnt;	/* Number of TLB flushes that
    						   have been started */
    
    	atomic64_t	fq_flush_finish_cnt;	/* Number of TLB flushes that
    						   have been finished */
    
    	struct timer_list fq_timer;		/* Timer to regularily empty the
    						   flush-queues *///caq:定时器用来刷掉fq中的cmd
    	atomic_t fq_timer_on;			/* 1 when timer is active, 0
    						   when not */
    };
    

    很显然,不同的iommu_domain都有这么一个iova_domain,两者是1:1的关系。
    一般来说,当 iommu_domain 的类型是 IOMMU_DOMAIN_DMA 的话,从iommu_domain索引 iova_domain是放在 iova_cookie

    //caq:从驱动的dma api请求过来,完成iova的分配
    static dma_addr_t iommu_dma_alloc_iova(struct iommu_domain *domain,
    		size_t size, dma_addr_t dma_limit, struct device *dev)
    {
    	struct iommu_dma_cookie *cookie = domain->iova_cookie;
    	struct iova_domain *iovad = &cookie->iovad;//caq:iova_domain 在此
    

    11、dev怎么关联对应的 iommu 设备呢?
    不同的arch有不同的实现,对于arm smmuv3来说,

    //caq:将设备dev关联到 iommu_domain
    static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
    {
    	int ret = 0;
    	struct arm_smmu_device *smmu;
    	struct arm_smmu_domain *smmu_domain = to_smmu_domain(domain);//caq:从iommu_domain 中得到arm_smmu_domain
    	struct arm_smmu_master_data *master;
    	struct arm_smmu_strtab_ent *ste;
    
    	if (!dev->iommu_fwspec)
    		return -ENOENT;
    
    **	master = dev->iommu_fwspec->iommu_priv;**
    **	smmu = master->smmu;**
    

    对于intel来说,比较复杂,可以参照 device_to_iommu 函数的实现:

    //caq:bus和devfn是出参
    static struct intel_iommu *device_to_iommu(struct device *dev, u8 *bus, u8 *devfn)
    {
    	struct dmar_drhd_unit *drhd = NULL;
    	struct intel_iommu *iommu;
    	struct device *tmp;
    	struct pci_dev *ptmp, *pdev = NULL;
    	u16 segment = 0;
    	int i;
    
    	if (iommu_dummy(dev))//caq:该设备没有关联归属iommu,
    		return NULL;
    
    	if (dev_is_pci(dev)) {//caq:pci设备,也就是他的bus type 是pci_bus_type
    		struct pci_dev *pf_pdev;
    
    		pdev = to_pci_dev(dev);
    
    #ifdef CONFIG_X86
    		/* VMD child devices currently cannot be handled individually */
    		if (is_vmd(pdev->bus))//caq:VMD:Intel® Volume Management Device
    			return NULL;
    #endif
    
    		/* VFs aren't listed in scope tables; we need to look up
    		 * the PF instead to find the IOMMU. */
    		pf_pdev = pci_physfn(pdev);**//caq:以 pf 为dev,在drhd管理的dev中,是看不到vf的**
    		dev = &pf_pdev->dev;
    		segment = pci_domain_nr(pdev->bus);//caq:segment其实就是bus归属的domain
    	} else if (has_acpi_companion(dev))
    		dev = &ACPI_COMPANION(dev)->dev;
    
    	rcu_read_lock();
    	for_each_active_iommu(iommu, drhd) {//caq:除掉ignored 的所有 intel_iommu
    		if (pdev && segment != drhd->segment)
    			continue;
    
    		for_each_active_dev_scope(drhd->devices,
    					  drhd->devices_cnt, i, tmp) {
    			if (tmp == dev) {
    
    

    参考资料:
    http://www.intel.com/content/dam/www/public/us/en/documents/product-specifications/vt-directed-io-spec.pdf

    水平有限,如果有错误,请帮忙提醒我。如果您觉得本文对您有帮助,可以点击下面的 推荐 支持一下我。版权所有,需要转发请带上本文源地址,博客一直在更新,欢迎 关注 。
  • 相关阅读:
    最短Hamilton路径-状压dp解法
    泡芙
    斗地主
    楼间跳跃
    联合权值
    虫食算
    抢掠计划
    间谍网络
    城堡the castle
    【模板】缩点
  • 原文地址:https://www.cnblogs.com/10087622blog/p/15468851.html
Copyright © 2011-2022 走看看