Linux kernel
代码版本是3.10
。
intel-iommu.h
头文件定义了root-entry table address
寄存器:
#define DMAR_RTADDR_REG 0x20 /* Root entry table */
DMAR_RTADDR_REG
只在iommu_set_root_entry
这个函数中使用(这个函数作用是更新root-entry table
的地址):
static void iommu_set_root_entry(struct intel_iommu *iommu)
{
void *addr;
u32 sts;
unsigned long flag;
addr = iommu->root_entry;
raw_spin_lock_irqsave(&iommu->register_lock, flag);
dmar_writeq(iommu->reg + DMAR_RTADDR_REG, virt_to_phys(addr));
writel(iommu->gcmd | DMA_GCMD_SRTP, iommu->reg + DMAR_GCMD_REG);
/* Make sure hardware complete it */
IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
readl, (sts & DMA_GSTS_RTPS), sts);
raw_spin_unlock_irqrestore(&iommu->register_lock, flag);
}
DMAR_RTADDR_REG
存储的是root-entry table
的物理地址(virt_to_phys()
函数把virtual address
转成physical address
)。整个root-entry table
是4KiB
大小,并且要求起始地址是“页面对齐的(page-aligned
,page
长度是4KiB
)”,所以DMAR_RTADDR_REG
低12 bits
为0
。更新DMAR_RTADDR_REG
代码如下:
dmar_writeq(iommu->reg + DMAR_RTADDR_REG, virt_to_phys(addr));
更新完DMAR_RTADDR_REG
寄存器,还要把global command
寄存器的SRTP
(Set Root Table Pointer
)位置1
:
writel(iommu->gcmd | DMA_GCMD_SRTP, iommu->reg + DMAR_GCMD_REG);
最后读取Global Status
寄存器的RTPS
(Root Table Pointer Status
)位,确认更新成功:
IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG,
readl, (sts & DMA_GSTS_RTPS), sts);