2 * Copyright © 2015 Intel Corporation
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
32 #include <sys/types.h>
33 #include <sys/sysmacros.h>
35 #include <sys/ioctl.h>
43 #include "intel_aub.h"
44 #include "aub_write.h"
46 #include "dev/gen_device_info.h"
47 #include "util/macros.h"
49 static int close_init_helper(int fd
);
50 static int ioctl_init_helper(int fd
, unsigned long request
, ...);
52 static int (*libc_close
)(int fd
) = close_init_helper
;
53 static int (*libc_ioctl
)(int fd
, unsigned long request
, ...) = ioctl_init_helper
;
55 static int drm_fd
= -1;
56 static char *output_filename
= NULL
;
57 static FILE *output_file
= NULL
;
58 static int verbose
= 0;
59 static bool device_override
;
61 #define MAX_BO_COUNT 64 * 1024
69 static struct bo
*bos
;
73 /* We set bit 0 in the map pointer for userptr BOs so we know not to
74 * munmap them on DRM_IOCTL_GEM_CLOSE.
76 #define USERPTR_FLAG 1
77 #define IS_USERPTR(p) ((uintptr_t) (p) & USERPTR_FLAG)
78 #define GET_PTR(p) ( (void *) ((uintptr_t) p & ~(uintptr_t) 1) )
80 static void __attribute__ ((format(__printf__
, 2, 3)))
81 fail_if(int cond
, const char *format
, ...)
88 va_start(args
, format
);
89 fprintf(stderr
, "intel_dump_gpu: ");
90 vfprintf(stderr
, format
, args
);
97 get_bo(uint32_t handle
)
101 fail_if(handle
>= MAX_BO_COUNT
, "bo handle too large\n");
107 static inline uint32_t
108 align_u32(uint32_t v
, uint32_t a
)
110 return (v
+ a
- 1) & ~(a
- 1);
113 static struct gen_device_info devinfo
= {0};
114 static uint32_t device
= 0;
115 static struct aub_file aub_file
;
118 relocate_bo(struct bo
*bo
, const struct drm_i915_gem_execbuffer2
*execbuffer2
,
119 const struct drm_i915_gem_exec_object2
*obj
)
121 const struct drm_i915_gem_exec_object2
*exec_objects
=
122 (struct drm_i915_gem_exec_object2
*) (uintptr_t) execbuffer2
->buffers_ptr
;
123 const struct drm_i915_gem_relocation_entry
*relocs
=
124 (const struct drm_i915_gem_relocation_entry
*) (uintptr_t) obj
->relocs_ptr
;
128 relocated
= malloc(bo
->size
);
129 fail_if(relocated
== NULL
, "out of memory\n");
130 memcpy(relocated
, GET_PTR(bo
->map
), bo
->size
);
131 for (size_t i
= 0; i
< obj
->relocation_count
; i
++) {
132 fail_if(relocs
[i
].offset
>= bo
->size
, "reloc outside bo\n");
134 if (execbuffer2
->flags
& I915_EXEC_HANDLE_LUT
)
135 handle
= exec_objects
[relocs
[i
].target_handle
].handle
;
137 handle
= relocs
[i
].target_handle
;
139 aub_write_reloc(&devinfo
, ((char *)relocated
) + relocs
[i
].offset
,
140 get_bo(handle
)->offset
+ relocs
[i
].delta
);
147 gem_ioctl(int fd
, unsigned long request
, void *argp
)
152 ret
= libc_ioctl(fd
, request
, argp
);
153 } while (ret
== -1 && (errno
== EINTR
|| errno
== EAGAIN
));
159 gem_mmap(int fd
, uint32_t handle
, uint64_t offset
, uint64_t size
)
161 struct drm_i915_gem_mmap mmap
= {
167 if (gem_ioctl(fd
, DRM_IOCTL_I915_GEM_MMAP
, &mmap
) == -1)
170 return (void *)(uintptr_t) mmap
.addr_ptr
;
174 gem_get_param(int fd
, uint32_t param
)
177 drm_i915_getparam_t gp
= {
182 if (gem_ioctl(fd
, DRM_IOCTL_I915_GETPARAM
, &gp
) == -1)
189 dump_execbuffer2(int fd
, struct drm_i915_gem_execbuffer2
*execbuffer2
)
191 struct drm_i915_gem_exec_object2
*exec_objects
=
192 (struct drm_i915_gem_exec_object2
*) (uintptr_t) execbuffer2
->buffers_ptr
;
193 uint32_t ring_flag
= execbuffer2
->flags
& I915_EXEC_RING_MASK
;
195 struct drm_i915_gem_exec_object2
*obj
;
196 struct bo
*bo
, *batch_bo
;
200 /* We can't do this at open time as we're not yet authenticated. */
202 device
= gem_get_param(fd
, I915_PARAM_CHIPSET_ID
);
203 fail_if(device
== 0 || devinfo
.gen
== 0, "failed to identify chipset\n");
205 if (devinfo
.gen
== 0) {
206 fail_if(!gen_get_device_info(device
, &devinfo
),
207 "failed to identify chipset=0x%x\n", device
);
209 aub_file_init(&aub_file
, output_file
, device
);
211 aub_file
.verbose_log_file
= stdout
;
212 aub_write_header(&aub_file
, program_invocation_short_name
);
215 printf("[running, output file %s, chipset id 0x%04x, gen %d]\n",
216 output_filename
, device
, devinfo
.gen
);
219 if (aub_use_execlists(&aub_file
))
222 offset
= aub_gtt_size(&aub_file
);
225 printf("Dumping execbuffer2:\n");
227 for (uint32_t i
= 0; i
< execbuffer2
->buffer_count
; i
++) {
228 obj
= &exec_objects
[i
];
229 bo
= get_bo(obj
->handle
);
231 /* If bo->size == 0, this means they passed us an invalid
232 * buffer. The kernel will reject it and so should we.
236 printf("BO #%d is invalid!\n", obj
->handle
);
240 if (obj
->flags
& EXEC_OBJECT_PINNED
) {
241 bo
->offset
= obj
->offset
;
243 printf("BO #%d (%dB) pinned @ 0x%lx\n",
244 obj
->handle
, bo
->size
, bo
->offset
);
246 if (obj
->alignment
!= 0)
247 offset
= align_u32(offset
, obj
->alignment
);
250 printf("BO #%d (%dB) @ 0x%lx\n", obj
->handle
,
251 bo
->size
, bo
->offset
);
252 offset
= align_u32(offset
+ bo
->size
+ 4095, 4096);
255 if (bo
->map
== NULL
&& bo
->size
> 0)
256 bo
->map
= gem_mmap(fd
, obj
->handle
, 0, bo
->size
);
257 fail_if(bo
->map
== MAP_FAILED
, "bo mmap failed\n");
259 if (aub_use_execlists(&aub_file
))
260 aub_map_ppgtt(&aub_file
, bo
->offset
, bo
->size
);
263 batch_index
= (execbuffer2
->flags
& I915_EXEC_BATCH_FIRST
) ? 0 :
264 execbuffer2
->buffer_count
- 1;
265 batch_bo
= get_bo(exec_objects
[batch_index
].handle
);
266 for (uint32_t i
= 0; i
< execbuffer2
->buffer_count
; i
++) {
267 obj
= &exec_objects
[i
];
268 bo
= get_bo(obj
->handle
);
270 if (obj
->relocation_count
> 0)
271 data
= relocate_bo(bo
, execbuffer2
, obj
);
275 if (bo
== batch_bo
) {
276 aub_write_trace_block(&aub_file
, AUB_TRACE_TYPE_BATCH
,
277 GET_PTR(data
), bo
->size
, bo
->offset
);
279 aub_write_trace_block(&aub_file
, AUB_TRACE_TYPE_NOTYPE
,
280 GET_PTR(data
), bo
->size
, bo
->offset
);
287 aub_write_exec(&aub_file
,
288 batch_bo
->offset
+ execbuffer2
->batch_start_offset
,
291 if (device_override
&&
292 (execbuffer2
->flags
& I915_EXEC_FENCE_ARRAY
) != 0) {
293 struct drm_i915_gem_exec_fence
*fences
=
294 (void*)(uintptr_t)execbuffer2
->cliprects_ptr
;
295 for (uint32_t i
= 0; i
< execbuffer2
->num_cliprects
; i
++) {
296 if ((fences
[i
].flags
& I915_EXEC_FENCE_SIGNAL
) != 0) {
297 struct drm_syncobj_array arg
= {
298 .handles
= (uintptr_t)&fences
[i
].handle
,
302 libc_ioctl(fd
, DRM_IOCTL_SYNCOBJ_SIGNAL
, &arg
);
309 add_new_bo(int handle
, uint64_t size
, void *map
)
311 struct bo
*bo
= &bos
[handle
];
313 fail_if(handle
>= MAX_BO_COUNT
, "bo handle out of range\n");
314 fail_if(size
== 0, "bo size is invalid\n");
321 remove_bo(int handle
)
323 struct bo
*bo
= get_bo(handle
);
325 if (bo
->map
&& !IS_USERPTR(bo
->map
))
326 munmap(bo
->map
, bo
->size
);
331 __attribute__ ((visibility ("default"))) int
337 return libc_close(fd
);
343 static bool initialized
= false;
352 config
= fopen(getenv("INTEL_DUMP_GPU_CONFIG"), "r");
353 while (fscanf(config
, "%m[^=]=%m[^\n]\n", &key
, &value
) != EOF
) {
354 if (!strcmp(key
, "verbose")) {
355 if (!strcmp(value
, "1")) {
357 } else if (!strcmp(value
, "2")) {
360 } else if (!strcmp(key
, "device")) {
361 fail_if(device
!= 0, "Device/Platform override specified multiple times.");
362 fail_if(sscanf(value
, "%i", &device
) != 1,
363 "failed to parse device id '%s'",
365 device_override
= true;
366 } else if (!strcmp(key
, "platform")) {
367 fail_if(device
!= 0, "Device/Platform override specified multiple times.");
368 device
= gen_device_name_to_pci_device_id(value
);
369 fail_if(device
== -1, "Unknown platform '%s'", value
);
370 device_override
= true;
371 } else if (!strcmp(key
, "file")) {
372 output_filename
= strdup(value
);
373 output_file
= fopen(output_filename
, "w+");
374 fail_if(output_file
== NULL
,
375 "failed to open file '%s'\n",
378 fprintf(stderr
, "unknown option '%s'\n", key
);
386 bos
= calloc(MAX_BO_COUNT
, sizeof(bos
[0]));
387 fail_if(bos
== NULL
, "out of memory\n");
390 __attribute__ ((visibility ("default"))) int
391 ioctl(int fd
, unsigned long request
, ...)
398 va_start(args
, request
);
399 argp
= va_arg(args
, void *);
402 if (_IOC_TYPE(request
) == DRM_IOCTL_BASE
&&
403 drm_fd
!= fd
&& fstat(fd
, &buf
) == 0 &&
404 (buf
.st_mode
& S_IFMT
) == S_IFCHR
&& major(buf
.st_rdev
) == DRM_MAJOR
) {
407 printf("[intercept drm ioctl on fd %d]\n", fd
);
414 case DRM_IOCTL_I915_GETPARAM
: {
415 struct drm_i915_getparam
*getparam
= argp
;
417 if (device_override
&& getparam
->param
== I915_PARAM_CHIPSET_ID
) {
418 *getparam
->value
= device
;
422 ret
= libc_ioctl(fd
, request
, argp
);
424 /* If the application looks up chipset_id
425 * (they typically do), we'll piggy-back on
426 * their ioctl and store the id for later
428 if (ret
== 0 && getparam
->param
== I915_PARAM_CHIPSET_ID
)
429 device
= *getparam
->value
;
434 case DRM_IOCTL_I915_GEM_EXECBUFFER
: {
438 "application uses DRM_IOCTL_I915_GEM_EXECBUFFER, not handled\n");
441 return libc_ioctl(fd
, request
, argp
);
444 case DRM_IOCTL_I915_GEM_EXECBUFFER2
:
445 case DRM_IOCTL_I915_GEM_EXECBUFFER2_WR
: {
446 dump_execbuffer2(fd
, argp
);
450 return libc_ioctl(fd
, request
, argp
);
453 case DRM_IOCTL_I915_GEM_CREATE
: {
454 struct drm_i915_gem_create
*create
= argp
;
456 ret
= libc_ioctl(fd
, request
, argp
);
458 add_new_bo(create
->handle
, create
->size
, NULL
);
463 case DRM_IOCTL_I915_GEM_USERPTR
: {
464 struct drm_i915_gem_userptr
*userptr
= argp
;
466 ret
= libc_ioctl(fd
, request
, argp
);
468 add_new_bo(userptr
->handle
, userptr
->user_size
,
469 (void *) (uintptr_t) (userptr
->user_ptr
| USERPTR_FLAG
));
473 case DRM_IOCTL_GEM_CLOSE
: {
474 struct drm_gem_close
*close
= argp
;
476 remove_bo(close
->handle
);
478 return libc_ioctl(fd
, request
, argp
);
481 case DRM_IOCTL_GEM_OPEN
: {
482 struct drm_gem_open
*open
= argp
;
484 ret
= libc_ioctl(fd
, request
, argp
);
486 add_new_bo(open
->handle
, open
->size
, NULL
);
491 case DRM_IOCTL_PRIME_FD_TO_HANDLE
: {
492 struct drm_prime_handle
*prime
= argp
;
494 ret
= libc_ioctl(fd
, request
, argp
);
498 size
= lseek(prime
->fd
, 0, SEEK_END
);
499 fail_if(size
== -1, "failed to get prime bo size\n");
500 add_new_bo(prime
->handle
, size
, NULL
);
507 return libc_ioctl(fd
, request
, argp
);
510 return libc_ioctl(fd
, request
, argp
);
517 libc_close
= dlsym(RTLD_NEXT
, "close");
518 libc_ioctl
= dlsym(RTLD_NEXT
, "ioctl");
519 fail_if(libc_close
== NULL
|| libc_ioctl
== NULL
,
520 "failed to get libc ioctl or close\n");
524 close_init_helper(int fd
)
527 return libc_close(fd
);
531 ioctl_init_helper(int fd
, unsigned long request
, ...)
536 va_start(args
, request
);
537 argp
= va_arg(args
, void *);
541 return libc_ioctl(fd
, request
, argp
);
544 static void __attribute__ ((destructor
))
547 free(output_filename
);
548 aub_file_finish(&aub_file
);