跳转至

第二篇:IOMMU 引擎 — 硬件寄存器、关键数据结构与初始化

源码:drivers/iommu/intel/iommu.h drivers/iommu/intel/iommu.c | 系列目录:Intel IOMMU 内核源码深度解析


1. 核心数据结构全景

VT-d 的代码围绕几个中心数据结构展开,理解它们的层次关系是掌握全部代码的前提。

1.1 struct intel_iommu — IOMMU 实例

// drivers/iommu/intel/iommu.h:682-737
struct intel_iommu {
    void __iomem    *reg;           /* MMIO 寄存器虚拟地址               */
    u64             reg_phys;       /* 寄存器组物理地址                  */
    u64             reg_size;       /* 寄存器组大小                      */
    u64             cap;            /* 能力寄存器值                       */
    u64             ecap;           /* 扩展能力寄存器值                   */
    u64             vccap;          /* 虚拟命令能力                       */
    u64             ecmdcap[DMA_MAX_NUM_ECMDCAP]; /* 扩展命令能力        */
    u32             gcmd;           /* GCMD 缓存值 (TE, EAFL, SRTP...)  */
    raw_spinlock_t  register_lock;  /* 寄存器访问保护                    */
    int             seq_id;         /* IOMMU 序列号                      */
    int             agaw;           /* 实际 AGAW                         */
    int             msagaw;         /* 最大支持的 AGAW                    */
    unsigned int    irq, pr_irq, perf_irq;  /* 三类中断线                */
    u16             segment;        /* PCI segment                       */
    unsigned char   name[16];       /* 设备名称                          */

    /* 域管理 */
    struct mutex    did_lock;
    struct ida      domain_ida;      /* 域 ID 分配器                    */
    unsigned long   *copied_tables;  /* 已拷贝 context 表位图            */
    spinlock_t      lock;            /* context/domain id 保护           */
    struct root_entry *root_entry;   /* Root Table 虚拟地址              */

    struct iommu_flush flush;

    /* 页面请求 */
    struct page_req_dsc *prq;        /* Page Request Queue               */
    unsigned char   prq_name[16];
    unsigned long   prq_seq_number;
    struct completion prq_complete;
    struct iopf_queue *iopf_queue;
    unsigned char   iopfq_name[16];
    struct mutex    iopf_lock;

    /* Queued Invalidation */
    struct q_inval  *qi;            /* QI 队列                           */

    u32 iommu_state[MAX_SR_DMAR_REGS];  /* 休眠/恢复状态                */

    /* 设备跟踪 */
    struct rb_root  device_rbtree;   /* 所有 probed 设备的红黑树         */
    spinlock_t      device_rbtree_lock;

    /* 中断重映射 */
    struct ir_table *ir_table;       /* IRTE 表                          */
    struct irq_domain *ir_domain;

    struct iommu_device iommu;       /* IOMMU 核心层句柄                  */
    int             node;            /* NUMA 节点                         */
    u32             flags;           /* 软件标志                          */
    struct dmar_drhd_unit *drhd;     /* 回指 DRHD                        */
    void            *perf_statistic;
    struct iommu_pmu *pmu;           /* 性能计数器                        */
};

每个 intel_iommu 对应一个物理 VT-d 硬件单元,通过 drhd 指针回指到 DMAR 解析出的 dmar_drhd_unit

1.2 struct dmar_domain — DMA 地址域

// drivers/iommu/intel/iommu.h:592-639
struct dmar_domain {
    union {
        struct iommu_domain domain;     /* IOMMU 核心层 domain */
        struct pt_iommu iommu;
        struct pt_iommu_x86_64 fspt;    /* 第一阶段(first-stage)页表 */
        struct pt_iommu_vtdss sspt;     /* 第二阶段(second-stage)页表 */
    };

    struct xarray iommu_array;          /* 已绑定的 IOMMU 数组 */

    u8 force_snooping:1;
    u8 dirty_tracking:1;               /* 脏页面跟踪 */
    u8 nested_parent:1;                 /* 是否有嵌套域以其为 S2 */
    u8 iotlb_sync_map:1;               /* 建立映射时是否需要 flush IOTLB */

    spinlock_t lock;                    /* 设备列表保护 */
    struct list_head devices;          /* 设备链表 */
    struct list_head dev_pasids;       /* 附加的 PASID 链表 */

    spinlock_t cache_lock;             /* cache_tag 列表保护 */
    struct list_head cache_tags;       /* 缓存标签链表 */
    struct qi_batch *qi_batch;         /* 批量 QI 描述符 */

    union {
        /* DMA 重映射域 */
        struct {
            spinlock_t s1_lock;
            struct list_head s1_domains;
        };
        /* 嵌套用户域 */
        struct {
            struct dmar_domain *s2_domain;    /* S2 父域 */
            struct iommu_hwpt_vtd_s1 s1_cfg;
            struct list_head s2_link;
        };
        /* SVA 域 */
        struct {
            struct mm_struct *mm;
        };
    };
};

关键转换宏:

// iommu.h:784-786
static inline struct dmar_domain *to_dmar_domain(struct iommu_domain *dom)
{
    return container_of(dom, struct dmar_domain, domain);
}

Domain ID 分配说明(iommu.h:789-804): - Domain ID 0:保留给 caching mode 的 invalid translation,非分配标记 - Domain ID 1:保留给 first-level/pass-through/nested 模式(FLPT_DEFAULT_DID) - 可用域 ID:从 2 开始 — 每个 IOMMU 独立维护 domain_ida

1.3 struct device_domain_info — 设备-域绑定

// drivers/iommu/intel/iommu.h:740-765
struct device_domain_info {
    struct list_head link;       /* 域内兄弟链表                    */
    u32 segment;                 /* PCI segment                     */
    u8 bus;                      /* PCI 总线号                      */
    u8 devfn;                    /* PCI devfn                       */
    u16 pfsid;                   /* SRIOV PF source ID (DIT 模式)  */
    u8 pasid_supported:3;
    u8 pasid_enabled:1;
    u8 pri_supported:1;
    u8 pri_enabled:1;
    u8 ats_supported:1;
    u8 ats_enabled:1;
    u8 dtlb_extra_inval:1;       /* quirk: 需要额外 devTLB 刷新    */
    u8 domain_attached:1;
    u8 ats_qdep;                 /* ATS 队列深度                    */
    unsigned int iopf_refcount;
    struct device *dev;          /* 指向设备 (PCI bridge 为 NULL)   */
    struct intel_iommu *iommu;  /* 所属 IOMMU                      */
    struct dmar_domain *domain;  /* 所属域                          */
    struct pasid_table *pasid_table; /* PASID 表                    */
    struct rb_node node;         /* IOMMU device_rbtree 节点        */
#ifdef CONFIG_INTEL_IOMMU_DEBUGFS
    struct dentry *debugfs_dentry;
#endif
};

每个设备通过 device_domain_info 绑定到特定 IOMMU 和域,同时携带 ATS/PRI/PASID 能力标志。


2. 页表层级数据结构

2.1 struct root_entry — 根表项

// drivers/iommu/intel/iommu.h:550-553
/*
 * 0: Present
 * 1-11: Reserved
 * 12-63: Context Ptr (12 - (haw-1))
 * 64-127: Reserved
 */
struct root_entry {
    u64     lo;
    u64     hi;
};

每个 root_entry 对应一个 PCI bus number(256 个 root_entry 覆盖 0-255 bus)。root_entry.lo[12:63] 指向该 bus 的 context table 物理地址。

Scalable mode 下 root_entry 用法不同 — 同时包含 lower 和 upper context table 指针。

2.2 struct context_entry — 上下文表项

// drivers/iommu/intel/iommu.h:566-569
/*
 * low 64 bits:
 * 0: present
 * 1: fault processing disable
 * 2-3: translation type
 * 12-63: address space root
 * high 64 bits:
 * 0-2: address width
 * 3-6: aval
 * 8-23: domain id
 */
struct context_entry {
    u64 lo;
    u64 hi;
};

Context entry 的 translation type(iommu.h:60-63): - CONTEXT_TT_MULTI_LEVEL (0):标准多级 DMA 页表 - CONTEXT_TT_DEV_IOTLB (1):使用设备 IOTLB 的旁路模式 - CONTEXT_TT_PASS_THROUGH (2):直通模式(不转换) - CONTEXT_PASIDE (bit 3):PASID 模式(允许 per-PASID 页表)

Context entry 操作宏:

// iommu.h:865-867 — 检查 present
static inline bool context_present(struct context_entry *context)
{
    return (context->lo & 1);
}

// iommu.h:925-930 — 设置 translation type
static inline void context_set_translation_type(struct context_entry *context,
                                                unsigned long value)
{
    context->lo &= ~((u64)0x3 << 2);
    context->lo |= (value & 0x3) << 2;
}

// iommu.h:945-949 — 设置 domain id
static inline void context_set_domain_id(struct context_entry *context,
                                         unsigned long value)
{
    context->hi |= (value & GENMASK_ULL(15, 0)) << 8;
}

// iommu.h:951-954 — 设置 PASID enable
static inline void context_set_pasid(struct context_entry *context)
{
    context->lo |= CONTEXT_PASIDE;
}

2.3 struct dma_pte — DMA 页表项

// drivers/iommu/intel/iommu.h:841-843
/*
 * 0: readable
 * 1: writable
 * 2-6: reserved
 * 7: super page  (bit 7 标记大页)
 * 8-10: available
 * 11: snoop behavior
 * 12-63: Host physical address
 */
struct dma_pte {
    u64 val;
};

// iommu.h:845-853 — 读取物理地址
static inline u64 dma_pte_addr(struct dma_pte *pte)
{
    return pte->val & VTD_PAGE_MASK;
}

// iommu.h:855-858 — 检查 present
static inline bool dma_pte_present(struct dma_pte *pte)
{
    return (pte->val & 3) != 0;    // bit 0-1 不全为 0 即 present
}

// iommu.h:860-863 — 检查超级页
static inline bool dma_pte_superpage(struct dma_pte *pte)
{
    return (pte->val & DMA_PTE_LARGE_PAGE);
}

3. 页表地址转换层级

VT-d 页表走查从 root_entry 开始,经过 context_entry 后进入多级 DMA 页表:

Device → DMA Request (IOVA)
├── PCI Bus# ──→ Root Table (256 entries, 4KB aligned)
│   │               [bus 0] root_entry.lo → context table
│   │               [bus 1] root_entry
│   │               ...
│   │
│   └── Context Table (256 entries per bus = 14-bit devfn)
│       │               [devfn=N] context_entry
│       │                   ├── translation_type = CONTEXT_TT_MULTI_LEVEL
│       │                   ├── domain_id
│       │                   ├── address_width
│       │                   └── address_space_root → DMA Page Table
│       │
│       └── 3-Level DMA Page Table (standard, AGAW ≤ 48-bit)
│           │
│           │  dma_pte[level=2] → 512 entries (9 bits ea.)
│           │       │   addr[47:39] index into L2
│           │       │
│           │       └── dma_pte[level=1] → 512 entries
│           │               │   addr[38:30] index into L1
│           │               │
│           │               └── dma_pte[level=0] → 512 entries
│           │                       │   addr[29:21] index into L0
│           │                       │   HPA = pte[12:63] | addr[20:0]
│           │
│           └── 超级页 shortcut:
│               L2 superpage: 1GB (bit 7 set in L2 pte)
│               L1 superpage: 2MB (bit 7 set in L1 pte)
└── 5-Level DMA Page Table (LA57, AGAW = 57-bit)
        dma_pte[level=4] → L4 (9 bits, addr[56:48])
            └── dma_pte[level=3] → ... same as 3-level from here

AGAW → Level 转换 (iommu.h:875-878):

static inline int agaw_to_level(int agaw)
{
    return agaw + 2;  // AGAW 30 → 4 levels (32-bit), AGAW 39 → 5 levels (48-bit)
}

LEVEL_STRIDE = 9 (iommu.h:870) 意味着每层覆盖 9 位地址 (512 entries × 4KB = 2MB per page table)。


4. MMIO 寄存器映射

VT-d 硬件寄存器通过 MMIO 访问,基础定义在 iommu.h:65-143

Offset  Register               说明
─────────────────────────────────────────────────────────────
0x00    DMAR_VER_REG          版本号 (MAJ.MIN)
0x08    DMAR_CAP_REG          能力寄存器 (64-bit)
0x10    DMAR_ECAP_REG         扩展能力寄存器 (64-bit)
0x18    DMAR_GCMD_REG         全局命令寄存器
0x1C    DMAR_GSTS_REG         全局状态寄存器
0x20    DMAR_RTADDR_REG       根表地址 (Root Table Address)
0x28    DMAR_CCMD_REG         上下文命令寄存器
0x34    DMAR_FSTS_REG         故障状态寄存器
0x38    DMAR_FECTL_REG        故障控制寄存器
0x3C    DMAR_FEDATA_REG       故障事件数据
0x40    DMAR_FEADDR_REG       故障事件地址 (基址)
0x44    DMAR_FEUADDR_REG      故障事件上地址
0x64    DMAR_PMEN_REG         PMR 使能
0x68-0x78 DMAR_PLMBASE/PLMLIMIT/PHMBASE/PHMLIMIT  PMR 范围
0x80    DMAR_IQH_REG          QI 队列头
0x88    DMAR_IQT_REG          QI 队列尾
0x90    DMAR_IQA_REG          QI 队列地址
0x9C    DMAR_ICS_REG          QI 完成状态
0xB0    DMAR_IQER_REG         QI 错误记录
0xB8    DMAR_IRTA_REG         中断重映射表地址
0xC0    DMAR_PQH_REG          页面请求队列头
0xC8    DMAR_PQT_REG          页面请求队列尾
0xD0    DMAR_PQA_REG          页面请求队列地址
0xDC    DMAR_PRS_REG          页面请求状态
0xE0    DMAR_PECTL_REG        页面请求事件控制
0x100+  DMAR_MTRRCAP_REG      MTRR 能力
0x300   DMAR_PERFCAP_REG      性能计数器能力 (VT-d 4.0+)
0x380   DMAR_PERFEVNTCAP_REG  性能事件能力
0x400   DMAR_ECMD_REG         扩展命令寄存器

4.1 GCMD (Global Command) 位定义

// iommu.h:288-305
#define DMA_GCMD_TE     BIT(31)   // Translation Enable
#define DMA_GCMD_SRTP   BIT(30)   // Set Root Table Pointer
#define DMA_GCMD_SFL    BIT(29)   // Set Fault Log
#define DMA_GCMD_EAFL   BIT(28)   // Enable Advanced Fault Logging
#define DMA_GCMD_WBF    BIT(27)   // Write Buffer Flush
#define DMA_GCMD_QIE    BIT(26)   // Queued Invalidation Enable
#define DMA_GCMD_SIRTP  BIT(24)   // Set Interrupt Remap Table Pointer
#define DMA_GCMD_IRE    BIT(25)   // Interrupt Remapping Enable
#define DMA_GCMD_CFI    BIT(23)   // Compatibility Format Interrupt

4.2 GSTS (Global Status) 位定义

// iommu.h:307-325
#define DMA_GSTS_TES    BIT(31)   // Translation Enable Status
#define DMA_GSTS_RTPS   BIT(30)   // Root Table Pointer Status
#define DMA_GSTS_FLS    BIT(29)   // Fault Log Status
#define DMA_GSTS_AFLS   BIT(28)   // Advanced Fault Logging Status
#define DMA_GSTS_WBFS   BIT(27)   // Write Buffer Flush Status
#define DMA_GSTS_QIES   BIT(26)   // Queued Invalidation Enable Status
#define DMA_GSTS_IRTPS  BIT(24)   // Interrupt Remap Table Pointer Status
#define DMA_GSTS_IRES   BIT(25)   // Interrupt Remap Enable Status
#define DMA_GSTS_CFIS   BIT(23)   // Compatibility Format Interrupt Status

5. CAP / ECAP 寄存器解码

CAP 寄存器(iommu.h:157-184)编码 IOMMU 的能力:

CAP 位 含义
cap_esrtps(c) 63 Enhanced Set Root Table Pointer Support
cap_fl5lp_support(c) 60 5-level paging (LA57) 支持
cap_pi_support(c) 59 Posted Interrupt 支持
cap_fl1gp_support(c) 56 1GB 第一级大页支持
cap_read_drain(c) 55 Read drain 支持
cap_write_drain(c) 54 Write drain 支持
cap_max_amask_val(c) 48-53 最大地址掩码值 (for page-selective invalidation)
cap_num_fault_regs(c) 40-47 故障记录寄存器数量
cap_pgsel_inv(c) 39 Page-selective invalidation 支持
cap_super_page_val(c) 34-37 超级页位图 (bit0=4KB, bit1=2MB, bit2=1GB)
cap_mgaw(c) 16-21 最大 Guest Address Width (MGAW = value + 1)
cap_sagaw(c) 8-12 支持的 AGAW 位图
cap_caching_mode(c) 7 Caching mode (需要 cache flush)
cap_rwbf(c) 4 Read/Write Buffer Flush 需要
cap_afl(c) 3 Advanced Fault Logging 支持
cap_ndoms(c) 0-2 最大 domain 数量 = 2^(4+2×value)

ECAP 寄存器(iommu.h:189-218)编码扩展能力:

ECAP 位 含义
ecap_pms(e) 51 Performance Monitoring Support
ecap_rps(e) 49 RID-PASID Support
ecap_smpwc(e) 48 Scalable Mode PASID Write Clear
ecap_flts(e) 47 First Level Translation Support
ecap_slts(e) 46 Second Level Translation Support
ecap_smts(e) 43 Scalable Mode Translation Support
ecap_dit(e) 41 Device IOTLB Throttling
ecap_pds(e) 42 Page-request Drain Support
ecap_pasid(e) 40 PASID Support
ecap_pss(e) 35-39 PASID Size Supported (2^pss bit = max PASID entries)
ecap_prs(e) 29 Page Request Support
ecap_nest(e) 26 Nested Translation Support
ecap_mts(e) 25 Memory Type Support
ecap_coherent(e) 0 Cache Coherency
ecap_qis(e) 1 Queued Invalidation Support
ecap_dev_iotlb_support(e) 2 Device IOTLB Support
ecap_ir_support(e) 3 Interrupt Remapping Support
ecap_eim_support(e) 4 Extended Interrupt Mode (x2APIC)
ecap_pass_through(e) 6 Pass Through Support
ecap_sc_support(e) 7 Snoop Control Support
ecap_max_handle_mask(e) 20-23 Max Invalidation Handle Mask
ecap_iotlb_offset(e) 8-17 IOTLB 寄存器偏移

6. Queued Invalidation 数据结构

6.1 struct qi_desc — 队列条目

// drivers/iommu/intel/iommu.h:469-474
struct qi_desc {
    u64 qw0;    /* 类型 + 粒度 + DID + SID */
    u64 qw1;    /* 地址 + 粒度 */
    u64 qw2;    /* 保留 / PASID 扩展 */
    u64 qw3;    /* 保留 / 包间类数据 */
};

6.2 struct q_inval — QI 队列

// drivers/iommu/intel/iommu.h:476-483
struct q_inval {
    raw_spinlock_t  q_lock;        /* 队列锁 */
    void            *desc;         /* 循环缓冲区 (物理连续性) */
    int             *desc_status;  /* 描述符完成状态数组 */
    int             free_head;     /* 第一个空闲槽 */
    int             free_tail;     /* 最后一个空闲槽 */
    int             free_cnt;      /* 空闲槽计数 */
};

6.3 struct qi_batch — 批量提交

// drivers/iommu/intel/iommu.h:586-590
#define QI_MAX_BATCHED_DESC_COUNT 16

struct qi_batch {
    struct qi_desc descs[QI_MAX_BATCHED_DESC_COUNT];
    unsigned int index;
};

6.4 struct iommu_flush — IOMMU flush 方法

// drivers/iommu/intel/iommu.h:512-517
struct iommu_flush {
    void (*flush_context)(struct intel_iommu *iommu, u16 did,
                         u16 sid, u8 fm, u64 type);
    void (*flush_iotlb)(struct intel_iommu *iommu, u16 did, u64 addr,
                       unsigned int size_order, u64 type);
};

7. 设备 Probe 全流程

7.1 intel_iommu_probe_device — 设备探测

// drivers/iommu/intel/iommu.c:3229-3322
static struct iommu_device *intel_iommu_probe_device(struct device *dev)
{
    struct pci_dev *pdev = dev_is_pci(dev) ? to_pci_dev(dev) : NULL;
    struct device_domain_info *info;
    struct intel_iommu *iommu;
    u8 bus, devfn;
    int ret;

    // 1. 找到设备对应的 IOMMU
    iommu = device_lookup_iommu(dev, &bus, &devfn);
    if (!iommu || !iommu->iommu.ops)
        return ERR_PTR(-ENODEV);

    // 2. 分配 device_domain_info
    info = kzalloc_obj(*info);
    ...

    // 3. 设置 segment/bus/devfn
    if (dev_is_real_dma_subdevice(dev)) {
        info->bus = pdev->bus->number;
        info->devfn = pdev->devfn;
        info->segment = pci_domain_nr(pdev->bus);
    } else {
        info->bus = bus;
        info->devfn = devfn;
        info->segment = iommu->segment;
    }

    info->dev = dev;
    info->iommu = iommu;

    // 4. 探测 PCI 设备能力
    if (dev_is_pci(dev)) {
        // ATS Support
        if (ecap_dev_iotlb_support(iommu->ecap) &&
            pci_ats_supported(pdev) &&
            dmar_ats_supported(pdev, iommu)) {
            info->ats_supported = 1;
            info->dtlb_extra_inval = dev_needs_extra_dtlb_flush(pdev);
            if (ecap_dit(iommu->ecap))
                info->pfsid = pci_dev_id(pci_physfn(pdev));
            info->ats_qdep = pci_ats_queue_depth(pdev);
        }
        // PASID Support
        if (sm_supported(iommu)) {
            if (pasid_supported(iommu)) {
                int features = pci_pasid_features(pdev);
                if (features >= 0)
                    info->pasid_supported = features | 1;
            }
            // PRI Support
            if (info->ats_supported && ecap_prs(iommu->ecap) &&
                ecap_pds(iommu->ecap) && pci_pri_supported(pdev))
                info->pri_supported = 1;
        }
    }

    // 5. 将 info 注册到设备
    dev_iommu_priv_set(dev, info);

    // 6. 插入 device_rbtree
    if (pdev && pci_ats_supported(pdev)) {
        pci_prepare_ats(pdev, VTD_PAGE_SHIFT);
        ret = device_rbtree_insert(iommu, info);
    }

    // 7. 为 scalable mode 分配 PASID 表
    if (sm_supported(iommu) && !dev_is_real_dma_subdevice(dev)) {
        ret = intel_pasid_alloc_table(dev);
        ...
        if (!context_copied(iommu, info->bus, info->devfn)) {
            ret = intel_pasid_setup_sm_context(dev);
        }
    }

    intel_iommu_debugfs_create_dev(info);
    return &iommu->iommu;
}

7.2 intel_iommu_probe_finalize — 探测完成

// drivers/iommu/intel/iommu.c:3324-3351
static void intel_iommu_probe_finalize(struct device *dev)
{
    ...
    // PCIe spec: 必须在 ATS 启用前启用 PASID
    if (info->pasid_supported &&
        !pci_enable_pasid(to_pci_dev(dev), info->pasid_supported & ~1))
        info->pasid_enabled = 1;

    // 启用 ATS + 分配 DEVTLB cache tag
    if (sm_supported(iommu) && !dev_is_real_dma_subdevice(dev)) {
        iommu_enable_pci_ats(info);
        if (info->ats_enabled && info->domain) {
            u16 did = domain_id_iommu(info->domain, iommu);
            cache_tag_assign(info->domain, did, dev,
                           IOMMU_NO_PASID, CACHE_TAG_DEVTLB);
        }
    }
    iommu_enable_pci_pri(info);
}

8. IOMMU 操作表 (ops vtable)

8.1 intel_iommu_ops — 全局 ops

// drivers/iommu/intel/iommu.c:3913-3930
const struct iommu_ops intel_iommu_ops = {
    .blocked_domain         = &blocking_domain,
    .release_domain         = &blocking_domain,
    .identity_domain        = &identity_domain,
    .capable                = intel_iommu_capable,
    .hw_info                = intel_iommu_hw_info,
    .domain_alloc_paging_flags = intel_iommu_domain_alloc_paging_flags,
    .domain_alloc_sva       = intel_svm_domain_alloc,
    .domain_alloc_nested    = intel_iommu_domain_alloc_nested,
    .probe_device           = intel_iommu_probe_device,
    .probe_finalize         = intel_iommu_probe_finalize,
    .release_device         = intel_iommu_release_device,
    .get_resv_regions       = intel_iommu_get_resv_regions,
    .device_group           = intel_iommu_device_group,
    .is_attach_deferred     = intel_iommu_is_attach_deferred,
    .def_domain_type        = device_def_domain_type,
    .page_response          = intel_iommu_page_response,
};

8.2 intel_fs_paging_domain_ops — 第一级页表 ops

// drivers/iommu/intel/iommu.c:3891-3900
const struct iommu_domain_ops intel_fs_paging_domain_ops = {
    IOMMU_PT_DOMAIN_OPS(x86_64),        // 宏展开: .map_pages, .unmap_pages, .iova_to_phys
    .attach_dev = intel_iommu_attach_device,
    .set_dev_pasid = intel_iommu_set_dev_pasid,
    .iotlb_sync_map = intel_iommu_iotlb_sync_map,
    .flush_iotlb_all = intel_flush_iotlb_all,
    .iotlb_sync = intel_iommu_tlb_sync,
    .free = intel_iommu_domain_free,
    .enforce_cache_coherency = intel_iommu_enforce_cache_coherency_fs,
};

8.3 intel_ss_paging_domain_ops — 第二级页表 ops

// drivers/iommu/intel/iommu.c:3902-3911
const struct iommu_domain_ops intel_ss_paging_domain_ops = {
    IOMMU_PT_DOMAIN_OPS(vtdss),         // 宏展开: .map_pages, .unmap_pages, .iova_to_phys (vtdss 格式)
    .attach_dev = intel_iommu_attach_device,
    .set_dev_pasid = intel_iommu_set_dev_pasid,
    .iotlb_sync_map = intel_iommu_iotlb_sync_map,
    .flush_iotlb_all = intel_flush_iotlb_all,
    .iotlb_sync = intel_iommu_tlb_sync,
    .free = intel_iommu_domain_free,
    .enforce_cache_coherency = intel_iommu_enforce_cache_coherency_ss,
};

9. 页表 → Domain → Device 关系图

struct intel_iommu (iommu.h:682)
├── root_entry[] ──→ Root Table (物理连续)
│   │                   [bus 0] root_entry → context_table_0
│   │                   [bus 1] root_entry → context_table_1
│   │                   ...
│   │
│   └── context_entry per devfn
│       │
│       │  Translation type:
│       │  ├── TT_MULTI_LEVEL → dma_pte[] → 3/5-level PT
│       │  ├── TT_PASS_THROUGH → 1:1 mapping
│       │  └── CONTEXT_PASIDE → pasid_table
│       │
│       ├── device_domain_info.iommu = iommu
│       ├── device_domain_info.domain = dmar_domain
│       └── device_domain_info.bus/devfn = BDF identifier
├── device_rbtree → 所有 probed 设备 (by RID)
├── qi (q_inval) → IOTLB/devTLB/context cache flush
├── ir_table → Interrupt Remapping Table
└── prq → Page Request Queue (PRI)

10. Domain 生命周期

domain_alloc_paging_flags()
├── intel_iommu_domain_alloc_paging_flags()
│   ├── 分配 dmar_domain
│   ├── 选择 fspt (first-stage) 或 sspt (second-stage)
│   └── 初始化 xarray (iommu_array)
├── attach_dev()
│   ├── domain_attach_iommu() — 分配 per-IOMMU domain_id
│   ├── 设置 context_entry 的 address root → dma_pte
│   ├── cache_tag_assign() — IOTLB + DEVTLB 缓存标签
│   └── iommu_flush 刷新
├── map/unmap pages (IOMMU_PT_DOMAIN_OPS)
│   ├── 遍历/构建 dma_pte 层级
│   └── 标记 iotlb_sync_map = 1 (需要 flush)
├── iotlb_sync
│   └── cache_tag_flush_range() — 批量 flush
├── detach_dev()
│   └── domain_detach_iommu() + context_clear_entry()
└── domain_free()
    ├── 释放 dma_pte 页面
    └── 释放 domain struct

11. 关键行号速查

符号 文件 行号 说明
struct intel_iommu iommu.h 682 IOMMU 实例结构体
struct dmar_domain iommu.h 592 DMA 地址域
struct device_domain_info iommu.h 740 设备-域绑定
struct root_entry iommu.h 550 根表项
struct context_entry iommu.h 566 上下文表项
struct dma_pte iommu.h 841 DMA 页表项
struct qi_desc iommu.h 469 QI 描述符
struct q_inval iommu.h 476 QI 队列
struct qi_batch iommu.h 587 批量 QI
struct iommu_flush iommu.h 512 Flush 方法
struct cache_tag iommu.h 1214 缓存标签
cap_mgaw iommu.h 177 MGAW 解码
cap_sagaw iommu.h 178 SAGAW 解码
cap_caching_mode iommu.h 179 Caching mode
cap_ndoms iommu.h 184 Max domains
ecap_pasid iommu.h 198 PASID support
ecap_smts iommu.h 195 Scalable mode
ecap_nest iommu.h 207 Nested translation
ecap_coherent iommu.h 211 Cache coherency
ecap_ir_support iommu.h 215 IR support
ecap_eim_support iommu.h 214 x2APIC
DMAR_GCMD_REG iommu.h 71 GCMD 偏移
DMAR_GSTS_REG iommu.h 72 GSTS 偏移
DMAR_RTADDR_REG iommu.h 73 Root Table 地址
DMAR_IQH_REG iommu.h 85 QI 队列头
DMAR_IQA_REG iommu.h 90 QI 队列地址
intel_iommu_probe_device iommu.c 3229 设备探测
intel_iommu_probe_finalize iommu.c 3324 探测完成
intel_iommu_release_device iommu.c 3353 设备释放
intel_fs_paging_domain_ops iommu.c 3891 第一级页表 ops
intel_ss_paging_domain_ops iommu.c 3902 第二级页表 ops
intel_iommu_ops iommu.c 3913 全局 IOMMU ops
to_dmar_domain iommu.h 784 domain 转换
domain_id_iommu iommu.h 809 Domain ID 获取
agaw_to_level iommu.h 875 AGAW → level

下一篇文章

第三篇:DMA 重映射 — 页表遍历、TLB 刷新与缓存标签


💬 评论