1bf215546Sopenharmony_ci/*
2bf215546Sopenharmony_ci * Copyright © 2015-2018 Intel Corporation
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 DEALINGS
21bf215546Sopenharmony_ci * IN THE SOFTWARE.
22bf215546Sopenharmony_ci */
23bf215546Sopenharmony_ci
24bf215546Sopenharmony_ci#undef _FILE_OFFSET_BITS /* prevent #define open open64 */
25bf215546Sopenharmony_ci
26bf215546Sopenharmony_ci#include <string.h>
27bf215546Sopenharmony_ci#include <stdlib.h>
28bf215546Sopenharmony_ci#include <stdio.h>
29bf215546Sopenharmony_ci#include <stdint.h>
30bf215546Sopenharmony_ci#include <stdarg.h>
31bf215546Sopenharmony_ci#include <fcntl.h>
32bf215546Sopenharmony_ci#include <unistd.h>
33bf215546Sopenharmony_ci#include <sys/ioctl.h>
34bf215546Sopenharmony_ci#include <sys/stat.h>
35bf215546Sopenharmony_ci#include <sys/mman.h>
36bf215546Sopenharmony_ci#include <sys/sysmacros.h>
37bf215546Sopenharmony_ci#include <dlfcn.h>
38bf215546Sopenharmony_ci#include <pthread.h>
39bf215546Sopenharmony_ci#include "drm-uapi/i915_drm.h"
40bf215546Sopenharmony_ci
41bf215546Sopenharmony_ci#include "util/hash_table.h"
42bf215546Sopenharmony_ci#include "util/u_math.h"
43bf215546Sopenharmony_ci
44bf215546Sopenharmony_ci#define MESA_LOG_TAG "INTEL-SANITIZE-GPU"
45bf215546Sopenharmony_ci#include "util/log.h"
46bf215546Sopenharmony_ci#include "common/intel_clflush.h"
47bf215546Sopenharmony_ci
48bf215546Sopenharmony_cistatic int (*libc_open)(const char *pathname, int flags, mode_t mode);
49bf215546Sopenharmony_cistatic int (*libc_close)(int fd);
50bf215546Sopenharmony_cistatic int (*libc_ioctl)(int fd, unsigned long request, void *argp);
51bf215546Sopenharmony_cistatic int (*libc_fcntl)(int fd, int cmd, int param);
52bf215546Sopenharmony_ci
53bf215546Sopenharmony_ci#define DRM_MAJOR 226
54bf215546Sopenharmony_ci
55bf215546Sopenharmony_ci/* TODO: we want to make sure that the padding forces
56bf215546Sopenharmony_ci * the BO to take another page on the (PP)GTT; 4KB
57bf215546Sopenharmony_ci * may or may not be the page size for the BO. Indeed,
58bf215546Sopenharmony_ci * depending on GPU, kernel version and GEM size, the
59bf215546Sopenharmony_ci * page size can be one of 4KB, 64KB or 2M.
60bf215546Sopenharmony_ci */
61bf215546Sopenharmony_ci#define PADDING_SIZE 4096
62bf215546Sopenharmony_ci
63bf215546Sopenharmony_cistruct refcnt_hash_table {
64bf215546Sopenharmony_ci   struct hash_table *t;
65bf215546Sopenharmony_ci   int refcnt;
66bf215546Sopenharmony_ci};
67bf215546Sopenharmony_ci
68bf215546Sopenharmony_cipthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
69bf215546Sopenharmony_ci#define MUTEX_LOCK() do {                        \
70bf215546Sopenharmony_ci   if (unlikely(pthread_mutex_lock(&mutex))) {   \
71bf215546Sopenharmony_ci      mesa_loge("mutex_lock failed");           \
72bf215546Sopenharmony_ci      abort();                                   \
73bf215546Sopenharmony_ci   }                                             \
74bf215546Sopenharmony_ci} while (0)
75bf215546Sopenharmony_ci#define MUTEX_UNLOCK() do {                      \
76bf215546Sopenharmony_ci   if (unlikely(pthread_mutex_unlock(&mutex))) { \
77bf215546Sopenharmony_ci      mesa_loge("mutex_unlock failed");         \
78bf215546Sopenharmony_ci      abort();                                   \
79bf215546Sopenharmony_ci   }                                             \
80bf215546Sopenharmony_ci} while (0)
81bf215546Sopenharmony_ci
82bf215546Sopenharmony_cistatic struct hash_table *fds_to_bo_sizes = NULL;
83bf215546Sopenharmony_ci
84bf215546Sopenharmony_cistatic inline struct hash_table*
85bf215546Sopenharmony_cibo_size_table(int fd)
86bf215546Sopenharmony_ci{
87bf215546Sopenharmony_ci   struct hash_entry *e = _mesa_hash_table_search(fds_to_bo_sizes,
88bf215546Sopenharmony_ci                                                  (void*)(uintptr_t)fd);
89bf215546Sopenharmony_ci   return e ? ((struct refcnt_hash_table*)e->data)->t : NULL;
90bf215546Sopenharmony_ci}
91bf215546Sopenharmony_ci
92bf215546Sopenharmony_cistatic inline uint64_t
93bf215546Sopenharmony_cibo_size(int fd, uint32_t handle)
94bf215546Sopenharmony_ci{
95bf215546Sopenharmony_ci   struct hash_table *t = bo_size_table(fd);
96bf215546Sopenharmony_ci   if (!t)
97bf215546Sopenharmony_ci      return UINT64_MAX;
98bf215546Sopenharmony_ci   struct hash_entry *e = _mesa_hash_table_search(t, (void*)(uintptr_t)handle);
99bf215546Sopenharmony_ci   return e ? (uint64_t)(uintptr_t)e->data : UINT64_MAX;
100bf215546Sopenharmony_ci}
101bf215546Sopenharmony_ci
102bf215546Sopenharmony_cistatic inline bool
103bf215546Sopenharmony_ciis_drm_fd(int fd)
104bf215546Sopenharmony_ci{
105bf215546Sopenharmony_ci   return !!bo_size_table(fd);
106bf215546Sopenharmony_ci}
107bf215546Sopenharmony_ci
108bf215546Sopenharmony_cistatic inline void
109bf215546Sopenharmony_ciadd_drm_fd(int fd)
110bf215546Sopenharmony_ci{
111bf215546Sopenharmony_ci   struct refcnt_hash_table *r = malloc(sizeof(*r));
112bf215546Sopenharmony_ci   r->refcnt = 1;
113bf215546Sopenharmony_ci   r->t = _mesa_pointer_hash_table_create(NULL);
114bf215546Sopenharmony_ci   _mesa_hash_table_insert(fds_to_bo_sizes, (void*)(uintptr_t)fd,
115bf215546Sopenharmony_ci                           (void*)(uintptr_t)r);
116bf215546Sopenharmony_ci}
117bf215546Sopenharmony_ci
118bf215546Sopenharmony_cistatic inline void
119bf215546Sopenharmony_cidup_drm_fd(int old_fd, int new_fd)
120bf215546Sopenharmony_ci{
121bf215546Sopenharmony_ci   struct hash_entry *e = _mesa_hash_table_search(fds_to_bo_sizes,
122bf215546Sopenharmony_ci                                                  (void*)(uintptr_t)old_fd);
123bf215546Sopenharmony_ci   struct refcnt_hash_table *r = e->data;
124bf215546Sopenharmony_ci   r->refcnt++;
125bf215546Sopenharmony_ci   _mesa_hash_table_insert(fds_to_bo_sizes, (void*)(uintptr_t)new_fd,
126bf215546Sopenharmony_ci                           (void*)(uintptr_t)r);
127bf215546Sopenharmony_ci}
128bf215546Sopenharmony_ci
129bf215546Sopenharmony_cistatic inline void
130bf215546Sopenharmony_cidel_drm_fd(int fd)
131bf215546Sopenharmony_ci{
132bf215546Sopenharmony_ci   struct hash_entry *e = _mesa_hash_table_search(fds_to_bo_sizes,
133bf215546Sopenharmony_ci                                                  (void*)(uintptr_t)fd);
134bf215546Sopenharmony_ci   struct refcnt_hash_table *r = e->data;
135bf215546Sopenharmony_ci   if (!--r->refcnt) {
136bf215546Sopenharmony_ci      _mesa_hash_table_remove(fds_to_bo_sizes, e);
137bf215546Sopenharmony_ci      _mesa_hash_table_destroy(r->t, NULL);
138bf215546Sopenharmony_ci      free(r);
139bf215546Sopenharmony_ci   }
140bf215546Sopenharmony_ci}
141bf215546Sopenharmony_ci
142bf215546Sopenharmony_ci/* Our goal is not to have noise good enough for crypto,
143bf215546Sopenharmony_ci * but instead values that are unique-ish enough that
144bf215546Sopenharmony_ci * it is incredibly unlikely that a buffer overwrite
145bf215546Sopenharmony_ci * will produce the exact same values.
146bf215546Sopenharmony_ci */
147bf215546Sopenharmony_cistatic uint8_t
148bf215546Sopenharmony_cinext_noise_value(uint8_t prev_noise)
149bf215546Sopenharmony_ci{
150bf215546Sopenharmony_ci   uint32_t v = prev_noise;
151bf215546Sopenharmony_ci   return (v * 103u + 227u) & 0xFF;
152bf215546Sopenharmony_ci}
153bf215546Sopenharmony_ci
154bf215546Sopenharmony_cistatic void
155bf215546Sopenharmony_cifill_noise_buffer(uint8_t *dst, uint8_t start, uint32_t length)
156bf215546Sopenharmony_ci{
157bf215546Sopenharmony_ci   for(uint32_t i = 0; i < length; ++i) {
158bf215546Sopenharmony_ci      dst[i] = start;
159bf215546Sopenharmony_ci      start = next_noise_value(start);
160bf215546Sopenharmony_ci   }
161bf215546Sopenharmony_ci}
162bf215546Sopenharmony_ci
163bf215546Sopenharmony_cistatic bool
164bf215546Sopenharmony_cipadding_is_good(int fd, uint32_t handle)
165bf215546Sopenharmony_ci{
166bf215546Sopenharmony_ci   struct drm_i915_gem_mmap mmap_arg = {
167bf215546Sopenharmony_ci      .handle = handle,
168bf215546Sopenharmony_ci      .offset = align64(bo_size(fd, handle), 4096),
169bf215546Sopenharmony_ci      .size = PADDING_SIZE,
170bf215546Sopenharmony_ci      .flags = 0,
171bf215546Sopenharmony_ci   };
172bf215546Sopenharmony_ci
173bf215546Sopenharmony_ci   /* Unknown bo, maybe prime or userptr. Ignore */
174bf215546Sopenharmony_ci   if (mmap_arg.offset == UINT64_MAX)
175bf215546Sopenharmony_ci      return true;
176bf215546Sopenharmony_ci
177bf215546Sopenharmony_ci   uint8_t *mapped;
178bf215546Sopenharmony_ci   int ret;
179bf215546Sopenharmony_ci   uint8_t expected_value;
180bf215546Sopenharmony_ci
181bf215546Sopenharmony_ci   ret = libc_ioctl(fd, DRM_IOCTL_I915_GEM_MMAP, &mmap_arg);
182bf215546Sopenharmony_ci   if (ret != 0) {
183bf215546Sopenharmony_ci      mesa_logd("Unable to map buffer %d for pad checking.", handle);
184bf215546Sopenharmony_ci      return false;
185bf215546Sopenharmony_ci   }
186bf215546Sopenharmony_ci
187bf215546Sopenharmony_ci   mapped = (uint8_t*) (uintptr_t) mmap_arg.addr_ptr;
188bf215546Sopenharmony_ci   /* bah-humbug, we need to see the latest contents and
189bf215546Sopenharmony_ci    * if the bo is not cache coherent we likely need to
190bf215546Sopenharmony_ci    * invalidate the cache lines to get it.
191bf215546Sopenharmony_ci    */
192bf215546Sopenharmony_ci   intel_invalidate_range(mapped, PADDING_SIZE);
193bf215546Sopenharmony_ci
194bf215546Sopenharmony_ci   expected_value = handle & 0xFF;
195bf215546Sopenharmony_ci   for (uint32_t i = 0; i < PADDING_SIZE; ++i) {
196bf215546Sopenharmony_ci      if (expected_value != mapped[i]) {
197bf215546Sopenharmony_ci         munmap(mapped, PADDING_SIZE);
198bf215546Sopenharmony_ci         return false;
199bf215546Sopenharmony_ci      }
200bf215546Sopenharmony_ci      expected_value = next_noise_value(expected_value);
201bf215546Sopenharmony_ci   }
202bf215546Sopenharmony_ci   munmap(mapped, PADDING_SIZE);
203bf215546Sopenharmony_ci
204bf215546Sopenharmony_ci   return true;
205bf215546Sopenharmony_ci}
206bf215546Sopenharmony_ci
207bf215546Sopenharmony_cistatic int
208bf215546Sopenharmony_cicreate_with_padding(int fd, struct drm_i915_gem_create *create)
209bf215546Sopenharmony_ci{
210bf215546Sopenharmony_ci   uint64_t original_size = create->size;
211bf215546Sopenharmony_ci
212bf215546Sopenharmony_ci   create->size = align64(original_size, 4096) + PADDING_SIZE;
213bf215546Sopenharmony_ci   int ret = libc_ioctl(fd, DRM_IOCTL_I915_GEM_CREATE, create);
214bf215546Sopenharmony_ci   create->size = original_size;
215bf215546Sopenharmony_ci
216bf215546Sopenharmony_ci   if (ret != 0)
217bf215546Sopenharmony_ci      return ret;
218bf215546Sopenharmony_ci
219bf215546Sopenharmony_ci   uint8_t *noise_values;
220bf215546Sopenharmony_ci   struct drm_i915_gem_mmap mmap_arg = {
221bf215546Sopenharmony_ci      .handle = create->handle,
222bf215546Sopenharmony_ci      .offset = align64(create->size, 4096),
223bf215546Sopenharmony_ci      .size = PADDING_SIZE,
224bf215546Sopenharmony_ci      .flags = 0,
225bf215546Sopenharmony_ci   };
226bf215546Sopenharmony_ci
227bf215546Sopenharmony_ci   ret = libc_ioctl(fd, DRM_IOCTL_I915_GEM_MMAP, &mmap_arg);
228bf215546Sopenharmony_ci   if (ret != 0) {
229bf215546Sopenharmony_ci      mesa_logd("Unable to map buffer %d for pad creation.\n", create->handle);
230bf215546Sopenharmony_ci      return 0;
231bf215546Sopenharmony_ci   }
232bf215546Sopenharmony_ci
233bf215546Sopenharmony_ci   noise_values = (uint8_t*) (uintptr_t) mmap_arg.addr_ptr;
234bf215546Sopenharmony_ci   fill_noise_buffer(noise_values, create->handle & 0xFF,
235bf215546Sopenharmony_ci                     PADDING_SIZE);
236bf215546Sopenharmony_ci   munmap(noise_values, PADDING_SIZE);
237bf215546Sopenharmony_ci
238bf215546Sopenharmony_ci   _mesa_hash_table_insert(bo_size_table(fd), (void*)(uintptr_t)create->handle,
239bf215546Sopenharmony_ci                           (void*)(uintptr_t)create->size);
240bf215546Sopenharmony_ci
241bf215546Sopenharmony_ci   return 0;
242bf215546Sopenharmony_ci}
243bf215546Sopenharmony_ci
244bf215546Sopenharmony_cistatic int
245bf215546Sopenharmony_ciexec_and_check_padding(int fd, unsigned long request,
246bf215546Sopenharmony_ci                       struct drm_i915_gem_execbuffer2 *exec)
247bf215546Sopenharmony_ci{
248bf215546Sopenharmony_ci   int ret = libc_ioctl(fd, request, exec);
249bf215546Sopenharmony_ci   if (ret != 0)
250bf215546Sopenharmony_ci      return ret;
251bf215546Sopenharmony_ci
252bf215546Sopenharmony_ci   struct drm_i915_gem_exec_object2 *objects =
253bf215546Sopenharmony_ci      (void*)(uintptr_t)exec->buffers_ptr;
254bf215546Sopenharmony_ci   uint32_t batch_bo = exec->flags & I915_EXEC_BATCH_FIRST ? objects[0].handle :
255bf215546Sopenharmony_ci      objects[exec->buffer_count - 1].handle;
256bf215546Sopenharmony_ci
257bf215546Sopenharmony_ci   struct drm_i915_gem_wait wait = {
258bf215546Sopenharmony_ci      .bo_handle = batch_bo,
259bf215546Sopenharmony_ci      .timeout_ns = -1,
260bf215546Sopenharmony_ci   };
261bf215546Sopenharmony_ci   ret = libc_ioctl(fd, DRM_IOCTL_I915_GEM_WAIT, &wait);
262bf215546Sopenharmony_ci   if (ret != 0)
263bf215546Sopenharmony_ci      return ret;
264bf215546Sopenharmony_ci
265bf215546Sopenharmony_ci   bool detected_out_of_bounds_write = false;
266bf215546Sopenharmony_ci
267bf215546Sopenharmony_ci   for (int i = 0; i < exec->buffer_count; i++) {
268bf215546Sopenharmony_ci      uint32_t handle = objects[i].handle;
269bf215546Sopenharmony_ci
270bf215546Sopenharmony_ci      if (!padding_is_good(fd, handle)) {
271bf215546Sopenharmony_ci         detected_out_of_bounds_write = true;
272bf215546Sopenharmony_ci         mesa_loge("Detected buffer out-of-bounds write in bo %d", handle);
273bf215546Sopenharmony_ci      }
274bf215546Sopenharmony_ci   }
275bf215546Sopenharmony_ci
276bf215546Sopenharmony_ci   if (unlikely(detected_out_of_bounds_write)) {
277bf215546Sopenharmony_ci      abort();
278bf215546Sopenharmony_ci   }
279bf215546Sopenharmony_ci
280bf215546Sopenharmony_ci   return 0;
281bf215546Sopenharmony_ci}
282bf215546Sopenharmony_ci
283bf215546Sopenharmony_cistatic int
284bf215546Sopenharmony_cigem_close(int fd, struct drm_gem_close *close)
285bf215546Sopenharmony_ci{
286bf215546Sopenharmony_ci   int ret = libc_ioctl(fd, DRM_IOCTL_GEM_CLOSE, close);
287bf215546Sopenharmony_ci   if (ret != 0)
288bf215546Sopenharmony_ci      return ret;
289bf215546Sopenharmony_ci
290bf215546Sopenharmony_ci   struct hash_table *t = bo_size_table(fd);
291bf215546Sopenharmony_ci   struct hash_entry *e =
292bf215546Sopenharmony_ci      _mesa_hash_table_search(t, (void*)(uintptr_t)close->handle);
293bf215546Sopenharmony_ci
294bf215546Sopenharmony_ci   if (e)
295bf215546Sopenharmony_ci      _mesa_hash_table_remove(t, e);
296bf215546Sopenharmony_ci
297bf215546Sopenharmony_ci   return 0;
298bf215546Sopenharmony_ci}
299bf215546Sopenharmony_ci
300bf215546Sopenharmony_cistatic bool
301bf215546Sopenharmony_ciis_i915(int fd) {
302bf215546Sopenharmony_ci   struct stat stat;
303bf215546Sopenharmony_ci   if (fstat(fd, &stat))
304bf215546Sopenharmony_ci      return false;
305bf215546Sopenharmony_ci
306bf215546Sopenharmony_ci   if (!S_ISCHR(stat.st_mode) || major(stat.st_rdev) != DRM_MAJOR)
307bf215546Sopenharmony_ci      return false;
308bf215546Sopenharmony_ci
309bf215546Sopenharmony_ci   char name[5] = "";
310bf215546Sopenharmony_ci   drm_version_t version = {
311bf215546Sopenharmony_ci      .name = name,
312bf215546Sopenharmony_ci      .name_len = sizeof(name) - 1,
313bf215546Sopenharmony_ci   };
314bf215546Sopenharmony_ci   if (libc_ioctl(fd, DRM_IOCTL_VERSION, &version))
315bf215546Sopenharmony_ci      return false;
316bf215546Sopenharmony_ci
317bf215546Sopenharmony_ci   return strcmp("i915", name) == 0;
318bf215546Sopenharmony_ci}
319bf215546Sopenharmony_ci
320bf215546Sopenharmony_ci__attribute__ ((visibility ("default"))) int
321bf215546Sopenharmony_ciopen(const char *path, int flags, ...)
322bf215546Sopenharmony_ci{
323bf215546Sopenharmony_ci   va_list args;
324bf215546Sopenharmony_ci   mode_t mode;
325bf215546Sopenharmony_ci
326bf215546Sopenharmony_ci   va_start(args, flags);
327bf215546Sopenharmony_ci   mode = va_arg(args, int);
328bf215546Sopenharmony_ci   va_end(args);
329bf215546Sopenharmony_ci
330bf215546Sopenharmony_ci   int fd = libc_open(path, flags, mode);
331bf215546Sopenharmony_ci
332bf215546Sopenharmony_ci   MUTEX_LOCK();
333bf215546Sopenharmony_ci
334bf215546Sopenharmony_ci   if (fd >= 0 && is_i915(fd))
335bf215546Sopenharmony_ci      add_drm_fd(fd);
336bf215546Sopenharmony_ci
337bf215546Sopenharmony_ci   MUTEX_UNLOCK();
338bf215546Sopenharmony_ci
339bf215546Sopenharmony_ci   return fd;
340bf215546Sopenharmony_ci}
341bf215546Sopenharmony_ci
342bf215546Sopenharmony_ci__attribute__ ((visibility ("default"), alias ("open"))) int
343bf215546Sopenharmony_ciopen64(const char *path, int flags, ...);
344bf215546Sopenharmony_ci
345bf215546Sopenharmony_ci__attribute__ ((visibility ("default"))) int
346bf215546Sopenharmony_ciclose(int fd)
347bf215546Sopenharmony_ci{
348bf215546Sopenharmony_ci   MUTEX_LOCK();
349bf215546Sopenharmony_ci
350bf215546Sopenharmony_ci   if (is_drm_fd(fd))
351bf215546Sopenharmony_ci      del_drm_fd(fd);
352bf215546Sopenharmony_ci
353bf215546Sopenharmony_ci   MUTEX_UNLOCK();
354bf215546Sopenharmony_ci
355bf215546Sopenharmony_ci   return libc_close(fd);
356bf215546Sopenharmony_ci}
357bf215546Sopenharmony_ci
358bf215546Sopenharmony_ci__attribute__ ((visibility ("default"))) int
359bf215546Sopenharmony_cifcntl(int fd, int cmd, ...)
360bf215546Sopenharmony_ci{
361bf215546Sopenharmony_ci   va_list args;
362bf215546Sopenharmony_ci   int param;
363bf215546Sopenharmony_ci
364bf215546Sopenharmony_ci   va_start(args, cmd);
365bf215546Sopenharmony_ci   param = va_arg(args, int);
366bf215546Sopenharmony_ci   va_end(args);
367bf215546Sopenharmony_ci
368bf215546Sopenharmony_ci   int res = libc_fcntl(fd, cmd, param);
369bf215546Sopenharmony_ci
370bf215546Sopenharmony_ci   MUTEX_LOCK();
371bf215546Sopenharmony_ci
372bf215546Sopenharmony_ci   if (is_drm_fd(fd) && cmd == F_DUPFD_CLOEXEC)
373bf215546Sopenharmony_ci      dup_drm_fd(fd, res);
374bf215546Sopenharmony_ci
375bf215546Sopenharmony_ci   MUTEX_UNLOCK();
376bf215546Sopenharmony_ci
377bf215546Sopenharmony_ci   return res;
378bf215546Sopenharmony_ci}
379bf215546Sopenharmony_ci
380bf215546Sopenharmony_ci__attribute__ ((visibility ("default"))) int
381bf215546Sopenharmony_ciioctl(int fd, unsigned long request, ...)
382bf215546Sopenharmony_ci{
383bf215546Sopenharmony_ci   int res;
384bf215546Sopenharmony_ci   va_list args;
385bf215546Sopenharmony_ci   void *argp;
386bf215546Sopenharmony_ci
387bf215546Sopenharmony_ci   MUTEX_LOCK();
388bf215546Sopenharmony_ci
389bf215546Sopenharmony_ci   va_start(args, request);
390bf215546Sopenharmony_ci   argp = va_arg(args, void *);
391bf215546Sopenharmony_ci   va_end(args);
392bf215546Sopenharmony_ci
393bf215546Sopenharmony_ci   if (_IOC_TYPE(request) == DRM_IOCTL_BASE && !is_drm_fd(fd) && is_i915(fd)) {
394bf215546Sopenharmony_ci      mesa_loge("missed drm fd %d", fd);
395bf215546Sopenharmony_ci      add_drm_fd(fd);
396bf215546Sopenharmony_ci   }
397bf215546Sopenharmony_ci
398bf215546Sopenharmony_ci   if (is_drm_fd(fd)) {
399bf215546Sopenharmony_ci      switch (request) {
400bf215546Sopenharmony_ci      case DRM_IOCTL_GEM_CLOSE:
401bf215546Sopenharmony_ci         res = gem_close(fd, (struct drm_gem_close*)argp);
402bf215546Sopenharmony_ci         goto out;
403bf215546Sopenharmony_ci
404bf215546Sopenharmony_ci      case DRM_IOCTL_I915_GEM_CREATE:
405bf215546Sopenharmony_ci         res = create_with_padding(fd, (struct drm_i915_gem_create*)argp);
406bf215546Sopenharmony_ci         goto out;
407bf215546Sopenharmony_ci
408bf215546Sopenharmony_ci      case DRM_IOCTL_I915_GEM_EXECBUFFER2:
409bf215546Sopenharmony_ci      case DRM_IOCTL_I915_GEM_EXECBUFFER2_WR:
410bf215546Sopenharmony_ci         res = exec_and_check_padding(fd, request,
411bf215546Sopenharmony_ci                                      (struct drm_i915_gem_execbuffer2*)argp);
412bf215546Sopenharmony_ci         goto out;
413bf215546Sopenharmony_ci
414bf215546Sopenharmony_ci      default:
415bf215546Sopenharmony_ci         break;
416bf215546Sopenharmony_ci      }
417bf215546Sopenharmony_ci   }
418bf215546Sopenharmony_ci   res = libc_ioctl(fd, request, argp);
419bf215546Sopenharmony_ci
420bf215546Sopenharmony_ci out:
421bf215546Sopenharmony_ci   MUTEX_UNLOCK();
422bf215546Sopenharmony_ci   return res;
423bf215546Sopenharmony_ci}
424bf215546Sopenharmony_ci
425bf215546Sopenharmony_cistatic void __attribute__ ((constructor))
426bf215546Sopenharmony_ciinit(void)
427bf215546Sopenharmony_ci{
428bf215546Sopenharmony_ci   fds_to_bo_sizes = _mesa_pointer_hash_table_create(NULL);
429bf215546Sopenharmony_ci   libc_open = dlsym(RTLD_NEXT, "open");
430bf215546Sopenharmony_ci   libc_close = dlsym(RTLD_NEXT, "close");
431bf215546Sopenharmony_ci   libc_fcntl = dlsym(RTLD_NEXT, "fcntl");
432bf215546Sopenharmony_ci   libc_ioctl = dlsym(RTLD_NEXT, "ioctl");
433bf215546Sopenharmony_ci}
434