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