From 889cf429ee99f3d00ab70b379bce866dba2e844c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Roberto=20de=20Souza?= Date: Mon, 9 Mar 2026 10:17:03 -0700 Subject: [PATCH] anv: Fix placed address mmap with slab bo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The current implmentation adjust the mmap() parameters to make it work, but that causes us to map more addresses than application asked what could cause us to overwrite other application mmaps(). So here we export the slab parent as a dma-buf, then do the mmap with almost no adjustment, the only change is the offset that needs to include the difference between bo address and slab bo parent address. Reviewed-by: Lionel Landwerlin Signed-off-by: José Roberto de Souza Part-of: --- src/intel/vulkan/anv_allocator.c | 47 +++++++++++++++++++++++++-- src/intel/vulkan/anv_gem.c | 2 +- src/intel/vulkan/xe/anv_kmd_backend.c | 36 +++++++++++++++++--- 3 files changed, 76 insertions(+), 9 deletions(-) diff --git a/src/intel/vulkan/anv_allocator.c b/src/intel/vulkan/anv_allocator.c index a2ecd3bbcee..837f5bcf2a7 100644 --- a/src/intel/vulkan/anv_allocator.c +++ b/src/intel/vulkan/anv_allocator.c @@ -33,6 +33,7 @@ #include "common/intel_aux_map.h" #include "util/anon_file.h" #include "util/futex.h" +#include "util/os_mman.h" #ifdef HAVE_VALGRIND #define VG_NOACCESS_READ(__ptr) ({ \ @@ -1763,6 +1764,46 @@ anv_device_alloc_bo(struct anv_device *device, return VK_SUCCESS; } +static VkResult +map_placed_addr_slab(struct anv_device *device, + struct anv_bo *bo, + uint64_t offset, + size_t size, + void *placed_addr, + void **map_out) +{ + int prime_handle = anv_gem_handle_to_fd(device, bo->gem_handle); + VkResult result = VK_SUCCESS; + + if (prime_handle < 0) { + return vk_errorf(device, VK_ERROR_MEMORY_MAP_FAILED, + "anv_gem_handle_to_fd() before mmap failed: %m"); + } + + offset += (bo->offset - bo->slab_parent->offset); + void *map = os_mmap(placed_addr, + size, + PROT_READ | PROT_WRITE, + MAP_FIXED | MAP_SHARED, + prime_handle, + offset); + if (map == MAP_FAILED) { + result = vk_errorf(device, VK_ERROR_MEMORY_MAP_FAILED, "mmap failed: %m"); + goto end; + } + + assert(placed_addr == NULL || map == placed_addr); + assert(map != NULL); + VG(VALGRIND_MALLOCLIKE_BLOCK(map, size, 0, 1)); + + if (map_out) + *map_out = map; + +end: + close(prime_handle); + return result; +} + VkResult anv_device_map_bo(struct anv_device *device, struct anv_bo *bo, @@ -1777,6 +1818,9 @@ anv_device_map_bo(struct anv_device *device, struct anv_bo *real = anv_bo_get_real(bo); uint64_t offset_adjustment = 0; if (real != bo) { + if (placed_addr) + return map_placed_addr_slab(device, bo, offset, size, placed_addr, map_out); + offset += (bo->offset - real->offset); const uint64_t page_size = device->physical->page_size; @@ -1786,9 +1830,6 @@ anv_device_map_bo(struct anv_device *device, offset_adjustment = offset - munmap_offset; size += offset_adjustment; offset = munmap_offset; - - if (placed_addr) - placed_addr -= offset_adjustment; } assert((offset & (page_size - 1)) == 0); diff --git a/src/intel/vulkan/anv_gem.c b/src/intel/vulkan/anv_gem.c index cdffa6b3637..a486ca5d9a2 100644 --- a/src/intel/vulkan/anv_gem.c +++ b/src/intel/vulkan/anv_gem.c @@ -91,7 +91,7 @@ anv_gem_handle_to_fd(struct anv_device *device, uint32_t gem_handle) int ret = intel_ioctl(device->fd, DRM_IOCTL_PRIME_HANDLE_TO_FD, &args); if (ret == -1) - return -1; + return -errno; return args.fd; } diff --git a/src/intel/vulkan/xe/anv_kmd_backend.c b/src/intel/vulkan/xe/anv_kmd_backend.c index f7e56013190..e56b9005551 100644 --- a/src/intel/vulkan/xe/anv_kmd_backend.c +++ b/src/intel/vulkan/xe/anv_kmd_backend.c @@ -32,6 +32,27 @@ #include "drm-uapi/gpu_scheduler.h" #include "drm-uapi/xe_drm.h" +static bool +is_slab_parent_memory_mapped_placeable(struct anv_device *device, + enum anv_bo_alloc_flags alloc_flags) +{ + if ((alloc_flags & ANV_BO_ALLOC_SLAB_PARENT) == false) + return false; + if (device->physical->instance->debug & ANV_DEBUG_NO_SLAB) + return false; + if (!device->vk.enabled_features.memoryMapPlaced) + return false; + + /* Not subject to vkMapMemory*() */ + enum anv_bo_alloc_flags no_vk_map_memory = ANV_BO_ALLOC_COMPRESSED | + ANV_BO_ALLOC_INTERNAL | + ANV_BO_ALLOC_DESCRIPTOR_POOL; + if (alloc_flags & no_vk_map_memory) + return false; + + return true; +} + static uint32_t xe_gem_create(struct anv_device *device, const struct intel_memory_class_instance **regions, @@ -70,12 +91,17 @@ xe_gem_create(struct anv_device *device, device->info->xe2_has_no_compression_hint) flags |= DRM_XE_GEM_CREATE_FLAG_NO_COMPRESSION; + /* From xe_drm.h: If a VM is specified, this BO must: + * 1. Only ever be bound to that VM. + * 2. Cannot be exported as a PRIME fd. + */ + uint32_t vm_id = device->vm_id; + if ((alloc_flags & ANV_BO_ALLOC_EXTERNAL) || + is_slab_parent_memory_mapped_placeable(device, alloc_flags)) + vm_id = 0; + struct drm_xe_gem_create gem_create = { - /* From xe_drm.h: If a VM is specified, this BO must: - * 1. Only ever be bound to that VM. - * 2. Cannot be exported as a PRIME fd. - */ - .vm_id = alloc_flags & ANV_BO_ALLOC_EXTERNAL ? 0 : device->vm_id, + .vm_id = vm_id, .size = align64(size, device->info->mem_alignment), .flags = flags, };