1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright © 2018 Broadcom 3bf215546Sopenharmony_ci * 4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation 7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 10bf215546Sopenharmony_ci * 11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next 12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 13bf215546Sopenharmony_ci * Software. 14bf215546Sopenharmony_ci * 15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21bf215546Sopenharmony_ci * DEALINGS IN THE SOFTWARE. 22bf215546Sopenharmony_ci */ 23bf215546Sopenharmony_ci 24bf215546Sopenharmony_ci/** @file 25bf215546Sopenharmony_ci * 26bf215546Sopenharmony_ci * Implements core GEM support (particularly ioctls) underneath the libc ioctl 27bf215546Sopenharmony_ci * wrappers, and calls into the driver-specific code as necessary. 28bf215546Sopenharmony_ci */ 29bf215546Sopenharmony_ci 30bf215546Sopenharmony_ci#include <c11/threads.h> 31bf215546Sopenharmony_ci#include <errno.h> 32bf215546Sopenharmony_ci#include <linux/memfd.h> 33bf215546Sopenharmony_ci#include <stdbool.h> 34bf215546Sopenharmony_ci#include <stdio.h> 35bf215546Sopenharmony_ci#include <stdlib.h> 36bf215546Sopenharmony_ci#include <string.h> 37bf215546Sopenharmony_ci#include <sys/ioctl.h> 38bf215546Sopenharmony_ci#include <sys/mman.h> 39bf215546Sopenharmony_ci#include <unistd.h> 40bf215546Sopenharmony_ci#include "drm-uapi/drm.h" 41bf215546Sopenharmony_ci#include "drm_shim.h" 42bf215546Sopenharmony_ci#include "util/hash_table.h" 43bf215546Sopenharmony_ci#include "util/u_atomic.h" 44bf215546Sopenharmony_ci 45bf215546Sopenharmony_ci#define SHIM_MEM_SIZE (4ull * 1024 * 1024 * 1024) 46bf215546Sopenharmony_ci 47bf215546Sopenharmony_ci#ifndef HAVE_MEMFD_CREATE 48bf215546Sopenharmony_ci#include <sys/syscall.h> 49bf215546Sopenharmony_ci 50bf215546Sopenharmony_cistatic inline int 51bf215546Sopenharmony_cimemfd_create(const char *name, unsigned int flags) 52bf215546Sopenharmony_ci{ 53bf215546Sopenharmony_ci return syscall(SYS_memfd_create, name, flags); 54bf215546Sopenharmony_ci} 55bf215546Sopenharmony_ci#endif 56bf215546Sopenharmony_ci 57bf215546Sopenharmony_ci/* Global state for the shim shared between libc, core, and driver. */ 58bf215546Sopenharmony_cistruct shim_device shim_device; 59bf215546Sopenharmony_ci 60bf215546Sopenharmony_cilong shim_page_size; 61bf215546Sopenharmony_ci 62bf215546Sopenharmony_cistatic uint32_t 63bf215546Sopenharmony_ciuint_key_hash(const void *key) 64bf215546Sopenharmony_ci{ 65bf215546Sopenharmony_ci return (uintptr_t)key; 66bf215546Sopenharmony_ci} 67bf215546Sopenharmony_ci 68bf215546Sopenharmony_cistatic bool 69bf215546Sopenharmony_ciuint_key_compare(const void *a, const void *b) 70bf215546Sopenharmony_ci{ 71bf215546Sopenharmony_ci return a == b; 72bf215546Sopenharmony_ci} 73bf215546Sopenharmony_ci 74bf215546Sopenharmony_ci/** 75bf215546Sopenharmony_ci * Called when the first libc shim is called, to initialize GEM simulation 76bf215546Sopenharmony_ci * state (other than the shims themselves). 77bf215546Sopenharmony_ci */ 78bf215546Sopenharmony_civoid 79bf215546Sopenharmony_cidrm_shim_device_init(void) 80bf215546Sopenharmony_ci{ 81bf215546Sopenharmony_ci shim_device.fd_map = _mesa_hash_table_create(NULL, 82bf215546Sopenharmony_ci uint_key_hash, 83bf215546Sopenharmony_ci uint_key_compare); 84bf215546Sopenharmony_ci 85bf215546Sopenharmony_ci shim_device.offset_map = _mesa_hash_table_u64_create(NULL); 86bf215546Sopenharmony_ci 87bf215546Sopenharmony_ci mtx_init(&shim_device.mem_lock, mtx_plain); 88bf215546Sopenharmony_ci 89bf215546Sopenharmony_ci shim_device.mem_fd = memfd_create("shim mem", MFD_CLOEXEC); 90bf215546Sopenharmony_ci assert(shim_device.mem_fd != -1); 91bf215546Sopenharmony_ci 92bf215546Sopenharmony_ci ASSERTED int ret = ftruncate(shim_device.mem_fd, SHIM_MEM_SIZE); 93bf215546Sopenharmony_ci assert(ret == 0); 94bf215546Sopenharmony_ci 95bf215546Sopenharmony_ci /* The man page for mmap() says 96bf215546Sopenharmony_ci * 97bf215546Sopenharmony_ci * offset must be a multiple of the page size as returned by 98bf215546Sopenharmony_ci * sysconf(_SC_PAGE_SIZE). 99bf215546Sopenharmony_ci * 100bf215546Sopenharmony_ci * Depending on the configuration of the kernel, this may not be 4096. Get 101bf215546Sopenharmony_ci * this page size once and use it as the page size throughout, ensuring that 102bf215546Sopenharmony_ci * are offsets are page-size aligned as required. Otherwise, mmap will fail 103bf215546Sopenharmony_ci * with EINVAL. 104bf215546Sopenharmony_ci */ 105bf215546Sopenharmony_ci 106bf215546Sopenharmony_ci shim_page_size = sysconf(_SC_PAGE_SIZE); 107bf215546Sopenharmony_ci 108bf215546Sopenharmony_ci util_vma_heap_init(&shim_device.mem_heap, shim_page_size, 109bf215546Sopenharmony_ci SHIM_MEM_SIZE - shim_page_size); 110bf215546Sopenharmony_ci 111bf215546Sopenharmony_ci drm_shim_driver_init(); 112bf215546Sopenharmony_ci} 113bf215546Sopenharmony_ci 114bf215546Sopenharmony_cistatic struct shim_fd * 115bf215546Sopenharmony_cidrm_shim_file_create(int fd) 116bf215546Sopenharmony_ci{ 117bf215546Sopenharmony_ci struct shim_fd *shim_fd = calloc(1, sizeof(*shim_fd)); 118bf215546Sopenharmony_ci 119bf215546Sopenharmony_ci shim_fd->fd = fd; 120bf215546Sopenharmony_ci p_atomic_set(&shim_fd->refcount, 1); 121bf215546Sopenharmony_ci mtx_init(&shim_fd->handle_lock, mtx_plain); 122bf215546Sopenharmony_ci shim_fd->handles = _mesa_hash_table_create(NULL, 123bf215546Sopenharmony_ci uint_key_hash, 124bf215546Sopenharmony_ci uint_key_compare); 125bf215546Sopenharmony_ci 126bf215546Sopenharmony_ci return shim_fd; 127bf215546Sopenharmony_ci} 128bf215546Sopenharmony_ci 129bf215546Sopenharmony_ci/** 130bf215546Sopenharmony_ci * Called when the libc shims have interposed an open or dup of our simulated 131bf215546Sopenharmony_ci * DRM device. 132bf215546Sopenharmony_ci */ 133bf215546Sopenharmony_civoid drm_shim_fd_register(int fd, struct shim_fd *shim_fd) 134bf215546Sopenharmony_ci{ 135bf215546Sopenharmony_ci if (!shim_fd) 136bf215546Sopenharmony_ci shim_fd = drm_shim_file_create(fd); 137bf215546Sopenharmony_ci else 138bf215546Sopenharmony_ci p_atomic_inc(&shim_fd->refcount); 139bf215546Sopenharmony_ci 140bf215546Sopenharmony_ci _mesa_hash_table_insert(shim_device.fd_map, (void *)(uintptr_t)(fd + 1), shim_fd); 141bf215546Sopenharmony_ci} 142bf215546Sopenharmony_ci 143bf215546Sopenharmony_cistatic void handle_delete_fxn(struct hash_entry *entry) 144bf215546Sopenharmony_ci{ 145bf215546Sopenharmony_ci drm_shim_bo_put(entry->data); 146bf215546Sopenharmony_ci} 147bf215546Sopenharmony_ci 148bf215546Sopenharmony_civoid drm_shim_fd_unregister(int fd) 149bf215546Sopenharmony_ci{ 150bf215546Sopenharmony_ci struct hash_entry *entry = 151bf215546Sopenharmony_ci _mesa_hash_table_search(shim_device.fd_map, (void *)(uintptr_t)(fd + 1)); 152bf215546Sopenharmony_ci if (!entry) 153bf215546Sopenharmony_ci return; 154bf215546Sopenharmony_ci struct shim_fd *shim_fd = entry->data; 155bf215546Sopenharmony_ci _mesa_hash_table_remove(shim_device.fd_map, entry); 156bf215546Sopenharmony_ci 157bf215546Sopenharmony_ci if (!p_atomic_dec_zero(&shim_fd->refcount)) 158bf215546Sopenharmony_ci return; 159bf215546Sopenharmony_ci 160bf215546Sopenharmony_ci _mesa_hash_table_destroy(shim_fd->handles, handle_delete_fxn); 161bf215546Sopenharmony_ci free(shim_fd); 162bf215546Sopenharmony_ci} 163bf215546Sopenharmony_ci 164bf215546Sopenharmony_cistruct shim_fd * 165bf215546Sopenharmony_cidrm_shim_fd_lookup(int fd) 166bf215546Sopenharmony_ci{ 167bf215546Sopenharmony_ci if (fd == -1) 168bf215546Sopenharmony_ci return NULL; 169bf215546Sopenharmony_ci 170bf215546Sopenharmony_ci struct hash_entry *entry = 171bf215546Sopenharmony_ci _mesa_hash_table_search(shim_device.fd_map, (void *)(uintptr_t)(fd + 1)); 172bf215546Sopenharmony_ci 173bf215546Sopenharmony_ci if (!entry) 174bf215546Sopenharmony_ci return NULL; 175bf215546Sopenharmony_ci return entry->data; 176bf215546Sopenharmony_ci} 177bf215546Sopenharmony_ci 178bf215546Sopenharmony_ci/* ioctl used by drmGetVersion() */ 179bf215546Sopenharmony_cistatic int 180bf215546Sopenharmony_cidrm_shim_ioctl_version(int fd, unsigned long request, void *arg) 181bf215546Sopenharmony_ci{ 182bf215546Sopenharmony_ci struct drm_version *args = arg; 183bf215546Sopenharmony_ci const char *date = "20190320"; 184bf215546Sopenharmony_ci const char *desc = "shim"; 185bf215546Sopenharmony_ci 186bf215546Sopenharmony_ci args->version_major = shim_device.version_major; 187bf215546Sopenharmony_ci args->version_minor = shim_device.version_minor; 188bf215546Sopenharmony_ci args->version_patchlevel = shim_device.version_patchlevel; 189bf215546Sopenharmony_ci 190bf215546Sopenharmony_ci if (args->name) 191bf215546Sopenharmony_ci strncpy(args->name, shim_device.driver_name, args->name_len); 192bf215546Sopenharmony_ci if (args->date) 193bf215546Sopenharmony_ci strncpy(args->date, date, args->date_len); 194bf215546Sopenharmony_ci if (args->desc) 195bf215546Sopenharmony_ci strncpy(args->desc, desc, args->desc_len); 196bf215546Sopenharmony_ci args->name_len = strlen(shim_device.driver_name); 197bf215546Sopenharmony_ci args->date_len = strlen(date); 198bf215546Sopenharmony_ci args->desc_len = strlen(desc); 199bf215546Sopenharmony_ci 200bf215546Sopenharmony_ci return 0; 201bf215546Sopenharmony_ci} 202bf215546Sopenharmony_ci 203bf215546Sopenharmony_cistatic int 204bf215546Sopenharmony_cidrm_shim_ioctl_get_unique(int fd, unsigned long request, void *arg) 205bf215546Sopenharmony_ci{ 206bf215546Sopenharmony_ci struct drm_unique *gu = arg; 207bf215546Sopenharmony_ci 208bf215546Sopenharmony_ci if (gu->unique && shim_device.unique) 209bf215546Sopenharmony_ci strncpy(gu->unique, shim_device.unique, gu->unique_len); 210bf215546Sopenharmony_ci gu->unique_len = shim_device.unique ? strlen(shim_device.unique) : 0; 211bf215546Sopenharmony_ci 212bf215546Sopenharmony_ci return 0; 213bf215546Sopenharmony_ci} 214bf215546Sopenharmony_ci 215bf215546Sopenharmony_cistatic int 216bf215546Sopenharmony_cidrm_shim_ioctl_get_cap(int fd, unsigned long request, void *arg) 217bf215546Sopenharmony_ci{ 218bf215546Sopenharmony_ci struct drm_get_cap *gc = arg; 219bf215546Sopenharmony_ci 220bf215546Sopenharmony_ci switch (gc->capability) { 221bf215546Sopenharmony_ci case DRM_CAP_PRIME: 222bf215546Sopenharmony_ci case DRM_CAP_SYNCOBJ: 223bf215546Sopenharmony_ci case DRM_CAP_SYNCOBJ_TIMELINE: 224bf215546Sopenharmony_ci gc->value = 1; 225bf215546Sopenharmony_ci return 0; 226bf215546Sopenharmony_ci 227bf215546Sopenharmony_ci default: 228bf215546Sopenharmony_ci fprintf(stderr, "DRM_IOCTL_GET_CAP: unhandled 0x%x\n", 229bf215546Sopenharmony_ci (int)gc->capability); 230bf215546Sopenharmony_ci return -1; 231bf215546Sopenharmony_ci } 232bf215546Sopenharmony_ci} 233bf215546Sopenharmony_ci 234bf215546Sopenharmony_cistatic int 235bf215546Sopenharmony_cidrm_shim_ioctl_gem_close(int fd, unsigned long request, void *arg) 236bf215546Sopenharmony_ci{ 237bf215546Sopenharmony_ci struct shim_fd *shim_fd = drm_shim_fd_lookup(fd); 238bf215546Sopenharmony_ci struct drm_gem_close *c = arg; 239bf215546Sopenharmony_ci 240bf215546Sopenharmony_ci if (!c->handle) 241bf215546Sopenharmony_ci return 0; 242bf215546Sopenharmony_ci 243bf215546Sopenharmony_ci mtx_lock(&shim_fd->handle_lock); 244bf215546Sopenharmony_ci struct hash_entry *entry = 245bf215546Sopenharmony_ci _mesa_hash_table_search(shim_fd->handles, (void *)(uintptr_t)c->handle); 246bf215546Sopenharmony_ci if (!entry) { 247bf215546Sopenharmony_ci mtx_unlock(&shim_fd->handle_lock); 248bf215546Sopenharmony_ci return -EINVAL; 249bf215546Sopenharmony_ci } 250bf215546Sopenharmony_ci 251bf215546Sopenharmony_ci struct shim_bo *bo = entry->data; 252bf215546Sopenharmony_ci _mesa_hash_table_remove(shim_fd->handles, entry); 253bf215546Sopenharmony_ci drm_shim_bo_put(bo); 254bf215546Sopenharmony_ci mtx_unlock(&shim_fd->handle_lock); 255bf215546Sopenharmony_ci return 0; 256bf215546Sopenharmony_ci} 257bf215546Sopenharmony_ci 258bf215546Sopenharmony_cistatic int 259bf215546Sopenharmony_cidrm_shim_ioctl_syncobj_create(int fd, unsigned long request, void *arg) 260bf215546Sopenharmony_ci{ 261bf215546Sopenharmony_ci struct drm_syncobj_create *create = arg; 262bf215546Sopenharmony_ci 263bf215546Sopenharmony_ci create->handle = 1; /* 0 is invalid */ 264bf215546Sopenharmony_ci 265bf215546Sopenharmony_ci return 0; 266bf215546Sopenharmony_ci} 267bf215546Sopenharmony_ci 268bf215546Sopenharmony_cistatic int 269bf215546Sopenharmony_cidrm_shim_ioctl_stub(int fd, unsigned long request, void *arg) 270bf215546Sopenharmony_ci{ 271bf215546Sopenharmony_ci return 0; 272bf215546Sopenharmony_ci} 273bf215546Sopenharmony_ci 274bf215546Sopenharmony_ciioctl_fn_t core_ioctls[] = { 275bf215546Sopenharmony_ci [_IOC_NR(DRM_IOCTL_VERSION)] = drm_shim_ioctl_version, 276bf215546Sopenharmony_ci [_IOC_NR(DRM_IOCTL_GET_UNIQUE)] = drm_shim_ioctl_get_unique, 277bf215546Sopenharmony_ci [_IOC_NR(DRM_IOCTL_GET_CAP)] = drm_shim_ioctl_get_cap, 278bf215546Sopenharmony_ci [_IOC_NR(DRM_IOCTL_GEM_CLOSE)] = drm_shim_ioctl_gem_close, 279bf215546Sopenharmony_ci [_IOC_NR(DRM_IOCTL_SYNCOBJ_CREATE)] = drm_shim_ioctl_syncobj_create, 280bf215546Sopenharmony_ci [_IOC_NR(DRM_IOCTL_SYNCOBJ_DESTROY)] = drm_shim_ioctl_stub, 281bf215546Sopenharmony_ci [_IOC_NR(DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD)] = drm_shim_ioctl_stub, 282bf215546Sopenharmony_ci [_IOC_NR(DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE)] = drm_shim_ioctl_stub, 283bf215546Sopenharmony_ci [_IOC_NR(DRM_IOCTL_SYNCOBJ_WAIT)] = drm_shim_ioctl_stub, 284bf215546Sopenharmony_ci}; 285bf215546Sopenharmony_ci 286bf215546Sopenharmony_ci/** 287bf215546Sopenharmony_ci * Implements the GEM core ioctls, and calls into driver-specific ioctls. 288bf215546Sopenharmony_ci */ 289bf215546Sopenharmony_ciint 290bf215546Sopenharmony_cidrm_shim_ioctl(int fd, unsigned long request, void *arg) 291bf215546Sopenharmony_ci{ 292bf215546Sopenharmony_ci ASSERTED int type = _IOC_TYPE(request); 293bf215546Sopenharmony_ci int nr = _IOC_NR(request); 294bf215546Sopenharmony_ci 295bf215546Sopenharmony_ci assert(type == DRM_IOCTL_BASE); 296bf215546Sopenharmony_ci 297bf215546Sopenharmony_ci if (nr >= DRM_COMMAND_BASE && nr < DRM_COMMAND_END) { 298bf215546Sopenharmony_ci int driver_nr = nr - DRM_COMMAND_BASE; 299bf215546Sopenharmony_ci 300bf215546Sopenharmony_ci if (driver_nr < shim_device.driver_ioctl_count && 301bf215546Sopenharmony_ci shim_device.driver_ioctls[driver_nr]) { 302bf215546Sopenharmony_ci return shim_device.driver_ioctls[driver_nr](fd, request, arg); 303bf215546Sopenharmony_ci } 304bf215546Sopenharmony_ci } else { 305bf215546Sopenharmony_ci if (nr < ARRAY_SIZE(core_ioctls) && core_ioctls[nr]) { 306bf215546Sopenharmony_ci return core_ioctls[nr](fd, request, arg); 307bf215546Sopenharmony_ci } 308bf215546Sopenharmony_ci } 309bf215546Sopenharmony_ci 310bf215546Sopenharmony_ci if (nr >= DRM_COMMAND_BASE && nr < DRM_COMMAND_END) { 311bf215546Sopenharmony_ci fprintf(stderr, 312bf215546Sopenharmony_ci "DRM_SHIM: unhandled driver DRM ioctl %d (0x%08lx)\n", 313bf215546Sopenharmony_ci nr - DRM_COMMAND_BASE, request); 314bf215546Sopenharmony_ci } else { 315bf215546Sopenharmony_ci fprintf(stderr, 316bf215546Sopenharmony_ci "DRM_SHIM: unhandled core DRM ioctl 0x%X (0x%08lx)\n", 317bf215546Sopenharmony_ci nr, request); 318bf215546Sopenharmony_ci } 319bf215546Sopenharmony_ci 320bf215546Sopenharmony_ci return -EINVAL; 321bf215546Sopenharmony_ci} 322bf215546Sopenharmony_ci 323bf215546Sopenharmony_ciint 324bf215546Sopenharmony_cidrm_shim_bo_init(struct shim_bo *bo, size_t size) 325bf215546Sopenharmony_ci{ 326bf215546Sopenharmony_ci 327bf215546Sopenharmony_ci mtx_lock(&shim_device.mem_lock); 328bf215546Sopenharmony_ci bo->mem_addr = util_vma_heap_alloc(&shim_device.mem_heap, size, shim_page_size); 329bf215546Sopenharmony_ci mtx_unlock(&shim_device.mem_lock); 330bf215546Sopenharmony_ci 331bf215546Sopenharmony_ci if (!bo->mem_addr) 332bf215546Sopenharmony_ci return -ENOMEM; 333bf215546Sopenharmony_ci 334bf215546Sopenharmony_ci bo->size = size; 335bf215546Sopenharmony_ci 336bf215546Sopenharmony_ci return 0; 337bf215546Sopenharmony_ci} 338bf215546Sopenharmony_ci 339bf215546Sopenharmony_cistruct shim_bo * 340bf215546Sopenharmony_cidrm_shim_bo_lookup(struct shim_fd *shim_fd, int handle) 341bf215546Sopenharmony_ci{ 342bf215546Sopenharmony_ci if (!handle) 343bf215546Sopenharmony_ci return NULL; 344bf215546Sopenharmony_ci 345bf215546Sopenharmony_ci mtx_lock(&shim_fd->handle_lock); 346bf215546Sopenharmony_ci struct hash_entry *entry = 347bf215546Sopenharmony_ci _mesa_hash_table_search(shim_fd->handles, (void *)(uintptr_t)handle); 348bf215546Sopenharmony_ci struct shim_bo *bo = entry ? entry->data : NULL; 349bf215546Sopenharmony_ci mtx_unlock(&shim_fd->handle_lock); 350bf215546Sopenharmony_ci 351bf215546Sopenharmony_ci if (bo) 352bf215546Sopenharmony_ci p_atomic_inc(&bo->refcount); 353bf215546Sopenharmony_ci 354bf215546Sopenharmony_ci return bo; 355bf215546Sopenharmony_ci} 356bf215546Sopenharmony_ci 357bf215546Sopenharmony_civoid 358bf215546Sopenharmony_cidrm_shim_bo_get(struct shim_bo *bo) 359bf215546Sopenharmony_ci{ 360bf215546Sopenharmony_ci p_atomic_inc(&bo->refcount); 361bf215546Sopenharmony_ci} 362bf215546Sopenharmony_ci 363bf215546Sopenharmony_civoid 364bf215546Sopenharmony_cidrm_shim_bo_put(struct shim_bo *bo) 365bf215546Sopenharmony_ci{ 366bf215546Sopenharmony_ci if (p_atomic_dec_return(&bo->refcount) == 0) 367bf215546Sopenharmony_ci return; 368bf215546Sopenharmony_ci 369bf215546Sopenharmony_ci if (shim_device.driver_bo_free) 370bf215546Sopenharmony_ci shim_device.driver_bo_free(bo); 371bf215546Sopenharmony_ci 372bf215546Sopenharmony_ci mtx_lock(&shim_device.mem_lock); 373bf215546Sopenharmony_ci util_vma_heap_free(&shim_device.mem_heap, bo->mem_addr, bo->size); 374bf215546Sopenharmony_ci mtx_unlock(&shim_device.mem_lock); 375bf215546Sopenharmony_ci free(bo); 376bf215546Sopenharmony_ci} 377bf215546Sopenharmony_ci 378bf215546Sopenharmony_ciint 379bf215546Sopenharmony_cidrm_shim_bo_get_handle(struct shim_fd *shim_fd, struct shim_bo *bo) 380bf215546Sopenharmony_ci{ 381bf215546Sopenharmony_ci /* We should probably have some real datastructure for finding the free 382bf215546Sopenharmony_ci * number. 383bf215546Sopenharmony_ci */ 384bf215546Sopenharmony_ci mtx_lock(&shim_fd->handle_lock); 385bf215546Sopenharmony_ci for (int new_handle = 1; ; new_handle++) { 386bf215546Sopenharmony_ci void *key = (void *)(uintptr_t)new_handle; 387bf215546Sopenharmony_ci if (!_mesa_hash_table_search(shim_fd->handles, key)) { 388bf215546Sopenharmony_ci drm_shim_bo_get(bo); 389bf215546Sopenharmony_ci _mesa_hash_table_insert(shim_fd->handles, key, bo); 390bf215546Sopenharmony_ci mtx_unlock(&shim_fd->handle_lock); 391bf215546Sopenharmony_ci return new_handle; 392bf215546Sopenharmony_ci } 393bf215546Sopenharmony_ci } 394bf215546Sopenharmony_ci mtx_unlock(&shim_fd->handle_lock); 395bf215546Sopenharmony_ci 396bf215546Sopenharmony_ci return 0; 397bf215546Sopenharmony_ci} 398bf215546Sopenharmony_ci 399bf215546Sopenharmony_ci/* Creates an mmap offset for the BO in the DRM fd. 400bf215546Sopenharmony_ci */ 401bf215546Sopenharmony_ciuint64_t 402bf215546Sopenharmony_cidrm_shim_bo_get_mmap_offset(struct shim_fd *shim_fd, struct shim_bo *bo) 403bf215546Sopenharmony_ci{ 404bf215546Sopenharmony_ci mtx_lock(&shim_device.mem_lock); 405bf215546Sopenharmony_ci _mesa_hash_table_u64_insert(shim_device.offset_map, bo->mem_addr, bo); 406bf215546Sopenharmony_ci mtx_unlock(&shim_device.mem_lock); 407bf215546Sopenharmony_ci 408bf215546Sopenharmony_ci /* reuse the buffer address as the mmap offset: */ 409bf215546Sopenharmony_ci return bo->mem_addr; 410bf215546Sopenharmony_ci} 411bf215546Sopenharmony_ci 412bf215546Sopenharmony_ci/* For mmap() on the DRM fd, look up the BO from the "offset" and map the BO's 413bf215546Sopenharmony_ci * fd. 414bf215546Sopenharmony_ci */ 415bf215546Sopenharmony_civoid * 416bf215546Sopenharmony_cidrm_shim_mmap(struct shim_fd *shim_fd, size_t length, int prot, int flags, 417bf215546Sopenharmony_ci int fd, off64_t offset) 418bf215546Sopenharmony_ci{ 419bf215546Sopenharmony_ci mtx_lock(&shim_device.mem_lock); 420bf215546Sopenharmony_ci struct shim_bo *bo = _mesa_hash_table_u64_search(shim_device.offset_map, offset); 421bf215546Sopenharmony_ci mtx_unlock(&shim_device.mem_lock); 422bf215546Sopenharmony_ci 423bf215546Sopenharmony_ci if (!bo) 424bf215546Sopenharmony_ci return MAP_FAILED; 425bf215546Sopenharmony_ci 426bf215546Sopenharmony_ci if (length > bo->size) 427bf215546Sopenharmony_ci return MAP_FAILED; 428bf215546Sopenharmony_ci 429bf215546Sopenharmony_ci /* The offset we pass to mmap must be aligned to the page size */ 430bf215546Sopenharmony_ci assert((bo->mem_addr & (shim_page_size - 1)) == 0); 431bf215546Sopenharmony_ci 432bf215546Sopenharmony_ci return mmap(NULL, length, prot, flags, shim_device.mem_fd, bo->mem_addr); 433bf215546Sopenharmony_ci} 434