第一篇:DMAR 发现 — ACPI 表的解析与 IOMMU 注册¶
源码:
drivers/iommu/intel/dmar.cdrivers/iommu/intel/iommu.c| 头文件:include/linux/dmar.h| 系列目录:Intel IOMMU 内核源码深度解析
1. 什么是 DMAR 表¶
DMAR(DMA Remapping Reporting)是 ACPI 中的一个系统描述表,由 BIOS/UEFI 在启动时构建,告知操作系统平台上有哪些 IOMMU 硬件单元及其负责的设备范围。内核通过解析 DMAR 表来发现所有 VT-d 硬件。
DMAR 表包含多种子结构,每种用 type 字段区分:
// drivers/iommu/intel/dmar.c:634-650 — parse_dmar_table() 中的回调表
static int __init parse_dmar_table(void)
{
struct dmar_res_callback cb = {
.print_entry = true,
.ignore_unhandled = true,
.arg[ACPI_DMAR_TYPE_HARDWARE_UNIT] = &drhd_count,
.cb[ACPI_DMAR_TYPE_HARDWARE_UNIT] = &dmar_parse_one_drhd, // 硬件单元
.cb[ACPI_DMAR_TYPE_RESERVED_MEMORY] = &dmar_parse_one_rmrr, // 保留内存
.cb[ACPI_DMAR_TYPE_ROOT_ATS] = &dmar_parse_one_atsr, // ATS 根端口
.cb[ACPI_DMAR_TYPE_HARDWARE_AFFINITY]= &dmar_parse_one_rhsa, // NUMA 亲和性
.cb[ACPI_DMAR_TYPE_NAMESPACE] = &dmar_parse_one_andd, // ACPI 命名设备
.cb[ACPI_DMAR_TYPE_SATC] = &dmar_parse_one_satc, // SoC ATC
};
...
}
| 结构类型 | 枚举值 | 含义 |
|---|---|---|
| DRHD — DMA Remapping Hardware Unit | ACPI_DMAR_TYPE_HARDWARE_UNIT |
IOMMU 硬件单元,包含寄存器基地址、PCI segment、设备范围 |
| RMRR — Reserved Memory Region Reporting | ACPI_DMAR_TYPE_RESERVED_MEMORY |
保留内存区域,DMA 不经过重映射(BIOS/CSM/Legacy 使用) |
| ATSR — Root Port ATS Capability | ACPI_DMAR_TYPE_ROOT_ATS |
支持 ATS(Address Translation Service)的根端口 |
| RHSA — Remapping Hardware Status Affinity | ACPI_DMAR_TYPE_HARDWARE_AFFINITY |
IOMMU 对应的 NUMA 节点 |
| ANDD — ACPI Namespace Device Declaration | ACPI_DMAR_TYPE_NAMESPACE |
非 PCI 独立设备(如 HPET)的 IOMMU 关联 |
| SATC — SoC Integrated Address Translation Cache | ACPI_DMAR_TYPE_SATC |
SoC 集成设备的 ATC 信息 |
2. 关键数据结构¶
2.1 struct dmar_drhd_unit — IOMMU 单元描述符¶
// include/linux/dmar.h:38-50
struct dmar_drhd_unit {
struct list_head list; /* 全局链表节点 */
struct acpi_dmar_header *hdr; /* ACPI 头指针 */
u64 reg_base_addr; /* MMIO 寄存器物理基地址 */
unsigned long reg_size; /* 寄存器页面大小 */
struct dmar_dev_scope *devices; /* 设备 scope 数组 */
int devices_cnt; /* scope 设备数量 */
u16 segment; /* PCI domain 号 */
u8 ignored:1; /* 是否忽略此 drhd */
u8 include_all:1; /* 是否覆盖所有本 segment 设备 */
u8 gfx_dedicated:1; /* 是否专用于集成显卡 */
struct intel_iommu *iommu; /* 指向具体 IOMMU 实例 */
};
关键字段:
reg_base_addr:IOMMU 寄存器 MMIO 区域的物理地址,从 DRHD ACPI entry 的address字段获取reg_size:寄存器区域大小 =2^N × 4KB,N 从 DRHD header 的size字段获取include_all:BIT 0 of DRHD flags。include_all=1表示此 IOMMU 负责该 PCI segment 下的所有设备(除非有更精确的 scope 匹配)segment:PCI domain 号,多 socket 系统中每个 socket 可能使用不同的 segmentdevices[]:dmar_dev_scope数组,精确描述此 IOMMU 负责的总线/设备/功能号列表
2.2 struct dmar_dev_scope — 设备范围¶
// include/linux/dmar.h:30-34
struct dmar_dev_scope {
struct device __rcu *dev; /* 指向内核 device 对象(后期填充) */
u8 bus; /* PCI 总线号 */
u8 devfn; /* PCI 设备+功能号 */
};
设备范围枚举类型(entry_type):
- ACPI_DMAR_SCOPE_TYPE_ENDPOINT:端点设备
- ACPI_DMAR_SCOPE_TYPE_BRIDGE:PCI 桥
- ACPI_DMAR_SCOPE_TYPE_IOAPIC:I/O APIC
- ACPI_DMAR_SCOPE_TYPE_HPET:高精度定时器
- ACPI_DMAR_SCOPE_TYPE_NAMESPACE:ACPI 命名空间设备
// drivers/iommu/intel/dmar.c:82-103 — dmar_alloc_dev_scope()
void *dmar_alloc_dev_scope(void *start, void *end, int *cnt)
{
while (start < end) {
scope = start;
if (scope->entry_type == ACPI_DMAR_SCOPE_TYPE_NAMESPACE ||
scope->entry_type == ACPI_DMAR_SCOPE_TYPE_ENDPOINT ||
scope->entry_type == ACPI_DMAR_SCOPE_TYPE_BRIDGE)
(*cnt)++;
else if (scope->entry_type != ACPI_DMAR_SCOPE_TYPE_IOAPIC &&
scope->entry_type != ACPI_DMAR_SCOPE_TYPE_HPET)
pr_warn("Unsupported device scope\n");
start += scope->length;
}
return kzalloc_objs(struct dmar_dev_scope, *cnt);
}
3. 全局链表的组织¶
3.1 dmar_drhd_units — 全局 DRHD 链表¶
所有解析出的 DRHD 单元都注册到一个全局链表中:
dmar_global_lock:全局读写信号量,保护 DRHD 链表及 IOMMU 配置dmar_drhd_units:所有 DRHD 单元的头节点
3.2 遍历宏¶
// include/linux/dmar.h:70-87 — 四种遍历宏
#define for_each_drhd_unit(drhd)
list_for_each_entry_rcu(drhd, &dmar_drhd_units, list, dmar_rcu_check())
#define for_each_active_drhd_unit(drhd)
list_for_each_entry_rcu(drhd, &dmar_drhd_units, list, dmar_rcu_check())
if (drhd->ignored) {} else
#define for_each_active_iommu(i, drhd)
list_for_each_entry_rcu(drhd, &dmar_drhd_units, list, dmar_rcu_check())
if (i=drhd->iommu, drhd->ignored) {} else
#define for_each_iommu(i, drhd)
list_for_each_entry_rcu(drhd, &dmar_drhd_units, list, dmar_rcu_check())
if (i=drhd->iommu, 0) {} else
for_each_drhd_unit:遍历所有 DRHD(包括 ignored)for_each_active_drhd_unit:跳过ignored=1的 DRHDfor_each_active_iommu:直接遍历活动的struct intel_iommu *指针for_each_iommu:遍历所有struct intel_iommu *
4. DMAR 表解析流程¶
4.1 dmar_table_detect — 检测 DMAR 表是否存在¶
// drivers/iommu/intel/dmar.c:568-581
static int __init dmar_table_detect(void)
{
acpi_status status = AE_OK;
/* if we could find DMAR table, then there are DMAR devices */
status = acpi_get_table(ACPI_SIG_DMAR, 0, &dmar_tbl);
if (ACPI_SUCCESS(status) && !dmar_tbl) {
pr_warn("Unable to map DMAR\n");
status = AE_NOT_FOUND;
}
return ACPI_SUCCESS(status) ? 0 : -ENOENT;
}
通过 acpi_get_table(ACPI_SIG_DMAR, ...) 请求 ACPI 子系统查找签名为 "DMAR" 的表。
4.2 parse_dmar_table — 解析所有子结构¶
// drivers/iommu/intel/dmar.c:634-679
static int __init parse_dmar_table(void)
{
struct acpi_table_dmar *dmar;
int drhd_count = 0;
int ret;
struct dmar_res_callback cb = { ... };
dmar_table_detect(); // 1. 获取 DMAR 表
dmar_tbl = tboot_get_dmar_table(dmar_tbl); // 2. TXT 安全启动校验
dmar = (struct acpi_table_dmar *)dmar_tbl;
if (!dmar) return -ENODEV;
// 3. 校验 HAW (Host Address Width)
if (dmar->width < PAGE_SHIFT - 1) {
pr_warn("Invalid DMAR haw\n");
return -EINVAL;
}
pr_info("Host address width %d\n", dmar->width + 1);
ret = dmar_walk_dmar_table(dmar, &cb);
...
}
dmar_walk_dmar_table 遍历 DMAR 表中每个子结构,分发到对应的回调:
// drivers/iommu/intel/dmar.c:583-617 — dmar_walk_remapping_entries()
for (iter = start; iter < end; iter = next) {
next = (void *)iter + iter->length;
if (iter->type >= ACPI_DMAR_TYPE_RESERVED)
continue; // 前向兼容未知类型
else if (cb->cb[iter->type])
cb->cb[iter->type](iter, cb->arg[iter->type]);
}
4.3 dmar_parse_one_drhd — 解析一个 DRHD¶
// drivers/iommu/intel/dmar.c:408-456
static int dmar_parse_one_drhd(struct acpi_dmar_header *header, void *arg)
{
struct acpi_dmar_hardware_unit *drhd;
struct dmar_drhd_unit *dmaru;
int ret;
drhd = (struct acpi_dmar_hardware_unit *)header;
dmaru = dmar_find_dmaru(drhd);
if (dmaru)
goto out; // 已注册则跳过
dmaru = kzalloc(sizeof(*dmaru) + header->length, GFP_KERNEL);
// ...
dmaru->hdr = (void *)(dmaru + 1);
memcpy(dmaru->hdr, header, header->length);
dmaru->reg_base_addr = drhd->address;
dmaru->segment = drhd->segment;
dmaru->reg_size = 1UL << (drhd->size + 12); // 2^N × 4KB
dmaru->include_all = drhd->flags & 0x1;
dmaru->devices = dmar_alloc_dev_scope(...); // 分配设备 scope 数组
ret = alloc_iommu(dmaru); // 分配 struct intel_iommu
dmar_register_drhd_unit(dmaru); // 注册到全局链表
...
}
5. DRHD 注册策略¶
// drivers/iommu/intel/dmar.c:70-80
static void dmar_register_drhd_unit(struct dmar_drhd_unit *drhd)
{
/*
* add INCLUDE_ALL at the tail, so scan the list will find it at
* the very end.
*/
if (drhd->include_all)
list_add_tail_rcu(&drhd->list, &dmar_drhd_units);
else
list_add_rcu(&drhd->list, &dmar_drhd_units);
}
设计思想:
- 非 include_all 的 DRHD 加入链表头部(list_add_rcu),匹配时先被扫描
- include_all 的 DRHD 加入链表尾部(list_add_tail_rcu),作为"兜底"选项
- 设备查找 IOMMU 时,先精确匹配 scope 列表,找不到再用 include_all
dmar_drhd_units 全局链表:
HEAD → [DRHD-A: include_all=0, scope: 0:1.0, 0:2.0]
→ [DRHD-B: include_all=0, scope: 0:3.0]
→ [DRHD-C: include_all=1, seg=0] ← 兜底,最后匹配
→ [DRHD-D: include_all=0, scope: 1:0.0]
→ [DRHD-E: include_all=1, seg=1] ← 兜底
6. RMRR — 保留内存区域¶
RMRR 描述 BIOS/固件使用的、不能被 DMA 重映射的内存区域。典型用途:集成显卡的 stolen memory、CSM 兼容内存。
// drivers/iommu/intel/dmar.c:308 — dmar_parse_one_rmrr()
static int dmar_parse_one_rmrr(struct acpi_dmar_header *header, void *arg)
{
struct acpi_dmar_reserved_memory *rmrr;
struct dmar_rmrr_unit *rmrru;
rmrr = (struct acpi_dmar_reserved_memory *)header;
rmrru = kzalloc(sizeof(*rmrru), GFP_KERNEL);
rmrru->hdr = rmrr;
rmrru->base_address = rmrr->base_address;
rmrru->end_address = rmrr->end_address;
rmrru->devices = dmar_alloc_dev_scope(...); // 哪些设备受此 RMRR 约束
list_add(&rmrru->list, &dmar_rmrr_units);
...
}
RMRR 中的设备不能对其 reserved range 的 DMA 请求进行重映射,内核必须设置 1:1 映射(identity mapping)。
典型 RMRR 示例¶
RMRR base: 0xBD000000 ~ 0xBFFFFFFF (48MB)
Devices: 00:02.0 (集成显卡)
→ 集成显卡对 0xBD0_0000 ~ 0xBFF_FFFF 的 DMA 不经过 IOMMU 转译
7. ATSR — Root Port 的 ATS 能力¶
ATSR(ATS Required)标记哪些根端口下挂的设备支持 PCIe ATS(Address Translation Services)。ATS 允许设备缓存 IOVA→HPA 的转换结果,减少 IOMMU 查询延迟。
// drivers/iommu/intel/dmar.c:347 — dmar_parse_one_atsr()
static int dmar_parse_one_atsr(struct acpi_dmar_header *header, void *arg)
{
struct acpi_dmar_atsr *atsr;
struct dmar_atsr_unit *atsru;
atsr = (struct acpi_dmar_atsr *)header;
atsru = kzalloc(sizeof(*atsru), GFP_KERNEL);
atsru->hdr = atsr;
// ALL_PORTS flag: 此端口下的所有设备都支持 ATS
atsru->include_all = atsr->flags & 0x1;
atsru->devices = dmar_alloc_dev_scope(...);
list_add(&atsru->list, &dmar_atsr_units);
...
}
ATSR 与后续章节中的 设备 TLB (devTLB) 刷新 直接相关 — 有 ATS 能力的设备必须在 IOTLB Invalidation 时同步刷新 devTLB。
8. RHSA — NUMA 亲和性¶
// drivers/iommu/intel/dmar.c:496 — dmar_parse_one_rhsa()
static int dmar_parse_one_rhsa(struct acpi_dmar_header *header, void *arg)
{
struct acpi_dmar_rhsa *rhsa;
struct dmar_drhd_unit *drhd;
rhsa = (struct acpi_dmar_rhsa *)header;
for_each_drhd_unit(drhd) {
if (drhd->reg_base_addr == rhsa->base_address) {
int node = acpi_map_pxm_to_online_node(rhsa->proximity_domain);
drhd->iommu->node = node;
break;
}
}
return 0;
}
RHSA 通过 proximity_domain 关联到 ACPI SRAT 表中的 NUMA 节点,确保 IOMMU 的 DMA 缓冲区分配从本地 NUMA 节点取内存。
9. ANDD — ACPI 命名空间设备¶
// drivers/iommu/intel/dmar.c:467 — dmar_parse_one_andd()
static int dmar_parse_one_andd(struct acpi_dmar_header *header, void *arg)
{
struct acpi_dmar_andd *andd = (void *)header;
// 检查 device_name 是否为 NUL-terminated
if (strnlen(andd->device_name, header->length - 8) == header->length - 8) {
pr_warn(FW_BUG "ANDD object name is not NUL-terminated\n");
}
...
}
ANDD 将非 PCI 设备(如平台设备)关联到 IOMMU,这在 SoC 集成场景中常见。
10. SATC — SoC ATC¶
// drivers/iommu/intel/dmar.c:547 — dmar_parse_one_satc()
static int dmar_parse_one_satc(struct acpi_dmar_header *header, void *arg)
{
struct acpi_dmar_satc *satc = (struct acpi_dmar_satc *)header;
pr_info("SATC flags: 0x%x\n", satc->flags);
...
}
SoC ATC 描述集成在 SoC 中的设备端地址转换缓存。
11. 设备 → IOMMU 的查找¶
当内核需要为一个 PCI 设备找到对应的 IOMMU 时:
// drivers/iommu/intel/iommu.c:457-516 — device_lookup_iommu()
static struct intel_iommu *device_lookup_iommu(struct device *dev, u8 *bus, u8 *devfn)
{
struct dmar_drhd_unit *drhd = NULL;
struct pci_dev *pdev = NULL;
struct intel_iommu *iommu;
struct device *tmp;
u16 segment = 0;
int i;
if (dev_is_pci(dev)) {
struct pci_dev *pf_pdev;
pdev = pci_real_dma_dev(to_pci_dev(dev));
/* VFs aren't listed in scope tables; we need to look up
* the PF instead to find the IOMMU. */
pf_pdev = pci_physfn(pdev);
dev = &pf_pdev->dev; // SR-IOV VF → 使用 PF 查找
segment = pci_domain_nr(pdev->bus);
} else if (has_acpi_companion(dev))
dev = &ACPI_COMPANION(dev)->dev;
rcu_read_lock();
for_each_iommu(iommu, drhd) {
if (pdev && segment != drhd->segment)
continue;
// 1. 精确匹配 scope 列表
for_each_active_dev_scope(drhd->devices, drhd->devices_cnt, i, tmp) {
if (tmp == dev) {
if (pdev && pdev->is_virtfn)
goto got_pdev;
if (bus && devfn) {
*bus = drhd->devices[i].bus;
*devfn = drhd->devices[i].devfn;
}
goto out;
}
// 2. 下游桥设备
if (is_downstream_to_pci_bridge(dev, tmp))
goto got_pdev;
}
// 3. include_all 兜底
if (pdev && drhd->include_all) {
got_pdev:
if (bus && devfn) {
*bus = pdev->bus->number;
*devfn = pdev->devfn;
}
goto out;
}
}
...
}
查找策略:
1. 精确匹配:遍历每个 DRHD 的 devices[] scope,匹配 BDF 或 ACPI companion
2. 下游桥匹配:设备在 scope 中的 bridge 下游,则也归此 IOMMU
3. include_all 兜底:段内找不到精确匹配时用 include_all 的 IOMMU
4. SR-IOV 特殊处理:VF 不在 scope 表中,通过 PF(pci_physfn)查找
12. 完整初始化序列¶
// drivers/iommu/intel/iommu.c:2552-2631 — intel_iommu_init()
int __init intel_iommu_init(void)
{
int ret = -ENODEV;
struct dmar_drhd_unit *drhd;
struct intel_iommu *iommu;
// 检查强制开启(TXT/tboot 安全启动)
force_on = (!intel_iommu_tboot_noforce && tboot_force_iommu()) ||
platform_optin_force_iommu();
down_write(&dmar_global_lock);
if (dmar_table_init()) { // ① 解析 DMAR 表
if (force_on) panic(...);
goto out_free_dmar;
}
if (dmar_dev_scope_init() < 0) { // ② 初始化设备 scope
if (force_on) panic(...);
goto out_free_dmar;
}
up_write(&dmar_global_lock);
dmar_register_bus_notifier(); // ③ 注册 PCI 总线通知器
down_write(&dmar_global_lock);
if (!no_iommu)
intel_iommu_debugfs_init(); // ④ debugfs 初始化
if (no_iommu || dmar_disabled) {
intel_disable_iommus(); // ⑤ 关闭所有 IOMMU(kexec 场景)
goto out_free_dmar;
}
// ⑥ 检查可选项
if (list_empty(&dmar_rmrr_units))
pr_info("No RMRR found\n");
if (list_empty(&dmar_atsr_units))
pr_info("No ATSR found\n");
init_no_remapping_devices();
ret = init_dmars(); // ⑦ 初始化所有 IOMMU 硬件
if (ret) { ... }
up_write(&dmar_global_lock);
...
}
完整流程图:
intel_iommu_init()
│
├── dmar_table_init()
│ └── parse_dmar_table()
│ ├── dmar_table_detect() → acpi_get_table("DMAR")
│ ├── dmar_walk_dmar_table()
│ │ ├── dmar_parse_one_drhd() → 注册 DRHD → dmar_drhd_units 链表
│ │ ├── dmar_parse_one_rmrr() → 注册 RMRR → dmar_rmrr_units 链表
│ │ ├── dmar_parse_one_atsr() → 注册 ATSR → dmar_atsr_units 链表
│ │ ├── dmar_parse_one_rhsa() → NUMA 节点绑定
│ │ ├── dmar_parse_one_andd() → ACPI 设备绑定
│ │ └── dmar_parse_one_satc() → SoC ATC 绑定
│ └── dmar_validate_drhd() → 验证寄存器可访问
│
├── dmar_dev_scope_init() → 初始化设备 scope(ACPI 设备查找)
├── dmar_register_bus_notifier() → 监听 PCI 设备热插拔
├── init_dmars() → 初始化每个 IOMMU 硬件
│ ├── intel_iommu_setup_hardware() → 配置寄存器(RTADDR/CCMD/GCMD)
│ ├── intel_iommu_init_qi() → 初始化 Queued Invalidation
│ ├── intel_svm_check() → SVA 兼容性检查
│ └── iommu_device_register() → 注册到 IOMMU 核心层
│
└── up_write(&dmar_global_lock)
13. DMAR 表到 IOMMU 对象的关系¶
ACPI DMAR Table (内存中)
│
├── DRHD Entry #0 (ACPI_DMAR_HARDWARE_UNIT)
│ ├── address = 0xFED90000 → iommu->reg_phys
│ ├── segment = 0 → iommu->segment
│ ├── size = 1 → reg_size = 2^1 × 4KB = 8KB
│ ├── flags/include_all = 0
│ └── Device Scope:
│ ├── Endpoint: bus=0, dev=2, func=0 (显卡)
│ └── Endpoint: bus=0, dev=3, func=0 (网卡)
│
├── DRHD Entry #1
│ ├── address = 0xFED91000
│ ├── segment = 1
│ └── flags/include_all = 1
│
├── RMRR Entry: base=0xBD000000, end=0xBFFFFFFF, target: 0:2.0
├── ATSR Entry: root port 0:1.0
└── RHSA Entry: DRHD=0xFED90000, NUMA node=0
│
▼
struct dmar_drhd_unit (dmar.h:38) struct intel_iommu (iommu.h:682)
┌───────────────────────────┐ ┌──────────────────────────────┐
│ list (→全局链表) │ │ reg → MMIO 虚拟地址 │
│ hdr → ACPI 结构 │ │ reg_phys = 0xFED90000 │
│ reg_base_addr ← 硬件地址 │ ──→ │ cap/ecap/vccap │
│ reg_size ← 硬件计算 │ │ gcmd = TE|EAFL|SRTP|SFL|WBF │
│ devices[] ← scope 设备 │ │ root_entry → Root Table │
│ devices_cnt │ │ qi → Queued Invalidation │
│ segment = 0 │ │ ir_table → IRTE Table │
│ include_all = 0/1 │ │ device_rbtree ← 跟踪所有设备 │
│ gfx_dedicated │ │ segment = 0 │
│ iommu ────────────────────┘ │ drhd ──────────→ 回指 │
└───────────────────────────┘ │ node ← NUMA 节点 │
└──────────────────────────────┘
14. 锁序¶
DMAR 子系统使用 dmar_global_lock(rwsem)作为顶层保护:
dmar_global_lock (rwsem)
│
├── 保护 dmar_drhd_units 链表
├── 保护 dmar_rmrr_units 链表
├── 保护 dmar_atsr_units 链表
├── 保护 IOMMU register 操作
│
└── RCU 读端:for_each_drhd_unit/for_each_iommu
不持锁时读需要 rcu_read_lock()
15. 关键行号速查¶
| 符号 | 文件 | 行号 | 说明 |
|---|---|---|---|
LIST_HEAD(dmar_drhd_units) |
dmar.c | 61 | 全局 DRHD 链表 |
DECLARE_RWSEM(dmar_global_lock) |
dmar.c | 60 | 全局锁 |
dmar_register_drhd_unit |
dmar.c | 70 | DRHD 注册函数 |
dmar_alloc_dev_scope |
dmar.c | 82 | 设备 scope 分配 |
dmar_parse_one_drhd |
dmar.c | 408 | 单个 DRHD 解析 |
dmar_parse_one_rmrr |
dmar.c | 308 | RMRR 解析 |
dmar_parse_one_atsr |
dmar.c | 347 | ATSR 解析 |
dmar_parse_one_rhsa |
dmar.c | 496 | RHSA 解析 |
dmar_parse_one_andd |
dmar.c | 467 | ANDD 解析 |
dmar_parse_one_satc |
dmar.c | 547 | SATC 解析 |
dmar_table_detect |
dmar.c | 568 | DMAR 表检测 |
parse_dmar_table |
dmar.c | 634 | 表解析 |
dmar_table_init |
dmar.c | 844 | 表初始化入口 |
for_each_drhd_unit |
dmar.h | 70 | 遍历宏 |
for_each_active_iommu |
dmar.h | 79 | 活跃 IOMMU 遍历宏 |
device_lookup_iommu |
iommu.c | 457 | 设备→IOMMU 查找 |
intel_iommu_init |
iommu.c | 2552 | 主初始化入口 |
下一篇文章¶
第二篇:IOMMU 引擎 — 硬件寄存器、关键数据结构与初始化