AMD KFD的BO设计分析系列5-4:VM-amdgpu_vm_bo_map的完成详解

1. 设计背景与作用

在 AMDGPU 驱动的 GPU 虚拟内存(VM)管理体系中,amdgpu_vm_bo_map 是将一个显存对象(BO, Buffer Object)映射到某个虚拟地址空间(VM)的核心接口。它负责将 BO 的物理内存区域映射到指定的 GPU 虚拟地址,并设置访问属性(flags),从而实现用户进程或内核任务对显存的安全、灵活访问。

该接口是 GPU 显存虚拟化、资源隔离、页表管理的基础,广泛应用于图形渲染、异构计算、KFD 进程管理等场景。

2. 核心数据结构

2.1 amdgpu_vm

  • 代表一个 GPU 虚拟地址空间,通常对应一个用户进程或 KFD 计算上下文。

  • 管理所有映射的 BO 及其虚拟地址关系。

2.2 amdgpu_bo_va

  • 代表某个 BO 在某个 VM 中的映射关系。

  • 包含 BO 指针、VM 指针、映射状态链表等。

2.3 amdgpu_bo_va_mapping

  • 代表一次具体的虚拟地址映射(即 BO 的一段物理内存映射到 VM 的某个虚拟地址区间)。

  • 包含起始地址、结束地址、偏移、flags 等信息。

该结构体相当于CPU进程虚拟地址空间中的VMA。该类型对象会把加入的GPUVM中,代表这段GPU虚拟地址已经被分配。

3. amdgpu_vm_bo_map 实现流程

int amdgpu_vm_bo_map(
    struct amdgpu_device *adev,      // 指向 AMDGPU 设备对象,代表当前 GPU
    struct amdgpu_bo_va *bo_va,      // BO 在 VM 中的映射关系对象,包含 BO 和 VM 指针
    uint64_t saddr,                  // GPU 虚拟地址空间中的起始地址(映射目标地址)
    uint64_t offset,                 // BO 内部的偏移(从 BO 的哪个位置开始映射)
    uint64_t size,                   // 映射的字节数(BO 映射到 VM 的长度)
    uint64_t flags                   // 页属性标志(如读/写/有效/PRT等)
)

3.1 参数校验

校验参数合法性,包括地址对齐、offset、size 是否越界、虚拟地址空间是否足够等。

通过 amdgpu_vm_verify_parameters 实现,防止非法映射导致内存安全问题。

3.2 地址转换与冲突检测

将字节地址转换为页号(GPU 页大小)。

计算映射区间的起始页号和结束页号。

检查目标虚拟地址区间是否已被其他 BO 映射(通过 interval tree),防止地址冲突。

saddr /= AMDGPU_GPU_PAGE_SIZE;
eaddr = saddr + (size - 1) / AMDGPU_GPU_PAGE_SIZE;
tmp = amdgpu_vm_it_iter_first(&vm->va, saddr, eaddr);
if (tmp) {
    // 地址冲突,返回错误
}

3.3 映射结构分配与初始化

分配一个新的 amdgpu_bo_va_mapping 结构体,填充起始页号、结束页号、offset、flags 等信息。

mapping = kmalloc(sizeof(*mapping), GFP_KERNEL);
mapping->start = saddr;
mapping->last = eaddr;
mapping->offset = offset;
mapping->flags = flags;

3.4 插入映射关系、状态迁移与同步

这是最关键的一步,通过这步各个结构体之间就建立了关联。这一步由amdgpu_vm_bo_insert_map实现。它是 AMDGPU 虚拟内存管理中用于插入新的 BO 映射关系的核心函数,主要功能是将一个显存对象(BO)的虚拟地址映射(mapping)插入到 VM(虚拟地址空间)和 BO 的管理结构中,并维护相关的状态和特性。

核心流程如下:

  1. 映射关系挂接
    将新的 mapping 结构体与 bo_va(BO 在 VM 中的映射对象)关联,并加入到 bo_va->invalids 链表,表示该映射尚未被页表更新。

  2. 插入 interval tree
    把 mapping 插入到 VM 的 interval tree(vm->va),便于后续查找、冲突检测和批量管理所有虚拟地址映射。

  3. PRT(Partial Resident Texture)处理
    如果映射带有 PRT 标志,则增加 PRT 用户计数,驱动后续会根据用户数启用或禁用 PRT硬件特性。

  4. BO 状态迁移
    如果该 BO 在 VM 中始终有效且未迁移,则将其状态迁移到 moved 链表,等待后续页表更新。

amdgpu_vm_bo_insert_map(adev, bo_va, mapping);
static void amdgpu_vm_bo_insert_map(struct amdgpu_device *adev,
				    struct amdgpu_bo_va *bo_va,
				    struct amdgpu_bo_va_mapping *mapping)
{
	struct amdgpu_vm *vm = bo_va->base.vm;
	struct amdgpu_bo *bo = bo_va->base.bo;
	mapping->bo_va = bo_va;
	list_add(&mapping->list, &bo_va->invalids);
	amdgpu_vm_it_insert(mapping, &vm->va);
	if (mapping->flags & AMDGPU_PTE_PRT_FLAG(adev))
		amdgpu_vm_prt_get(adev);
	if (amdgpu_vm_is_bo_always_valid(vm, bo) && !bo_va->base.moved)
		amdgpu_vm_bo_moved(&bo_va->base);
	trace_amdgpu_vm_bo_map(bo_va, mapping);
}

4. 与虚拟内存系统的协作机制

4.1 页表更新

  • 新的 mapping 插入后,实际的页表项(PTE)尚未更新,需后续调用 amdgpu_vm_bo_update 或 amdgpu_vm_update_range 完成页表写入。

  • 页表更新涉及同步机制(fence)、TLB 刷新等,确保 GPU 能正确访问新映射的显存。

4.2 状态链表管理

  • 映射的生命周期由多个状态链表管理(invalids、valids、moved、idle、evicted等),amdgpu_vm_bo_map 负责将新映射挂载到 invalids 链表,后续状态迁移由页表更新和驱逐机制驱动。

4.3 资源隔离与安全

  • 通过 interval tree 和参数校验,确保不同 BO 之间的虚拟地址空间不冲突,实现多进程资源隔离和安全访问。

5. 总结

amdgpu_vm_bo_map 是 AMDGPU 驱动虚拟内存管理的核心接口之一,负责将显存对象安全、高效地映射到 GPU 虚拟地址空间。其设计充分考虑了多进程隔离、资源安全、页表管理、状态迁移和硬件特性,是现代 GPU 驱动架构的基础。

对于从专栏首篇一路跟进的读者而言,想必已深度理解 GPU 物理地址与虚拟地址的对应关系。稍加梳理便不难发现:二者的映射原理,与 CPU 端虚拟地址到物理地址的转换逻辑,在核心设计思路上高度契合。玩不出什么花来。

如有帮助,请三连:点赞、收藏、加关注。

posted on 2025-10-15 09:59  slgkaifa  阅读(15)  评论(0)    收藏  举报

导航