101e04c3fSmrg/* 201e04c3fSmrg * Copyright © 2015 Intel Corporation 301e04c3fSmrg * 401e04c3fSmrg * Permission is hereby granted, free of charge, to any person obtaining a 501e04c3fSmrg * copy of this software and associated documentation files (the "Software"), 601e04c3fSmrg * to deal in the Software without restriction, including without limitation 701e04c3fSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 801e04c3fSmrg * and/or sell copies of the Software, and to permit persons to whom the 901e04c3fSmrg * Software is furnished to do so, subject to the following conditions: 1001e04c3fSmrg * 1101e04c3fSmrg * The above copyright notice and this permission notice (including the next 1201e04c3fSmrg * paragraph) shall be included in all copies or substantial portions of the 1301e04c3fSmrg * Software. 1401e04c3fSmrg * 1501e04c3fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1601e04c3fSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1701e04c3fSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1801e04c3fSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 1901e04c3fSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 2001e04c3fSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 2101e04c3fSmrg * IN THE SOFTWARE. 2201e04c3fSmrg */ 2301e04c3fSmrg 2401e04c3fSmrg#include <stdlib.h> 2501e04c3fSmrg#include <stdio.h> 2601e04c3fSmrg#include <string.h> 2701e04c3fSmrg#include <stdint.h> 2801e04c3fSmrg#include <stdbool.h> 2901e04c3fSmrg#include <signal.h> 3001e04c3fSmrg#include <stdarg.h> 3101e04c3fSmrg#include <fcntl.h> 3201e04c3fSmrg#include <sys/types.h> 3301e04c3fSmrg#include <sys/sysmacros.h> 3401e04c3fSmrg#include <sys/stat.h> 3501e04c3fSmrg#include <sys/ioctl.h> 3601e04c3fSmrg#include <unistd.h> 3701e04c3fSmrg#include <errno.h> 3801e04c3fSmrg#include <sys/mman.h> 3901e04c3fSmrg#include <dlfcn.h> 409f464c52Smaya#include "drm-uapi/i915_drm.h" 4101e04c3fSmrg#include <inttypes.h> 4201e04c3fSmrg 4301e04c3fSmrg#include "intel_aub.h" 4401e04c3fSmrg#include "aub_write.h" 4501e04c3fSmrg 467ec681f3Smrg#include "dev/intel_debug.h" 477ec681f3Smrg#include "dev/intel_device_info.h" 4801e04c3fSmrg#include "util/macros.h" 4901e04c3fSmrg 5001e04c3fSmrgstatic int close_init_helper(int fd); 5101e04c3fSmrgstatic int ioctl_init_helper(int fd, unsigned long request, ...); 527ec681f3Smrgstatic int munmap_init_helper(void *addr, size_t length); 5301e04c3fSmrg 5401e04c3fSmrgstatic int (*libc_close)(int fd) = close_init_helper; 5501e04c3fSmrgstatic int (*libc_ioctl)(int fd, unsigned long request, ...) = ioctl_init_helper; 567ec681f3Smrgstatic int (*libc_munmap)(void *addr, size_t length) = munmap_init_helper; 5701e04c3fSmrg 5801e04c3fSmrgstatic int drm_fd = -1; 5901e04c3fSmrgstatic char *output_filename = NULL; 6001e04c3fSmrgstatic FILE *output_file = NULL; 6101e04c3fSmrgstatic int verbose = 0; 627ec681f3Smrgstatic bool device_override = false; 637ec681f3Smrgstatic bool capture_only = false; 647ec681f3Smrgstatic int64_t frame_id = -1; 657ec681f3Smrgstatic bool capture_finished = false; 6601e04c3fSmrg 679f464c52Smaya#define MAX_FD_COUNT 64 6801e04c3fSmrg#define MAX_BO_COUNT 64 * 1024 6901e04c3fSmrg 7001e04c3fSmrgstruct bo { 7101e04c3fSmrg uint32_t size; 7201e04c3fSmrg uint64_t offset; 7301e04c3fSmrg void *map; 747ec681f3Smrg /* Whether the buffer has been positionned in the GTT already. */ 757ec681f3Smrg bool gtt_mapped : 1; 767ec681f3Smrg /* Tracks userspace mmapping of the buffer */ 777ec681f3Smrg bool user_mapped : 1; 787ec681f3Smrg /* Using the i915-gem mmapping ioctl & execbuffer ioctl, track whether a 797ec681f3Smrg * buffer has been updated. 807ec681f3Smrg */ 817ec681f3Smrg bool dirty : 1; 8201e04c3fSmrg}; 8301e04c3fSmrg 8401e04c3fSmrgstatic struct bo *bos; 8501e04c3fSmrg 8601e04c3fSmrg#define DRM_MAJOR 226 8701e04c3fSmrg 8801e04c3fSmrg/* We set bit 0 in the map pointer for userptr BOs so we know not to 8901e04c3fSmrg * munmap them on DRM_IOCTL_GEM_CLOSE. 9001e04c3fSmrg */ 9101e04c3fSmrg#define USERPTR_FLAG 1 9201e04c3fSmrg#define IS_USERPTR(p) ((uintptr_t) (p) & USERPTR_FLAG) 9301e04c3fSmrg#define GET_PTR(p) ( (void *) ((uintptr_t) p & ~(uintptr_t) 1) ) 9401e04c3fSmrg 957ec681f3Smrg#define fail_if(cond, ...) _fail_if(cond, "intel_dump_gpu", __VA_ARGS__) 9601e04c3fSmrg 9701e04c3fSmrgstatic struct bo * 989f464c52Smayaget_bo(unsigned fd, uint32_t handle) 9901e04c3fSmrg{ 10001e04c3fSmrg struct bo *bo; 10101e04c3fSmrg 10201e04c3fSmrg fail_if(handle >= MAX_BO_COUNT, "bo handle too large\n"); 1039f464c52Smaya fail_if(fd >= MAX_FD_COUNT, "bo fd too large\n"); 1049f464c52Smaya bo = &bos[handle + fd * MAX_BO_COUNT]; 10501e04c3fSmrg 10601e04c3fSmrg return bo; 10701e04c3fSmrg} 10801e04c3fSmrg 10901e04c3fSmrgstatic inline uint32_t 11001e04c3fSmrgalign_u32(uint32_t v, uint32_t a) 11101e04c3fSmrg{ 11201e04c3fSmrg return (v + a - 1) & ~(a - 1); 11301e04c3fSmrg} 11401e04c3fSmrg 1157ec681f3Smrgstatic struct intel_device_info devinfo = {0}; 1167ec681f3Smrgstatic int device = 0; 11701e04c3fSmrgstatic struct aub_file aub_file; 11801e04c3fSmrg 1197ec681f3Smrgstatic void 1207ec681f3Smrgensure_device_info(int fd) 1217ec681f3Smrg{ 1227ec681f3Smrg /* We can't do this at open time as we're not yet authenticated. */ 1237ec681f3Smrg if (device == 0) { 1247ec681f3Smrg fail_if(!intel_get_device_info_from_fd(fd, &devinfo), 1257ec681f3Smrg "failed to identify chipset.\n"); 1267ec681f3Smrg device = devinfo.chipset_id; 1277ec681f3Smrg } else if (devinfo.ver == 0) { 1287ec681f3Smrg fail_if(!intel_get_device_info_from_pci_id(device, &devinfo), 1297ec681f3Smrg "failed to identify chipset.\n"); 1307ec681f3Smrg } 1317ec681f3Smrg} 1327ec681f3Smrg 13301e04c3fSmrgstatic void * 1349f464c52Smayarelocate_bo(int fd, struct bo *bo, const struct drm_i915_gem_execbuffer2 *execbuffer2, 13501e04c3fSmrg const struct drm_i915_gem_exec_object2 *obj) 13601e04c3fSmrg{ 13701e04c3fSmrg const struct drm_i915_gem_exec_object2 *exec_objects = 13801e04c3fSmrg (struct drm_i915_gem_exec_object2 *) (uintptr_t) execbuffer2->buffers_ptr; 13901e04c3fSmrg const struct drm_i915_gem_relocation_entry *relocs = 14001e04c3fSmrg (const struct drm_i915_gem_relocation_entry *) (uintptr_t) obj->relocs_ptr; 14101e04c3fSmrg void *relocated; 14201e04c3fSmrg int handle; 14301e04c3fSmrg 14401e04c3fSmrg relocated = malloc(bo->size); 14501e04c3fSmrg fail_if(relocated == NULL, "out of memory\n"); 14601e04c3fSmrg memcpy(relocated, GET_PTR(bo->map), bo->size); 14701e04c3fSmrg for (size_t i = 0; i < obj->relocation_count; i++) { 14801e04c3fSmrg fail_if(relocs[i].offset >= bo->size, "reloc outside bo\n"); 14901e04c3fSmrg 15001e04c3fSmrg if (execbuffer2->flags & I915_EXEC_HANDLE_LUT) 15101e04c3fSmrg handle = exec_objects[relocs[i].target_handle].handle; 15201e04c3fSmrg else 15301e04c3fSmrg handle = relocs[i].target_handle; 15401e04c3fSmrg 15501e04c3fSmrg aub_write_reloc(&devinfo, ((char *)relocated) + relocs[i].offset, 1569f464c52Smaya get_bo(fd, handle)->offset + relocs[i].delta); 15701e04c3fSmrg } 15801e04c3fSmrg 15901e04c3fSmrg return relocated; 16001e04c3fSmrg} 16101e04c3fSmrg 16201e04c3fSmrgstatic int 16301e04c3fSmrggem_ioctl(int fd, unsigned long request, void *argp) 16401e04c3fSmrg{ 16501e04c3fSmrg int ret; 16601e04c3fSmrg 16701e04c3fSmrg do { 16801e04c3fSmrg ret = libc_ioctl(fd, request, argp); 16901e04c3fSmrg } while (ret == -1 && (errno == EINTR || errno == EAGAIN)); 17001e04c3fSmrg 17101e04c3fSmrg return ret; 17201e04c3fSmrg} 17301e04c3fSmrg 17401e04c3fSmrgstatic void * 17501e04c3fSmrggem_mmap(int fd, uint32_t handle, uint64_t offset, uint64_t size) 17601e04c3fSmrg{ 17701e04c3fSmrg struct drm_i915_gem_mmap mmap = { 17801e04c3fSmrg .handle = handle, 17901e04c3fSmrg .offset = offset, 18001e04c3fSmrg .size = size 18101e04c3fSmrg }; 18201e04c3fSmrg 18301e04c3fSmrg if (gem_ioctl(fd, DRM_IOCTL_I915_GEM_MMAP, &mmap) == -1) 18401e04c3fSmrg return MAP_FAILED; 18501e04c3fSmrg 18601e04c3fSmrg return (void *)(uintptr_t) mmap.addr_ptr; 18701e04c3fSmrg} 18801e04c3fSmrg 1899f464c52Smayastatic enum drm_i915_gem_engine_class 1909f464c52Smayaengine_class_from_ring_flag(uint32_t ring_flag) 1919f464c52Smaya{ 1929f464c52Smaya switch (ring_flag) { 1939f464c52Smaya case I915_EXEC_DEFAULT: 1949f464c52Smaya case I915_EXEC_RENDER: 1959f464c52Smaya return I915_ENGINE_CLASS_RENDER; 1969f464c52Smaya case I915_EXEC_BSD: 1979f464c52Smaya return I915_ENGINE_CLASS_VIDEO; 1989f464c52Smaya case I915_EXEC_BLT: 1999f464c52Smaya return I915_ENGINE_CLASS_COPY; 2009f464c52Smaya case I915_EXEC_VEBOX: 2019f464c52Smaya return I915_ENGINE_CLASS_VIDEO_ENHANCE; 2029f464c52Smaya default: 2039f464c52Smaya return I915_ENGINE_CLASS_INVALID; 2049f464c52Smaya } 2059f464c52Smaya} 2069f464c52Smaya 20701e04c3fSmrgstatic void 20801e04c3fSmrgdump_execbuffer2(int fd, struct drm_i915_gem_execbuffer2 *execbuffer2) 20901e04c3fSmrg{ 21001e04c3fSmrg struct drm_i915_gem_exec_object2 *exec_objects = 21101e04c3fSmrg (struct drm_i915_gem_exec_object2 *) (uintptr_t) execbuffer2->buffers_ptr; 21201e04c3fSmrg uint32_t ring_flag = execbuffer2->flags & I915_EXEC_RING_MASK; 21301e04c3fSmrg uint32_t offset; 21401e04c3fSmrg struct drm_i915_gem_exec_object2 *obj; 21501e04c3fSmrg struct bo *bo, *batch_bo; 21601e04c3fSmrg int batch_index; 21701e04c3fSmrg void *data; 21801e04c3fSmrg 2197ec681f3Smrg ensure_device_info(fd); 2207ec681f3Smrg 2217ec681f3Smrg if (capture_finished) 2227ec681f3Smrg return; 22301e04c3fSmrg 2247ec681f3Smrg if (!aub_file.file) { 2259f464c52Smaya aub_file_init(&aub_file, output_file, 2269f464c52Smaya verbose == 2 ? stdout : NULL, 2279f464c52Smaya device, program_invocation_short_name); 2289f464c52Smaya aub_write_default_setup(&aub_file); 22901e04c3fSmrg 23001e04c3fSmrg if (verbose) 23101e04c3fSmrg printf("[running, output file %s, chipset id 0x%04x, gen %d]\n", 2327ec681f3Smrg output_filename, device, devinfo.ver); 23301e04c3fSmrg } 23401e04c3fSmrg 23501e04c3fSmrg if (aub_use_execlists(&aub_file)) 23601e04c3fSmrg offset = 0x1000; 23701e04c3fSmrg else 23801e04c3fSmrg offset = aub_gtt_size(&aub_file); 23901e04c3fSmrg 24001e04c3fSmrg for (uint32_t i = 0; i < execbuffer2->buffer_count; i++) { 24101e04c3fSmrg obj = &exec_objects[i]; 2429f464c52Smaya bo = get_bo(fd, obj->handle); 24301e04c3fSmrg 24401e04c3fSmrg /* If bo->size == 0, this means they passed us an invalid 24501e04c3fSmrg * buffer. The kernel will reject it and so should we. 24601e04c3fSmrg */ 24701e04c3fSmrg if (bo->size == 0) { 24801e04c3fSmrg if (verbose) 24901e04c3fSmrg printf("BO #%d is invalid!\n", obj->handle); 25001e04c3fSmrg return; 25101e04c3fSmrg } 25201e04c3fSmrg 25301e04c3fSmrg if (obj->flags & EXEC_OBJECT_PINNED) { 2547ec681f3Smrg if (bo->offset != obj->offset) 2557ec681f3Smrg bo->gtt_mapped = false; 25601e04c3fSmrg bo->offset = obj->offset; 25701e04c3fSmrg } else { 25801e04c3fSmrg if (obj->alignment != 0) 25901e04c3fSmrg offset = align_u32(offset, obj->alignment); 26001e04c3fSmrg bo->offset = offset; 26101e04c3fSmrg offset = align_u32(offset + bo->size + 4095, 4096); 26201e04c3fSmrg } 26301e04c3fSmrg 26401e04c3fSmrg if (bo->map == NULL && bo->size > 0) 26501e04c3fSmrg bo->map = gem_mmap(fd, obj->handle, 0, bo->size); 26601e04c3fSmrg fail_if(bo->map == MAP_FAILED, "bo mmap failed\n"); 2677ec681f3Smrg } 2687ec681f3Smrg 2697ec681f3Smrg uint64_t current_frame_id = 0; 2707ec681f3Smrg if (frame_id >= 0) { 2717ec681f3Smrg for (uint32_t i = 0; i < execbuffer2->buffer_count; i++) { 2727ec681f3Smrg obj = &exec_objects[i]; 2737ec681f3Smrg bo = get_bo(fd, obj->handle); 2747ec681f3Smrg 2757ec681f3Smrg /* Check against frame_id requirements. */ 2767ec681f3Smrg if (memcmp(bo->map, intel_debug_identifier(), 2777ec681f3Smrg intel_debug_identifier_size()) == 0) { 2787ec681f3Smrg const struct intel_debug_block_frame *frame_desc = 2797ec681f3Smrg intel_debug_get_identifier_block(bo->map, bo->size, 2807ec681f3Smrg INTEL_DEBUG_BLOCK_TYPE_FRAME); 2817ec681f3Smrg 2827ec681f3Smrg current_frame_id = frame_desc ? frame_desc->frame_id : 0; 2837ec681f3Smrg break; 2847ec681f3Smrg } 2857ec681f3Smrg } 2867ec681f3Smrg } 2877ec681f3Smrg 2887ec681f3Smrg if (verbose) 2897ec681f3Smrg printf("Dumping execbuffer2 (frame_id=%"PRIu64", buffers=%u):\n", 2907ec681f3Smrg current_frame_id, execbuffer2->buffer_count); 29101e04c3fSmrg 2927ec681f3Smrg /* Check whether we can stop right now. */ 2937ec681f3Smrg if (frame_id >= 0) { 2947ec681f3Smrg if (current_frame_id < frame_id) 2957ec681f3Smrg return; 2967ec681f3Smrg 2977ec681f3Smrg if (current_frame_id > frame_id) { 2987ec681f3Smrg aub_file_finish(&aub_file); 2997ec681f3Smrg capture_finished = true; 3007ec681f3Smrg return; 3017ec681f3Smrg } 3027ec681f3Smrg } 3037ec681f3Smrg 3047ec681f3Smrg 3057ec681f3Smrg /* Map buffers into the PPGTT. */ 3067ec681f3Smrg for (uint32_t i = 0; i < execbuffer2->buffer_count; i++) { 3077ec681f3Smrg obj = &exec_objects[i]; 3087ec681f3Smrg bo = get_bo(fd, obj->handle); 3097ec681f3Smrg 3107ec681f3Smrg if (verbose) { 3117ec681f3Smrg printf("BO #%d (%dB) @ 0x%" PRIx64 "\n", 3127ec681f3Smrg obj->handle, bo->size, bo->offset); 3137ec681f3Smrg } 3147ec681f3Smrg 3157ec681f3Smrg if (aub_use_execlists(&aub_file) && !bo->gtt_mapped) { 31601e04c3fSmrg aub_map_ppgtt(&aub_file, bo->offset, bo->size); 3177ec681f3Smrg bo->gtt_mapped = true; 3187ec681f3Smrg } 31901e04c3fSmrg } 32001e04c3fSmrg 3217ec681f3Smrg /* Write the buffer content into the Aub. */ 32201e04c3fSmrg batch_index = (execbuffer2->flags & I915_EXEC_BATCH_FIRST) ? 0 : 32301e04c3fSmrg execbuffer2->buffer_count - 1; 3249f464c52Smaya batch_bo = get_bo(fd, exec_objects[batch_index].handle); 32501e04c3fSmrg for (uint32_t i = 0; i < execbuffer2->buffer_count; i++) { 32601e04c3fSmrg obj = &exec_objects[i]; 3279f464c52Smaya bo = get_bo(fd, obj->handle); 32801e04c3fSmrg 32901e04c3fSmrg if (obj->relocation_count > 0) 3309f464c52Smaya data = relocate_bo(fd, bo, execbuffer2, obj); 33101e04c3fSmrg else 33201e04c3fSmrg data = bo->map; 33301e04c3fSmrg 3347ec681f3Smrg bool write = !capture_only || (obj->flags & EXEC_OBJECT_CAPTURE); 3357ec681f3Smrg 3367ec681f3Smrg if (write && bo->dirty) { 3377ec681f3Smrg if (bo == batch_bo) { 3387ec681f3Smrg aub_write_trace_block(&aub_file, AUB_TRACE_TYPE_BATCH, 3397ec681f3Smrg GET_PTR(data), bo->size, bo->offset); 3407ec681f3Smrg } else { 3417ec681f3Smrg aub_write_trace_block(&aub_file, AUB_TRACE_TYPE_NOTYPE, 3427ec681f3Smrg GET_PTR(data), bo->size, bo->offset); 3437ec681f3Smrg } 3447ec681f3Smrg 3457ec681f3Smrg if (!bo->user_mapped) 3467ec681f3Smrg bo->dirty = false; 34701e04c3fSmrg } 34801e04c3fSmrg 34901e04c3fSmrg if (data != bo->map) 35001e04c3fSmrg free(data); 35101e04c3fSmrg } 35201e04c3fSmrg 3537ec681f3Smrg uint32_t ctx_id = execbuffer2->rsvd1; 3547ec681f3Smrg 3557ec681f3Smrg aub_write_exec(&aub_file, ctx_id, 35601e04c3fSmrg batch_bo->offset + execbuffer2->batch_start_offset, 3579f464c52Smaya offset, engine_class_from_ring_flag(ring_flag)); 35801e04c3fSmrg 35901e04c3fSmrg if (device_override && 36001e04c3fSmrg (execbuffer2->flags & I915_EXEC_FENCE_ARRAY) != 0) { 36101e04c3fSmrg struct drm_i915_gem_exec_fence *fences = 36201e04c3fSmrg (void*)(uintptr_t)execbuffer2->cliprects_ptr; 36301e04c3fSmrg for (uint32_t i = 0; i < execbuffer2->num_cliprects; i++) { 36401e04c3fSmrg if ((fences[i].flags & I915_EXEC_FENCE_SIGNAL) != 0) { 36501e04c3fSmrg struct drm_syncobj_array arg = { 36601e04c3fSmrg .handles = (uintptr_t)&fences[i].handle, 36701e04c3fSmrg .count_handles = 1, 36801e04c3fSmrg .pad = 0, 36901e04c3fSmrg }; 37001e04c3fSmrg libc_ioctl(fd, DRM_IOCTL_SYNCOBJ_SIGNAL, &arg); 37101e04c3fSmrg } 37201e04c3fSmrg } 37301e04c3fSmrg } 37401e04c3fSmrg} 37501e04c3fSmrg 37601e04c3fSmrgstatic void 3779f464c52Smayaadd_new_bo(unsigned fd, int handle, uint64_t size, void *map) 37801e04c3fSmrg{ 3799f464c52Smaya struct bo *bo = &bos[handle + fd * MAX_BO_COUNT]; 38001e04c3fSmrg 38101e04c3fSmrg fail_if(handle >= MAX_BO_COUNT, "bo handle out of range\n"); 3829f464c52Smaya fail_if(fd >= MAX_FD_COUNT, "bo fd out of range\n"); 38301e04c3fSmrg fail_if(size == 0, "bo size is invalid\n"); 38401e04c3fSmrg 38501e04c3fSmrg bo->size = size; 38601e04c3fSmrg bo->map = map; 3877ec681f3Smrg bo->user_mapped = false; 3887ec681f3Smrg bo->gtt_mapped = false; 38901e04c3fSmrg} 39001e04c3fSmrg 39101e04c3fSmrgstatic void 3929f464c52Smayaremove_bo(int fd, int handle) 39301e04c3fSmrg{ 3949f464c52Smaya struct bo *bo = get_bo(fd, handle); 39501e04c3fSmrg 39601e04c3fSmrg if (bo->map && !IS_USERPTR(bo->map)) 39701e04c3fSmrg munmap(bo->map, bo->size); 3987ec681f3Smrg memset(bo, 0, sizeof(*bo)); 39901e04c3fSmrg} 40001e04c3fSmrg 40101e04c3fSmrg__attribute__ ((visibility ("default"))) int 40201e04c3fSmrgclose(int fd) 40301e04c3fSmrg{ 40401e04c3fSmrg if (fd == drm_fd) 40501e04c3fSmrg drm_fd = -1; 40601e04c3fSmrg 40701e04c3fSmrg return libc_close(fd); 40801e04c3fSmrg} 40901e04c3fSmrg 4107ec681f3Smrgstatic int 4117ec681f3Smrgget_pci_id(int fd, int *pci_id) 4127ec681f3Smrg{ 4137ec681f3Smrg struct drm_i915_getparam gparam; 4147ec681f3Smrg 4157ec681f3Smrg if (device_override) { 4167ec681f3Smrg *pci_id = device; 4177ec681f3Smrg return 0; 4187ec681f3Smrg } 4197ec681f3Smrg 4207ec681f3Smrg gparam.param = I915_PARAM_CHIPSET_ID; 4217ec681f3Smrg gparam.value = pci_id; 4227ec681f3Smrg return libc_ioctl(fd, DRM_IOCTL_I915_GETPARAM, &gparam); 4237ec681f3Smrg} 4247ec681f3Smrg 42501e04c3fSmrgstatic void 4267ec681f3Smrgmaybe_init(int fd) 42701e04c3fSmrg{ 42801e04c3fSmrg static bool initialized = false; 42901e04c3fSmrg FILE *config; 43001e04c3fSmrg char *key, *value; 43101e04c3fSmrg 43201e04c3fSmrg if (initialized) 43301e04c3fSmrg return; 43401e04c3fSmrg 43501e04c3fSmrg initialized = true; 43601e04c3fSmrg 4377ec681f3Smrg const char *config_path = getenv("INTEL_DUMP_GPU_CONFIG"); 4387ec681f3Smrg fail_if(config_path == NULL, "INTEL_DUMP_GPU_CONFIG is not set\n"); 4397ec681f3Smrg 4407ec681f3Smrg config = fopen(config_path, "r"); 4417ec681f3Smrg fail_if(config == NULL, "failed to open file %s\n", config_path); 4427ec681f3Smrg 44301e04c3fSmrg while (fscanf(config, "%m[^=]=%m[^\n]\n", &key, &value) != EOF) { 44401e04c3fSmrg if (!strcmp(key, "verbose")) { 44501e04c3fSmrg if (!strcmp(value, "1")) { 44601e04c3fSmrg verbose = 1; 44701e04c3fSmrg } else if (!strcmp(value, "2")) { 44801e04c3fSmrg verbose = 2; 44901e04c3fSmrg } 45001e04c3fSmrg } else if (!strcmp(key, "device")) { 4517ec681f3Smrg fail_if(device != 0, "Device/Platform override specified multiple times.\n"); 45201e04c3fSmrg fail_if(sscanf(value, "%i", &device) != 1, 4537ec681f3Smrg "failed to parse device id '%s'\n", 45401e04c3fSmrg value); 45501e04c3fSmrg device_override = true; 4569f464c52Smaya } else if (!strcmp(key, "platform")) { 4577ec681f3Smrg fail_if(device != 0, "Device/Platform override specified multiple times.\n"); 4587ec681f3Smrg device = intel_device_name_to_pci_device_id(value); 4597ec681f3Smrg fail_if(device == -1, "Unknown platform '%s'\n", value); 4609f464c52Smaya device_override = true; 46101e04c3fSmrg } else if (!strcmp(key, "file")) { 4627ec681f3Smrg free(output_filename); 4637ec681f3Smrg if (output_file) 4647ec681f3Smrg fclose(output_file); 46501e04c3fSmrg output_filename = strdup(value); 46601e04c3fSmrg output_file = fopen(output_filename, "w+"); 46701e04c3fSmrg fail_if(output_file == NULL, 46801e04c3fSmrg "failed to open file '%s'\n", 46901e04c3fSmrg output_filename); 4707ec681f3Smrg } else if (!strcmp(key, "capture_only")) { 4717ec681f3Smrg capture_only = atoi(value); 4727ec681f3Smrg } else if (!strcmp(key, "frame")) { 4737ec681f3Smrg frame_id = atol(value); 47401e04c3fSmrg } else { 47501e04c3fSmrg fprintf(stderr, "unknown option '%s'\n", key); 47601e04c3fSmrg } 47701e04c3fSmrg 47801e04c3fSmrg free(key); 47901e04c3fSmrg free(value); 48001e04c3fSmrg } 48101e04c3fSmrg fclose(config); 48201e04c3fSmrg 4839f464c52Smaya bos = calloc(MAX_FD_COUNT * MAX_BO_COUNT, sizeof(bos[0])); 48401e04c3fSmrg fail_if(bos == NULL, "out of memory\n"); 4857ec681f3Smrg 4867ec681f3Smrg ASSERTED int ret = get_pci_id(fd, &device); 4877ec681f3Smrg assert(ret == 0); 4887ec681f3Smrg 4897ec681f3Smrg aub_file_init(&aub_file, output_file, 4907ec681f3Smrg verbose == 2 ? stdout : NULL, 4917ec681f3Smrg device, program_invocation_short_name); 4927ec681f3Smrg aub_write_default_setup(&aub_file); 4937ec681f3Smrg 4947ec681f3Smrg if (verbose) 4957ec681f3Smrg printf("[running, output file %s, chipset id 0x%04x, gen %d]\n", 4967ec681f3Smrg output_filename, device, devinfo.ver); 49701e04c3fSmrg} 49801e04c3fSmrg 49901e04c3fSmrg__attribute__ ((visibility ("default"))) int 50001e04c3fSmrgioctl(int fd, unsigned long request, ...) 50101e04c3fSmrg{ 50201e04c3fSmrg va_list args; 50301e04c3fSmrg void *argp; 50401e04c3fSmrg int ret; 50501e04c3fSmrg struct stat buf; 50601e04c3fSmrg 50701e04c3fSmrg va_start(args, request); 50801e04c3fSmrg argp = va_arg(args, void *); 50901e04c3fSmrg va_end(args); 51001e04c3fSmrg 51101e04c3fSmrg if (_IOC_TYPE(request) == DRM_IOCTL_BASE && 51201e04c3fSmrg drm_fd != fd && fstat(fd, &buf) == 0 && 51301e04c3fSmrg (buf.st_mode & S_IFMT) == S_IFCHR && major(buf.st_rdev) == DRM_MAJOR) { 51401e04c3fSmrg drm_fd = fd; 51501e04c3fSmrg if (verbose) 51601e04c3fSmrg printf("[intercept drm ioctl on fd %d]\n", fd); 51701e04c3fSmrg } 51801e04c3fSmrg 51901e04c3fSmrg if (fd == drm_fd) { 5207ec681f3Smrg maybe_init(fd); 52101e04c3fSmrg 52201e04c3fSmrg switch (request) { 5237ec681f3Smrg case DRM_IOCTL_SYNCOBJ_WAIT: 5247ec681f3Smrg case DRM_IOCTL_I915_GEM_WAIT: { 5257ec681f3Smrg if (device_override) 5267ec681f3Smrg return 0; 5277ec681f3Smrg return libc_ioctl(fd, request, argp); 5287ec681f3Smrg } 5297ec681f3Smrg 5307ec681f3Smrg case DRM_IOCTL_I915_GET_RESET_STATS: { 5317ec681f3Smrg if (device_override) { 5327ec681f3Smrg struct drm_i915_reset_stats *stats = argp; 5337ec681f3Smrg 5347ec681f3Smrg stats->reset_count = 0; 5357ec681f3Smrg stats->batch_active = 0; 5367ec681f3Smrg stats->batch_pending = 0; 5377ec681f3Smrg return 0; 5387ec681f3Smrg } 5397ec681f3Smrg return libc_ioctl(fd, request, argp); 5407ec681f3Smrg } 5417ec681f3Smrg 54201e04c3fSmrg case DRM_IOCTL_I915_GETPARAM: { 54301e04c3fSmrg struct drm_i915_getparam *getparam = argp; 54401e04c3fSmrg 5457ec681f3Smrg ensure_device_info(fd); 5467ec681f3Smrg 5477ec681f3Smrg if (getparam->param == I915_PARAM_CHIPSET_ID) 5487ec681f3Smrg return get_pci_id(fd, getparam->value); 5497ec681f3Smrg 5507ec681f3Smrg if (device_override) { 5517ec681f3Smrg switch (getparam->param) { 5527ec681f3Smrg case I915_PARAM_CS_TIMESTAMP_FREQUENCY: 5537ec681f3Smrg *getparam->value = devinfo.timestamp_frequency; 5547ec681f3Smrg return 0; 5557ec681f3Smrg 5567ec681f3Smrg case I915_PARAM_HAS_WAIT_TIMEOUT: 5577ec681f3Smrg case I915_PARAM_HAS_EXECBUF2: 5587ec681f3Smrg case I915_PARAM_MMAP_VERSION: 5597ec681f3Smrg case I915_PARAM_HAS_EXEC_ASYNC: 5607ec681f3Smrg case I915_PARAM_HAS_EXEC_FENCE: 5617ec681f3Smrg case I915_PARAM_HAS_EXEC_FENCE_ARRAY: 5627ec681f3Smrg *getparam->value = 1; 5637ec681f3Smrg return 0; 5647ec681f3Smrg 5657ec681f3Smrg case I915_PARAM_HAS_EXEC_SOFTPIN: 5667ec681f3Smrg *getparam->value = devinfo.ver >= 8 && !devinfo.is_cherryview; 5677ec681f3Smrg return 0; 5687ec681f3Smrg 5697ec681f3Smrg default: 5707ec681f3Smrg return -1; 5717ec681f3Smrg } 57201e04c3fSmrg } 57301e04c3fSmrg 5747ec681f3Smrg return libc_ioctl(fd, request, argp); 5757ec681f3Smrg } 57601e04c3fSmrg 5777ec681f3Smrg case DRM_IOCTL_I915_GEM_CONTEXT_GETPARAM: { 5787ec681f3Smrg struct drm_i915_gem_context_param *getparam = argp; 5797ec681f3Smrg 5807ec681f3Smrg ensure_device_info(fd); 5817ec681f3Smrg 5827ec681f3Smrg if (device_override) { 5837ec681f3Smrg switch (getparam->param) { 5847ec681f3Smrg case I915_CONTEXT_PARAM_GTT_SIZE: 5857ec681f3Smrg if (devinfo.is_elkhartlake) 5867ec681f3Smrg getparam->value = 1ull << 36; 5877ec681f3Smrg else if (devinfo.ver >= 8 && !devinfo.is_cherryview) 5887ec681f3Smrg getparam->value = 1ull << 48; 5897ec681f3Smrg else 5907ec681f3Smrg getparam->value = 1ull << 31; 5917ec681f3Smrg return 0; 5927ec681f3Smrg 5937ec681f3Smrg default: 5947ec681f3Smrg return -1; 5957ec681f3Smrg } 5967ec681f3Smrg } 59701e04c3fSmrg 5987ec681f3Smrg return libc_ioctl(fd, request, argp); 59901e04c3fSmrg } 60001e04c3fSmrg 60101e04c3fSmrg case DRM_IOCTL_I915_GEM_EXECBUFFER: { 60201e04c3fSmrg static bool once; 60301e04c3fSmrg if (!once) { 60401e04c3fSmrg fprintf(stderr, 60501e04c3fSmrg "application uses DRM_IOCTL_I915_GEM_EXECBUFFER, not handled\n"); 60601e04c3fSmrg once = true; 60701e04c3fSmrg } 60801e04c3fSmrg return libc_ioctl(fd, request, argp); 60901e04c3fSmrg } 61001e04c3fSmrg 61101e04c3fSmrg case DRM_IOCTL_I915_GEM_EXECBUFFER2: 61201e04c3fSmrg case DRM_IOCTL_I915_GEM_EXECBUFFER2_WR: { 61301e04c3fSmrg dump_execbuffer2(fd, argp); 61401e04c3fSmrg if (device_override) 61501e04c3fSmrg return 0; 61601e04c3fSmrg 61701e04c3fSmrg return libc_ioctl(fd, request, argp); 61801e04c3fSmrg } 61901e04c3fSmrg 6207ec681f3Smrg case DRM_IOCTL_I915_GEM_CONTEXT_CREATE: { 6217ec681f3Smrg uint32_t *ctx_id = NULL; 6227ec681f3Smrg struct drm_i915_gem_context_create *create = argp; 6237ec681f3Smrg ret = 0; 6247ec681f3Smrg if (!device_override) { 6257ec681f3Smrg ret = libc_ioctl(fd, request, argp); 6267ec681f3Smrg ctx_id = &create->ctx_id; 6277ec681f3Smrg } 6287ec681f3Smrg 6297ec681f3Smrg if (ret == 0) 6307ec681f3Smrg create->ctx_id = aub_write_context_create(&aub_file, ctx_id); 6317ec681f3Smrg 6327ec681f3Smrg return ret; 6337ec681f3Smrg } 6347ec681f3Smrg 6357ec681f3Smrg case DRM_IOCTL_I915_GEM_CONTEXT_CREATE_EXT: { 6367ec681f3Smrg uint32_t *ctx_id = NULL; 6377ec681f3Smrg struct drm_i915_gem_context_create_ext *create = argp; 6387ec681f3Smrg ret = 0; 6397ec681f3Smrg if (!device_override) { 6407ec681f3Smrg ret = libc_ioctl(fd, request, argp); 6417ec681f3Smrg ctx_id = &create->ctx_id; 6427ec681f3Smrg } 6437ec681f3Smrg 6447ec681f3Smrg if (ret == 0) 6457ec681f3Smrg create->ctx_id = aub_write_context_create(&aub_file, ctx_id); 6467ec681f3Smrg 6477ec681f3Smrg return ret; 6487ec681f3Smrg } 6497ec681f3Smrg 65001e04c3fSmrg case DRM_IOCTL_I915_GEM_CREATE: { 65101e04c3fSmrg struct drm_i915_gem_create *create = argp; 65201e04c3fSmrg 65301e04c3fSmrg ret = libc_ioctl(fd, request, argp); 65401e04c3fSmrg if (ret == 0) 6559f464c52Smaya add_new_bo(fd, create->handle, create->size, NULL); 65601e04c3fSmrg 65701e04c3fSmrg return ret; 65801e04c3fSmrg } 65901e04c3fSmrg 66001e04c3fSmrg case DRM_IOCTL_I915_GEM_USERPTR: { 66101e04c3fSmrg struct drm_i915_gem_userptr *userptr = argp; 66201e04c3fSmrg 66301e04c3fSmrg ret = libc_ioctl(fd, request, argp); 66401e04c3fSmrg if (ret == 0) 6659f464c52Smaya add_new_bo(fd, userptr->handle, userptr->user_size, 66601e04c3fSmrg (void *) (uintptr_t) (userptr->user_ptr | USERPTR_FLAG)); 6679f464c52Smaya 66801e04c3fSmrg return ret; 66901e04c3fSmrg } 67001e04c3fSmrg 67101e04c3fSmrg case DRM_IOCTL_GEM_CLOSE: { 67201e04c3fSmrg struct drm_gem_close *close = argp; 67301e04c3fSmrg 6749f464c52Smaya remove_bo(fd, close->handle); 67501e04c3fSmrg 67601e04c3fSmrg return libc_ioctl(fd, request, argp); 67701e04c3fSmrg } 67801e04c3fSmrg 67901e04c3fSmrg case DRM_IOCTL_GEM_OPEN: { 68001e04c3fSmrg struct drm_gem_open *open = argp; 68101e04c3fSmrg 68201e04c3fSmrg ret = libc_ioctl(fd, request, argp); 68301e04c3fSmrg if (ret == 0) 6849f464c52Smaya add_new_bo(fd, open->handle, open->size, NULL); 68501e04c3fSmrg 68601e04c3fSmrg return ret; 68701e04c3fSmrg } 68801e04c3fSmrg 68901e04c3fSmrg case DRM_IOCTL_PRIME_FD_TO_HANDLE: { 69001e04c3fSmrg struct drm_prime_handle *prime = argp; 69101e04c3fSmrg 69201e04c3fSmrg ret = libc_ioctl(fd, request, argp); 69301e04c3fSmrg if (ret == 0) { 69401e04c3fSmrg off_t size; 69501e04c3fSmrg 69601e04c3fSmrg size = lseek(prime->fd, 0, SEEK_END); 69701e04c3fSmrg fail_if(size == -1, "failed to get prime bo size\n"); 6989f464c52Smaya add_new_bo(fd, prime->handle, size, NULL); 6999f464c52Smaya 70001e04c3fSmrg } 70101e04c3fSmrg 70201e04c3fSmrg return ret; 70301e04c3fSmrg } 70401e04c3fSmrg 7057ec681f3Smrg case DRM_IOCTL_I915_GEM_MMAP: { 7067ec681f3Smrg ret = libc_ioctl(fd, request, argp); 7077ec681f3Smrg if (ret == 0) { 7087ec681f3Smrg struct drm_i915_gem_mmap *mmap = argp; 7097ec681f3Smrg struct bo *bo = get_bo(fd, mmap->handle); 7107ec681f3Smrg bo->user_mapped = true; 7117ec681f3Smrg bo->dirty = true; 7127ec681f3Smrg } 7137ec681f3Smrg return ret; 7147ec681f3Smrg } 7157ec681f3Smrg 7167ec681f3Smrg case DRM_IOCTL_I915_GEM_MMAP_OFFSET: { 7177ec681f3Smrg ret = libc_ioctl(fd, request, argp); 7187ec681f3Smrg if (ret == 0) { 7197ec681f3Smrg struct drm_i915_gem_mmap_offset *mmap = argp; 7207ec681f3Smrg struct bo *bo = get_bo(fd, mmap->handle); 7217ec681f3Smrg bo->user_mapped = true; 7227ec681f3Smrg bo->dirty = true; 7237ec681f3Smrg } 7247ec681f3Smrg return ret; 7257ec681f3Smrg } 7267ec681f3Smrg 72701e04c3fSmrg default: 72801e04c3fSmrg return libc_ioctl(fd, request, argp); 72901e04c3fSmrg } 73001e04c3fSmrg } else { 73101e04c3fSmrg return libc_ioctl(fd, request, argp); 73201e04c3fSmrg } 73301e04c3fSmrg} 73401e04c3fSmrg 73501e04c3fSmrgstatic void 73601e04c3fSmrginit(void) 73701e04c3fSmrg{ 73801e04c3fSmrg libc_close = dlsym(RTLD_NEXT, "close"); 73901e04c3fSmrg libc_ioctl = dlsym(RTLD_NEXT, "ioctl"); 7407ec681f3Smrg libc_munmap = dlsym(RTLD_NEXT, "munmap"); 74101e04c3fSmrg fail_if(libc_close == NULL || libc_ioctl == NULL, 74201e04c3fSmrg "failed to get libc ioctl or close\n"); 74301e04c3fSmrg} 74401e04c3fSmrg 74501e04c3fSmrgstatic int 74601e04c3fSmrgclose_init_helper(int fd) 74701e04c3fSmrg{ 74801e04c3fSmrg init(); 74901e04c3fSmrg return libc_close(fd); 75001e04c3fSmrg} 75101e04c3fSmrg 75201e04c3fSmrgstatic int 75301e04c3fSmrgioctl_init_helper(int fd, unsigned long request, ...) 75401e04c3fSmrg{ 75501e04c3fSmrg va_list args; 75601e04c3fSmrg void *argp; 75701e04c3fSmrg 75801e04c3fSmrg va_start(args, request); 75901e04c3fSmrg argp = va_arg(args, void *); 76001e04c3fSmrg va_end(args); 76101e04c3fSmrg 76201e04c3fSmrg init(); 76301e04c3fSmrg return libc_ioctl(fd, request, argp); 76401e04c3fSmrg} 76501e04c3fSmrg 7667ec681f3Smrgstatic int 7677ec681f3Smrgmunmap_init_helper(void *addr, size_t length) 7687ec681f3Smrg{ 7697ec681f3Smrg init(); 7707ec681f3Smrg for (uint32_t i = 0; i < MAX_FD_COUNT * MAX_BO_COUNT; i++) { 7717ec681f3Smrg struct bo *bo = &bos[i]; 7727ec681f3Smrg if (bo->map == addr) { 7737ec681f3Smrg bo->user_mapped = false; 7747ec681f3Smrg break; 7757ec681f3Smrg } 7767ec681f3Smrg } 7777ec681f3Smrg return libc_munmap(addr, length); 7787ec681f3Smrg} 7797ec681f3Smrg 78001e04c3fSmrgstatic void __attribute__ ((destructor)) 78101e04c3fSmrgfini(void) 78201e04c3fSmrg{ 7837ec681f3Smrg if (devinfo.ver != 0) { 7849f464c52Smaya free(output_filename); 7857ec681f3Smrg if (!capture_finished) 7867ec681f3Smrg aub_file_finish(&aub_file); 7879f464c52Smaya free(bos); 7889f464c52Smaya } 78901e04c3fSmrg} 790