1b8e80941Smrg/*
2b8e80941Smrg * Copyright © 2015 Intel Corporation
3b8e80941Smrg *
4b8e80941Smrg * Permission is hereby granted, free of charge, to any person obtaining a
5b8e80941Smrg * copy of this software and associated documentation files (the "Software"),
6b8e80941Smrg * to deal in the Software without restriction, including without limitation
7b8e80941Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8b8e80941Smrg * and/or sell copies of the Software, and to permit persons to whom the
9b8e80941Smrg * Software is furnished to do so, subject to the following conditions:
10b8e80941Smrg *
11b8e80941Smrg * The above copyright notice and this permission notice (including the next
12b8e80941Smrg * paragraph) shall be included in all copies or substantial portions of the
13b8e80941Smrg * Software.
14b8e80941Smrg *
15b8e80941Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16b8e80941Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17b8e80941Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18b8e80941Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19b8e80941Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20b8e80941Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21b8e80941Smrg * IN THE SOFTWARE.
22b8e80941Smrg */
23b8e80941Smrg
24b8e80941Smrg#include <stdlib.h>
25b8e80941Smrg#include <stdio.h>
26b8e80941Smrg#include <string.h>
27b8e80941Smrg#include <stdint.h>
28b8e80941Smrg#include <stdbool.h>
29b8e80941Smrg#include <signal.h>
30b8e80941Smrg#include <stdarg.h>
31b8e80941Smrg#include <fcntl.h>
32b8e80941Smrg#include <sys/types.h>
33b8e80941Smrg#include <sys/sysmacros.h>
34b8e80941Smrg#include <sys/stat.h>
35b8e80941Smrg#include <sys/ioctl.h>
36b8e80941Smrg#include <unistd.h>
37b8e80941Smrg#include <errno.h>
38b8e80941Smrg#include <sys/mman.h>
39b8e80941Smrg#include <dlfcn.h>
40b8e80941Smrg#include "drm-uapi/i915_drm.h"
41b8e80941Smrg#include <inttypes.h>
42b8e80941Smrg
43b8e80941Smrg#include "intel_aub.h"
44b8e80941Smrg#include "aub_write.h"
45b8e80941Smrg
46b8e80941Smrg#include "dev/gen_device_info.h"
47b8e80941Smrg#include "util/macros.h"
48b8e80941Smrg
49b8e80941Smrgstatic int close_init_helper(int fd);
50b8e80941Smrgstatic int ioctl_init_helper(int fd, unsigned long request, ...);
51b8e80941Smrg
52b8e80941Smrgstatic int (*libc_close)(int fd) = close_init_helper;
53b8e80941Smrgstatic int (*libc_ioctl)(int fd, unsigned long request, ...) = ioctl_init_helper;
54b8e80941Smrg
55b8e80941Smrgstatic int drm_fd = -1;
56b8e80941Smrgstatic char *output_filename = NULL;
57b8e80941Smrgstatic FILE *output_file = NULL;
58b8e80941Smrgstatic int verbose = 0;
59b8e80941Smrgstatic bool device_override;
60b8e80941Smrg
61b8e80941Smrg#define MAX_FD_COUNT 64
62b8e80941Smrg#define MAX_BO_COUNT 64 * 1024
63b8e80941Smrg
64b8e80941Smrgstruct bo {
65b8e80941Smrg   uint32_t size;
66b8e80941Smrg   uint64_t offset;
67b8e80941Smrg   void *map;
68b8e80941Smrg};
69b8e80941Smrg
70b8e80941Smrgstatic struct bo *bos;
71b8e80941Smrg
72b8e80941Smrg#define DRM_MAJOR 226
73b8e80941Smrg
74b8e80941Smrg/* We set bit 0 in the map pointer for userptr BOs so we know not to
75b8e80941Smrg * munmap them on DRM_IOCTL_GEM_CLOSE.
76b8e80941Smrg */
77b8e80941Smrg#define USERPTR_FLAG 1
78b8e80941Smrg#define IS_USERPTR(p) ((uintptr_t) (p) & USERPTR_FLAG)
79b8e80941Smrg#define GET_PTR(p) ( (void *) ((uintptr_t) p & ~(uintptr_t) 1) )
80b8e80941Smrg
81b8e80941Smrgstatic void __attribute__ ((format(__printf__, 2, 3)))
82b8e80941Smrgfail_if(int cond, const char *format, ...)
83b8e80941Smrg{
84b8e80941Smrg   va_list args;
85b8e80941Smrg
86b8e80941Smrg   if (!cond)
87b8e80941Smrg      return;
88b8e80941Smrg
89b8e80941Smrg   va_start(args, format);
90b8e80941Smrg   fprintf(stderr, "intel_dump_gpu: ");
91b8e80941Smrg   vfprintf(stderr, format, args);
92b8e80941Smrg   va_end(args);
93b8e80941Smrg
94b8e80941Smrg   raise(SIGTRAP);
95b8e80941Smrg}
96b8e80941Smrg
97b8e80941Smrgstatic struct bo *
98b8e80941Smrgget_bo(unsigned fd, uint32_t handle)
99b8e80941Smrg{
100b8e80941Smrg   struct bo *bo;
101b8e80941Smrg
102b8e80941Smrg   fail_if(handle >= MAX_BO_COUNT, "bo handle too large\n");
103b8e80941Smrg   fail_if(fd >= MAX_FD_COUNT, "bo fd too large\n");
104b8e80941Smrg   bo = &bos[handle + fd * MAX_BO_COUNT];
105b8e80941Smrg
106b8e80941Smrg   return bo;
107b8e80941Smrg}
108b8e80941Smrg
109b8e80941Smrgstatic inline uint32_t
110b8e80941Smrgalign_u32(uint32_t v, uint32_t a)
111b8e80941Smrg{
112b8e80941Smrg   return (v + a - 1) & ~(a - 1);
113b8e80941Smrg}
114b8e80941Smrg
115b8e80941Smrgstatic struct gen_device_info devinfo = {0};
116b8e80941Smrgstatic uint32_t device = 0;
117b8e80941Smrgstatic struct aub_file aub_file;
118b8e80941Smrg
119b8e80941Smrgstatic void *
120b8e80941Smrgrelocate_bo(int fd, struct bo *bo, const struct drm_i915_gem_execbuffer2 *execbuffer2,
121b8e80941Smrg            const struct drm_i915_gem_exec_object2 *obj)
122b8e80941Smrg{
123b8e80941Smrg   const struct drm_i915_gem_exec_object2 *exec_objects =
124b8e80941Smrg      (struct drm_i915_gem_exec_object2 *) (uintptr_t) execbuffer2->buffers_ptr;
125b8e80941Smrg   const struct drm_i915_gem_relocation_entry *relocs =
126b8e80941Smrg      (const struct drm_i915_gem_relocation_entry *) (uintptr_t) obj->relocs_ptr;
127b8e80941Smrg   void *relocated;
128b8e80941Smrg   int handle;
129b8e80941Smrg
130b8e80941Smrg   relocated = malloc(bo->size);
131b8e80941Smrg   fail_if(relocated == NULL, "out of memory\n");
132b8e80941Smrg   memcpy(relocated, GET_PTR(bo->map), bo->size);
133b8e80941Smrg   for (size_t i = 0; i < obj->relocation_count; i++) {
134b8e80941Smrg      fail_if(relocs[i].offset >= bo->size, "reloc outside bo\n");
135b8e80941Smrg
136b8e80941Smrg      if (execbuffer2->flags & I915_EXEC_HANDLE_LUT)
137b8e80941Smrg         handle = exec_objects[relocs[i].target_handle].handle;
138b8e80941Smrg      else
139b8e80941Smrg         handle = relocs[i].target_handle;
140b8e80941Smrg
141b8e80941Smrg      aub_write_reloc(&devinfo, ((char *)relocated) + relocs[i].offset,
142b8e80941Smrg                      get_bo(fd, handle)->offset + relocs[i].delta);
143b8e80941Smrg   }
144b8e80941Smrg
145b8e80941Smrg   return relocated;
146b8e80941Smrg}
147b8e80941Smrg
148b8e80941Smrgstatic int
149b8e80941Smrggem_ioctl(int fd, unsigned long request, void *argp)
150b8e80941Smrg{
151b8e80941Smrg   int ret;
152b8e80941Smrg
153b8e80941Smrg   do {
154b8e80941Smrg      ret = libc_ioctl(fd, request, argp);
155b8e80941Smrg   } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
156b8e80941Smrg
157b8e80941Smrg   return ret;
158b8e80941Smrg}
159b8e80941Smrg
160b8e80941Smrgstatic void *
161b8e80941Smrggem_mmap(int fd, uint32_t handle, uint64_t offset, uint64_t size)
162b8e80941Smrg{
163b8e80941Smrg   struct drm_i915_gem_mmap mmap = {
164b8e80941Smrg      .handle = handle,
165b8e80941Smrg      .offset = offset,
166b8e80941Smrg      .size = size
167b8e80941Smrg   };
168b8e80941Smrg
169b8e80941Smrg   if (gem_ioctl(fd, DRM_IOCTL_I915_GEM_MMAP, &mmap) == -1)
170b8e80941Smrg      return MAP_FAILED;
171b8e80941Smrg
172b8e80941Smrg   return (void *)(uintptr_t) mmap.addr_ptr;
173b8e80941Smrg}
174b8e80941Smrg
175b8e80941Smrgstatic int
176b8e80941Smrggem_get_param(int fd, uint32_t param)
177b8e80941Smrg{
178b8e80941Smrg   int value;
179b8e80941Smrg   drm_i915_getparam_t gp = {
180b8e80941Smrg      .param = param,
181b8e80941Smrg      .value = &value
182b8e80941Smrg   };
183b8e80941Smrg
184b8e80941Smrg   if (gem_ioctl(fd, DRM_IOCTL_I915_GETPARAM, &gp) == -1)
185b8e80941Smrg      return 0;
186b8e80941Smrg
187b8e80941Smrg   return value;
188b8e80941Smrg}
189b8e80941Smrg
190b8e80941Smrgstatic enum drm_i915_gem_engine_class
191b8e80941Smrgengine_class_from_ring_flag(uint32_t ring_flag)
192b8e80941Smrg{
193b8e80941Smrg   switch (ring_flag) {
194b8e80941Smrg   case I915_EXEC_DEFAULT:
195b8e80941Smrg   case I915_EXEC_RENDER:
196b8e80941Smrg      return I915_ENGINE_CLASS_RENDER;
197b8e80941Smrg   case I915_EXEC_BSD:
198b8e80941Smrg      return I915_ENGINE_CLASS_VIDEO;
199b8e80941Smrg   case I915_EXEC_BLT:
200b8e80941Smrg      return I915_ENGINE_CLASS_COPY;
201b8e80941Smrg   case I915_EXEC_VEBOX:
202b8e80941Smrg      return I915_ENGINE_CLASS_VIDEO_ENHANCE;
203b8e80941Smrg   default:
204b8e80941Smrg      return I915_ENGINE_CLASS_INVALID;
205b8e80941Smrg   }
206b8e80941Smrg}
207b8e80941Smrg
208b8e80941Smrgstatic void
209b8e80941Smrgdump_execbuffer2(int fd, struct drm_i915_gem_execbuffer2 *execbuffer2)
210b8e80941Smrg{
211b8e80941Smrg   struct drm_i915_gem_exec_object2 *exec_objects =
212b8e80941Smrg      (struct drm_i915_gem_exec_object2 *) (uintptr_t) execbuffer2->buffers_ptr;
213b8e80941Smrg   uint32_t ring_flag = execbuffer2->flags & I915_EXEC_RING_MASK;
214b8e80941Smrg   uint32_t offset;
215b8e80941Smrg   struct drm_i915_gem_exec_object2 *obj;
216b8e80941Smrg   struct bo *bo, *batch_bo;
217b8e80941Smrg   int batch_index;
218b8e80941Smrg   void *data;
219b8e80941Smrg
220b8e80941Smrg   /* We can't do this at open time as we're not yet authenticated. */
221b8e80941Smrg   if (device == 0) {
222b8e80941Smrg      device = gem_get_param(fd, I915_PARAM_CHIPSET_ID);
223b8e80941Smrg      fail_if(device == 0 || devinfo.gen == 0, "failed to identify chipset\n");
224b8e80941Smrg   }
225b8e80941Smrg   if (devinfo.gen == 0) {
226b8e80941Smrg      fail_if(!gen_get_device_info(device, &devinfo),
227b8e80941Smrg              "failed to identify chipset=0x%x\n", device);
228b8e80941Smrg
229b8e80941Smrg      aub_file_init(&aub_file, output_file,
230b8e80941Smrg                    verbose == 2 ? stdout : NULL,
231b8e80941Smrg                    device, program_invocation_short_name);
232b8e80941Smrg      aub_write_default_setup(&aub_file);
233b8e80941Smrg
234b8e80941Smrg      if (verbose)
235b8e80941Smrg         printf("[running, output file %s, chipset id 0x%04x, gen %d]\n",
236b8e80941Smrg                output_filename, device, devinfo.gen);
237b8e80941Smrg   }
238b8e80941Smrg
239b8e80941Smrg   if (aub_use_execlists(&aub_file))
240b8e80941Smrg      offset = 0x1000;
241b8e80941Smrg   else
242b8e80941Smrg      offset = aub_gtt_size(&aub_file);
243b8e80941Smrg
244b8e80941Smrg   if (verbose)
245b8e80941Smrg      printf("Dumping execbuffer2:\n");
246b8e80941Smrg
247b8e80941Smrg   for (uint32_t i = 0; i < execbuffer2->buffer_count; i++) {
248b8e80941Smrg      obj = &exec_objects[i];
249b8e80941Smrg      bo = get_bo(fd, obj->handle);
250b8e80941Smrg
251b8e80941Smrg      /* If bo->size == 0, this means they passed us an invalid
252b8e80941Smrg       * buffer.  The kernel will reject it and so should we.
253b8e80941Smrg       */
254b8e80941Smrg      if (bo->size == 0) {
255b8e80941Smrg         if (verbose)
256b8e80941Smrg            printf("BO #%d is invalid!\n", obj->handle);
257b8e80941Smrg         return;
258b8e80941Smrg      }
259b8e80941Smrg
260b8e80941Smrg      if (obj->flags & EXEC_OBJECT_PINNED) {
261b8e80941Smrg         bo->offset = obj->offset;
262b8e80941Smrg         if (verbose)
263b8e80941Smrg            printf("BO #%d (%dB) pinned @ 0x%lx\n",
264b8e80941Smrg                   obj->handle, bo->size, bo->offset);
265b8e80941Smrg      } else {
266b8e80941Smrg         if (obj->alignment != 0)
267b8e80941Smrg            offset = align_u32(offset, obj->alignment);
268b8e80941Smrg         bo->offset = offset;
269b8e80941Smrg         if (verbose)
270b8e80941Smrg            printf("BO #%d (%dB) @ 0x%lx\n", obj->handle,
271b8e80941Smrg                   bo->size, bo->offset);
272b8e80941Smrg         offset = align_u32(offset + bo->size + 4095, 4096);
273b8e80941Smrg      }
274b8e80941Smrg
275b8e80941Smrg      if (bo->map == NULL && bo->size > 0)
276b8e80941Smrg         bo->map = gem_mmap(fd, obj->handle, 0, bo->size);
277b8e80941Smrg      fail_if(bo->map == MAP_FAILED, "bo mmap failed\n");
278b8e80941Smrg
279b8e80941Smrg      if (aub_use_execlists(&aub_file))
280b8e80941Smrg         aub_map_ppgtt(&aub_file, bo->offset, bo->size);
281b8e80941Smrg   }
282b8e80941Smrg
283b8e80941Smrg   batch_index = (execbuffer2->flags & I915_EXEC_BATCH_FIRST) ? 0 :
284b8e80941Smrg      execbuffer2->buffer_count - 1;
285b8e80941Smrg   batch_bo = get_bo(fd, exec_objects[batch_index].handle);
286b8e80941Smrg   for (uint32_t i = 0; i < execbuffer2->buffer_count; i++) {
287b8e80941Smrg      obj = &exec_objects[i];
288b8e80941Smrg      bo = get_bo(fd, obj->handle);
289b8e80941Smrg
290b8e80941Smrg      if (obj->relocation_count > 0)
291b8e80941Smrg         data = relocate_bo(fd, bo, execbuffer2, obj);
292b8e80941Smrg      else
293b8e80941Smrg         data = bo->map;
294b8e80941Smrg
295b8e80941Smrg      if (bo == batch_bo) {
296b8e80941Smrg         aub_write_trace_block(&aub_file, AUB_TRACE_TYPE_BATCH,
297b8e80941Smrg                               GET_PTR(data), bo->size, bo->offset);
298b8e80941Smrg      } else {
299b8e80941Smrg         aub_write_trace_block(&aub_file, AUB_TRACE_TYPE_NOTYPE,
300b8e80941Smrg                               GET_PTR(data), bo->size, bo->offset);
301b8e80941Smrg      }
302b8e80941Smrg
303b8e80941Smrg      if (data != bo->map)
304b8e80941Smrg         free(data);
305b8e80941Smrg   }
306b8e80941Smrg
307b8e80941Smrg   aub_write_exec(&aub_file,
308b8e80941Smrg                  batch_bo->offset + execbuffer2->batch_start_offset,
309b8e80941Smrg                  offset, engine_class_from_ring_flag(ring_flag));
310b8e80941Smrg
311b8e80941Smrg   if (device_override &&
312b8e80941Smrg       (execbuffer2->flags & I915_EXEC_FENCE_ARRAY) != 0) {
313b8e80941Smrg      struct drm_i915_gem_exec_fence *fences =
314b8e80941Smrg         (void*)(uintptr_t)execbuffer2->cliprects_ptr;
315b8e80941Smrg      for (uint32_t i = 0; i < execbuffer2->num_cliprects; i++) {
316b8e80941Smrg         if ((fences[i].flags & I915_EXEC_FENCE_SIGNAL) != 0) {
317b8e80941Smrg            struct drm_syncobj_array arg = {
318b8e80941Smrg               .handles = (uintptr_t)&fences[i].handle,
319b8e80941Smrg               .count_handles = 1,
320b8e80941Smrg               .pad = 0,
321b8e80941Smrg            };
322b8e80941Smrg            libc_ioctl(fd, DRM_IOCTL_SYNCOBJ_SIGNAL, &arg);
323b8e80941Smrg         }
324b8e80941Smrg      }
325b8e80941Smrg   }
326b8e80941Smrg}
327b8e80941Smrg
328b8e80941Smrgstatic void
329b8e80941Smrgadd_new_bo(unsigned fd, int handle, uint64_t size, void *map)
330b8e80941Smrg{
331b8e80941Smrg   struct bo *bo = &bos[handle + fd * MAX_BO_COUNT];
332b8e80941Smrg
333b8e80941Smrg   fail_if(handle >= MAX_BO_COUNT, "bo handle out of range\n");
334b8e80941Smrg   fail_if(fd >= MAX_FD_COUNT, "bo fd out of range\n");
335b8e80941Smrg   fail_if(size == 0, "bo size is invalid\n");
336b8e80941Smrg
337b8e80941Smrg   bo->size = size;
338b8e80941Smrg   bo->map = map;
339b8e80941Smrg}
340b8e80941Smrg
341b8e80941Smrgstatic void
342b8e80941Smrgremove_bo(int fd, int handle)
343b8e80941Smrg{
344b8e80941Smrg   struct bo *bo = get_bo(fd, handle);
345b8e80941Smrg
346b8e80941Smrg   if (bo->map && !IS_USERPTR(bo->map))
347b8e80941Smrg      munmap(bo->map, bo->size);
348b8e80941Smrg   bo->size = 0;
349b8e80941Smrg   bo->map = NULL;
350b8e80941Smrg}
351b8e80941Smrg
352b8e80941Smrg__attribute__ ((visibility ("default"))) int
353b8e80941Smrgclose(int fd)
354b8e80941Smrg{
355b8e80941Smrg   if (fd == drm_fd)
356b8e80941Smrg      drm_fd = -1;
357b8e80941Smrg
358b8e80941Smrg   return libc_close(fd);
359b8e80941Smrg}
360b8e80941Smrg
361b8e80941Smrgstatic void
362b8e80941Smrgmaybe_init(void)
363b8e80941Smrg{
364b8e80941Smrg   static bool initialized = false;
365b8e80941Smrg   FILE *config;
366b8e80941Smrg   char *key, *value;
367b8e80941Smrg
368b8e80941Smrg   if (initialized)
369b8e80941Smrg      return;
370b8e80941Smrg
371b8e80941Smrg   initialized = true;
372b8e80941Smrg
373b8e80941Smrg   config = fopen(getenv("INTEL_DUMP_GPU_CONFIG"), "r");
374b8e80941Smrg   while (fscanf(config, "%m[^=]=%m[^\n]\n", &key, &value) != EOF) {
375b8e80941Smrg      if (!strcmp(key, "verbose")) {
376b8e80941Smrg         if (!strcmp(value, "1")) {
377b8e80941Smrg            verbose = 1;
378b8e80941Smrg         } else if (!strcmp(value, "2")) {
379b8e80941Smrg            verbose = 2;
380b8e80941Smrg         }
381b8e80941Smrg      } else if (!strcmp(key, "device")) {
382b8e80941Smrg         fail_if(device != 0, "Device/Platform override specified multiple times.");
383b8e80941Smrg         fail_if(sscanf(value, "%i", &device) != 1,
384b8e80941Smrg                 "failed to parse device id '%s'",
385b8e80941Smrg                 value);
386b8e80941Smrg         device_override = true;
387b8e80941Smrg      } else if (!strcmp(key, "platform")) {
388b8e80941Smrg         fail_if(device != 0, "Device/Platform override specified multiple times.");
389b8e80941Smrg         device = gen_device_name_to_pci_device_id(value);
390b8e80941Smrg         fail_if(device == -1, "Unknown platform '%s'", value);
391b8e80941Smrg         device_override = true;
392b8e80941Smrg      } else if (!strcmp(key, "file")) {
393b8e80941Smrg         output_filename = strdup(value);
394b8e80941Smrg         output_file = fopen(output_filename, "w+");
395b8e80941Smrg         fail_if(output_file == NULL,
396b8e80941Smrg                 "failed to open file '%s'\n",
397b8e80941Smrg                 output_filename);
398b8e80941Smrg      } else {
399b8e80941Smrg         fprintf(stderr, "unknown option '%s'\n", key);
400b8e80941Smrg      }
401b8e80941Smrg
402b8e80941Smrg      free(key);
403b8e80941Smrg      free(value);
404b8e80941Smrg   }
405b8e80941Smrg   fclose(config);
406b8e80941Smrg
407b8e80941Smrg   bos = calloc(MAX_FD_COUNT * MAX_BO_COUNT, sizeof(bos[0]));
408b8e80941Smrg   fail_if(bos == NULL, "out of memory\n");
409b8e80941Smrg}
410b8e80941Smrg
411b8e80941Smrg__attribute__ ((visibility ("default"))) int
412b8e80941Smrgioctl(int fd, unsigned long request, ...)
413b8e80941Smrg{
414b8e80941Smrg   va_list args;
415b8e80941Smrg   void *argp;
416b8e80941Smrg   int ret;
417b8e80941Smrg   struct stat buf;
418b8e80941Smrg
419b8e80941Smrg   va_start(args, request);
420b8e80941Smrg   argp = va_arg(args, void *);
421b8e80941Smrg   va_end(args);
422b8e80941Smrg
423b8e80941Smrg   if (_IOC_TYPE(request) == DRM_IOCTL_BASE &&
424b8e80941Smrg       drm_fd != fd && fstat(fd, &buf) == 0 &&
425b8e80941Smrg       (buf.st_mode & S_IFMT) == S_IFCHR && major(buf.st_rdev) == DRM_MAJOR) {
426b8e80941Smrg      drm_fd = fd;
427b8e80941Smrg      if (verbose)
428b8e80941Smrg         printf("[intercept drm ioctl on fd %d]\n", fd);
429b8e80941Smrg   }
430b8e80941Smrg
431b8e80941Smrg   if (fd == drm_fd) {
432b8e80941Smrg      maybe_init();
433b8e80941Smrg
434b8e80941Smrg      switch (request) {
435b8e80941Smrg      case DRM_IOCTL_I915_GETPARAM: {
436b8e80941Smrg         struct drm_i915_getparam *getparam = argp;
437b8e80941Smrg
438b8e80941Smrg         if (device_override && getparam->param == I915_PARAM_CHIPSET_ID) {
439b8e80941Smrg            *getparam->value = device;
440b8e80941Smrg            return 0;
441b8e80941Smrg         }
442b8e80941Smrg
443b8e80941Smrg         ret = libc_ioctl(fd, request, argp);
444b8e80941Smrg
445b8e80941Smrg         /* If the application looks up chipset_id
446b8e80941Smrg          * (they typically do), we'll piggy-back on
447b8e80941Smrg          * their ioctl and store the id for later
448b8e80941Smrg          * use. */
449b8e80941Smrg         if (ret == 0 && getparam->param == I915_PARAM_CHIPSET_ID)
450b8e80941Smrg            device = *getparam->value;
451b8e80941Smrg
452b8e80941Smrg         return ret;
453b8e80941Smrg      }
454b8e80941Smrg
455b8e80941Smrg      case DRM_IOCTL_I915_GEM_EXECBUFFER: {
456b8e80941Smrg         static bool once;
457b8e80941Smrg         if (!once) {
458b8e80941Smrg            fprintf(stderr,
459b8e80941Smrg                    "application uses DRM_IOCTL_I915_GEM_EXECBUFFER, not handled\n");
460b8e80941Smrg            once = true;
461b8e80941Smrg         }
462b8e80941Smrg         return libc_ioctl(fd, request, argp);
463b8e80941Smrg      }
464b8e80941Smrg
465b8e80941Smrg      case DRM_IOCTL_I915_GEM_EXECBUFFER2:
466b8e80941Smrg      case DRM_IOCTL_I915_GEM_EXECBUFFER2_WR: {
467b8e80941Smrg         dump_execbuffer2(fd, argp);
468b8e80941Smrg         if (device_override)
469b8e80941Smrg            return 0;
470b8e80941Smrg
471b8e80941Smrg         return libc_ioctl(fd, request, argp);
472b8e80941Smrg      }
473b8e80941Smrg
474b8e80941Smrg      case DRM_IOCTL_I915_GEM_CREATE: {
475b8e80941Smrg         struct drm_i915_gem_create *create = argp;
476b8e80941Smrg
477b8e80941Smrg         ret = libc_ioctl(fd, request, argp);
478b8e80941Smrg         if (ret == 0)
479b8e80941Smrg            add_new_bo(fd, create->handle, create->size, NULL);
480b8e80941Smrg
481b8e80941Smrg         return ret;
482b8e80941Smrg      }
483b8e80941Smrg
484b8e80941Smrg      case DRM_IOCTL_I915_GEM_USERPTR: {
485b8e80941Smrg         struct drm_i915_gem_userptr *userptr = argp;
486b8e80941Smrg
487b8e80941Smrg         ret = libc_ioctl(fd, request, argp);
488b8e80941Smrg         if (ret == 0)
489b8e80941Smrg            add_new_bo(fd, userptr->handle, userptr->user_size,
490b8e80941Smrg                       (void *) (uintptr_t) (userptr->user_ptr | USERPTR_FLAG));
491b8e80941Smrg
492b8e80941Smrg         return ret;
493b8e80941Smrg      }
494b8e80941Smrg
495b8e80941Smrg      case DRM_IOCTL_GEM_CLOSE: {
496b8e80941Smrg         struct drm_gem_close *close = argp;
497b8e80941Smrg
498b8e80941Smrg         remove_bo(fd, close->handle);
499b8e80941Smrg
500b8e80941Smrg         return libc_ioctl(fd, request, argp);
501b8e80941Smrg      }
502b8e80941Smrg
503b8e80941Smrg      case DRM_IOCTL_GEM_OPEN: {
504b8e80941Smrg         struct drm_gem_open *open = argp;
505b8e80941Smrg
506b8e80941Smrg         ret = libc_ioctl(fd, request, argp);
507b8e80941Smrg         if (ret == 0)
508b8e80941Smrg            add_new_bo(fd, open->handle, open->size, NULL);
509b8e80941Smrg
510b8e80941Smrg         return ret;
511b8e80941Smrg      }
512b8e80941Smrg
513b8e80941Smrg      case DRM_IOCTL_PRIME_FD_TO_HANDLE: {
514b8e80941Smrg         struct drm_prime_handle *prime = argp;
515b8e80941Smrg
516b8e80941Smrg         ret = libc_ioctl(fd, request, argp);
517b8e80941Smrg         if (ret == 0) {
518b8e80941Smrg            off_t size;
519b8e80941Smrg
520b8e80941Smrg            size = lseek(prime->fd, 0, SEEK_END);
521b8e80941Smrg            fail_if(size == -1, "failed to get prime bo size\n");
522b8e80941Smrg            add_new_bo(fd, prime->handle, size, NULL);
523b8e80941Smrg
524b8e80941Smrg         }
525b8e80941Smrg
526b8e80941Smrg         return ret;
527b8e80941Smrg      }
528b8e80941Smrg
529b8e80941Smrg      default:
530b8e80941Smrg         return libc_ioctl(fd, request, argp);
531b8e80941Smrg      }
532b8e80941Smrg   } else {
533b8e80941Smrg      return libc_ioctl(fd, request, argp);
534b8e80941Smrg   }
535b8e80941Smrg}
536b8e80941Smrg
537b8e80941Smrgstatic void
538b8e80941Smrginit(void)
539b8e80941Smrg{
540b8e80941Smrg   libc_close = dlsym(RTLD_NEXT, "close");
541b8e80941Smrg   libc_ioctl = dlsym(RTLD_NEXT, "ioctl");
542b8e80941Smrg   fail_if(libc_close == NULL || libc_ioctl == NULL,
543b8e80941Smrg           "failed to get libc ioctl or close\n");
544b8e80941Smrg}
545b8e80941Smrg
546b8e80941Smrgstatic int
547b8e80941Smrgclose_init_helper(int fd)
548b8e80941Smrg{
549b8e80941Smrg   init();
550b8e80941Smrg   return libc_close(fd);
551b8e80941Smrg}
552b8e80941Smrg
553b8e80941Smrgstatic int
554b8e80941Smrgioctl_init_helper(int fd, unsigned long request, ...)
555b8e80941Smrg{
556b8e80941Smrg   va_list args;
557b8e80941Smrg   void *argp;
558b8e80941Smrg
559b8e80941Smrg   va_start(args, request);
560b8e80941Smrg   argp = va_arg(args, void *);
561b8e80941Smrg   va_end(args);
562b8e80941Smrg
563b8e80941Smrg   init();
564b8e80941Smrg   return libc_ioctl(fd, request, argp);
565b8e80941Smrg}
566b8e80941Smrg
567b8e80941Smrgstatic void __attribute__ ((destructor))
568b8e80941Smrgfini(void)
569b8e80941Smrg{
570b8e80941Smrg   if (devinfo.gen != 0) {
571b8e80941Smrg      free(output_filename);
572b8e80941Smrg      aub_file_finish(&aub_file);
573b8e80941Smrg      free(bos);
574b8e80941Smrg   }
575b8e80941Smrg}
576