xref: /third_party/mesa3d/src/drm-shim/device.c (revision bf215546)
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