1 /*
2 * Copyright © 2022 Intel Corporation
3 *
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:
10 *
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
13 * Software.
14 *
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
21 * IN THE SOFTWARE.
22 *
23 * Capture the hanging application with INTEL_DEBUG=capture-all
24 *
25 * Turn the error state into a replay file with :
26 * $ intel_error2hangdump error_state
27 *
28 * Replay with :
29 * $ intel_hang_replay -d error_state.dmp
30 */
31
32 #include <fcntl.h>
33 #include <getopt.h>
34 #include <inttypes.h>
35 #include <stdbool.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <sys/mman.h>
39 #include <sys/stat.h>
40 #include <sys/types.h>
41 #include <unistd.h>
42
43 #include <xf86drm.h>
44
45 #include "common/intel_gem.h"
46 #include "common/i915/intel_gem.h"
47 #include "common/intel_hang_dump.h"
48 #include "compiler/elk/elk_disasm.h"
49 #include "compiler/elk/elk_isa_info.h"
50 #include "compiler/brw_disasm.h"
51 #include "compiler/brw_isa_info.h"
52 #include "dev/intel_device_info.h"
53
54 #include "drm-uapi/i915_drm.h"
55
56 #include "util/u_dynarray.h"
57 #include "util/u_math.h"
58
59 static uint32_t
gem_create(int drm_fd,uint64_t size)60 gem_create(int drm_fd, uint64_t size)
61 {
62 struct drm_i915_gem_create gem_create = {
63 .size = size,
64 };
65
66 int ret = intel_ioctl(drm_fd, DRM_IOCTL_I915_GEM_CREATE, &gem_create);
67 if (ret != 0) {
68 /* FIXME: What do we do if this fails? */
69 return 0;
70 }
71
72 return gem_create.handle;
73 }
74
75 static uint32_t
gem_context_create(int drm_fd)76 gem_context_create(int drm_fd)
77 {
78 /* TODO: add additional information in the intel_hang_dump_block_exec &
79 * intel_hang_dump_block_hw_image structures to specify the engine and use
80 * the correct engine here.
81 */
82 I915_DEFINE_CONTEXT_PARAM_ENGINES(engines_param, 1) = { };
83 struct drm_i915_gem_context_create_ext_setparam set_engines = {
84 .param = {
85 .param = I915_CONTEXT_PARAM_ENGINES,
86 .value = (uintptr_t)&engines_param,
87 .size = sizeof(engines_param),
88 }
89 };
90 struct drm_i915_gem_context_create_ext_setparam recoverable_param = {
91 .param = {
92 .param = I915_CONTEXT_PARAM_RECOVERABLE,
93 .value = 0,
94 },
95 };
96 struct drm_i915_gem_context_create_ext create = {
97 .flags = I915_CONTEXT_CREATE_FLAGS_USE_EXTENSIONS,
98 };
99
100 intel_i915_gem_add_ext(&create.extensions,
101 I915_CONTEXT_CREATE_EXT_SETPARAM,
102 &set_engines.base);
103 intel_i915_gem_add_ext(&create.extensions,
104 I915_CONTEXT_CREATE_EXT_SETPARAM,
105 &recoverable_param.base);
106
107 if (intel_ioctl(drm_fd, DRM_IOCTL_I915_GEM_CONTEXT_CREATE_EXT, &create) == -1)
108 return false;
109
110 return create.ctx_id;
111 }
112
113 static bool
gem_context_set_hw_image(int drm_fd,uint32_t ctx_id,const void * hw_img_data,uint32_t img_size)114 gem_context_set_hw_image(int drm_fd, uint32_t ctx_id,
115 const void *hw_img_data, uint32_t img_size)
116 {
117 /* TODO: add additional information in the intel_hang_dump_block_exec &
118 * intel_hang_dump_block_hw_image structures to specify the engine and use
119 * the correct engine here.
120 */
121 struct i915_gem_context_param_context_image img_param = {
122 .engine = {
123 .engine_class = 0,
124 .engine_instance = 0,
125 },
126 .flags = I915_CONTEXT_IMAGE_FLAG_ENGINE_INDEX,
127 .size = img_size,
128 .image = (uint64_t)(uintptr_t)hw_img_data,
129 };
130 struct drm_i915_gem_context_param param = {
131 .ctx_id = ctx_id,
132 .param = I915_CONTEXT_PARAM_CONTEXT_IMAGE,
133 };
134 uint64_t val = 0;
135 int ret;
136
137 param.ctx_id = ctx_id;
138 param.param = I915_CONTEXT_PARAM_RECOVERABLE;
139 param.value = (uint64_t)(uintptr_t)&val;
140
141 /* Force i915 to convert the "proto" context to be a "live" context, since
142 * the I915_CONTEXT_PARAM_CONTEXT_IMAGE parameter cannot be set on a "proto"
143 * context. See kernel docs for i915_gem_proto_context.
144 */
145 ret = intel_ioctl(drm_fd, DRM_IOCTL_I915_GEM_CONTEXT_GETPARAM, ¶m);
146 if (ret)
147 return false;
148
149 param.param = I915_CONTEXT_PARAM_CONTEXT_IMAGE;
150 param.size = sizeof(img_param);
151 param.value = (uint64_t)(uintptr_t)&img_param;
152
153 return intel_ioctl(drm_fd, DRM_IOCTL_I915_GEM_CONTEXT_SETPARAM, ¶m) == 0;
154 }
155
156 static void*
gem_mmap_offset(int drm_fd,uint32_t gem_handle,uint64_t offset,uint64_t size,uint32_t flags)157 gem_mmap_offset(int drm_fd,
158 uint32_t gem_handle,
159 uint64_t offset,
160 uint64_t size,
161 uint32_t flags)
162 {
163 struct drm_i915_gem_mmap_offset gem_mmap = {
164 .handle = gem_handle,
165 .flags = I915_MMAP_OFFSET_WB,
166 };
167 assert(offset == 0);
168
169 /* Get the fake offset back */
170 int ret = intel_ioctl(drm_fd, DRM_IOCTL_I915_GEM_MMAP_OFFSET, &gem_mmap);
171 if (ret != 0 && gem_mmap.flags == I915_MMAP_OFFSET_FIXED) {
172 gem_mmap.flags =
173 (flags & I915_MMAP_WC) ? I915_MMAP_OFFSET_WC : I915_MMAP_OFFSET_WB,
174 ret = intel_ioctl(drm_fd, DRM_IOCTL_I915_GEM_MMAP_OFFSET, &gem_mmap);
175 }
176
177 if (ret != 0)
178 return MAP_FAILED;
179
180 /* And map it */
181 void *map = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED,
182 drm_fd, gem_mmap.offset);
183 return map;
184 }
185
186 static void
write_malloc_data(void * out_data,int file_fd,size_t size)187 write_malloc_data(void *out_data,
188 int file_fd,
189 size_t size)
190 {
191 size_t total_read_len = 0;
192 ssize_t read_len;
193 while (total_read_len < size &&
194 (read_len = read(file_fd, out_data + total_read_len, size - total_read_len)) > 0) {
195 total_read_len += read_len;
196 }
197 assert(total_read_len == size);
198 }
199
200 static void
write_gem_bo_data(int drm_fd,uint32_t gem_handle,int file_fd,size_t size)201 write_gem_bo_data(int drm_fd,
202 uint32_t gem_handle,
203 int file_fd,
204 size_t size)
205 {
206 void *map = gem_mmap_offset(drm_fd, gem_handle, 0, size, I915_MMAP_OFFSET_WB);
207 assert(map != MAP_FAILED);
208
209 size_t total_read_len = 0;
210 ssize_t read_len;
211 while (total_read_len < size &&
212 (read_len = read(file_fd, map + total_read_len, size - total_read_len)) > 0) {
213 total_read_len += read_len;
214 }
215 munmap(map, size);
216
217 assert(total_read_len == size);
218 }
219
220 static void
skip_data(int file_fd,size_t size)221 skip_data(int file_fd, size_t size)
222 {
223 lseek(file_fd, size, SEEK_CUR);
224 }
225
226 static int
get_drm_device(struct intel_device_info * devinfo)227 get_drm_device(struct intel_device_info *devinfo)
228 {
229 drmDevicePtr devices[8];
230 int max_devices = drmGetDevices2(0, devices, 8);
231
232 int i, fd = -1;
233 for (i = 0; i < max_devices; i++) {
234 if (devices[i]->available_nodes & 1 << DRM_NODE_RENDER &&
235 devices[i]->bustype == DRM_BUS_PCI &&
236 devices[i]->deviceinfo.pci->vendor_id == 0x8086) {
237 fd = open(devices[i]->nodes[DRM_NODE_RENDER], O_RDWR | O_CLOEXEC);
238 if (fd < 0)
239 continue;
240
241 if (!intel_get_device_info_from_fd(fd, devinfo, -1, -1) ||
242 devinfo->ver < 8) {
243 close(fd);
244 fd = -1;
245 continue;
246 }
247
248 /* Found a device! */
249 break;
250 }
251 }
252
253 return fd;
254 }
255
256 struct gem_bo {
257 off_t file_offset;
258 uint32_t gem_handle;
259 uint64_t offset;
260 uint64_t size;
261 bool hw_img;
262 };
263
264 static int
compare_bos(const void * b1,const void * b2)265 compare_bos(const void *b1, const void *b2)
266 {
267 const struct gem_bo *gem_b1 = b1, *gem_b2 = b2;
268
269 return gem_b2->size > gem_b1->size;
270 }
271
272 static void
print_help(const char * filename,FILE * f)273 print_help(const char *filename, FILE *f)
274 {
275 fprintf(f, "%s: %s [options]...\n", filename, filename);
276 fprintf(f, " -d, --dump FILE hang file to replay\n");
277 fprintf(f, " -l, --list list content of hang file (no replay)\n");
278 fprintf(f, " -s, --shader ADDR print shader at ADDR\n");
279 fprintf(f, " -h, --help print this screen\n");
280 fprintf(f, " -a, --address ADDR Find BO containing ADDR\n");
281 }
282
283 static int
execbuffer(int drm_fd,uint32_t context_id,struct util_dynarray * execbuffer_bos,struct gem_bo * exec_bo,uint64_t exec_offset)284 execbuffer(int drm_fd,
285 uint32_t context_id,
286 struct util_dynarray *execbuffer_bos,
287 struct gem_bo *exec_bo, uint64_t exec_offset)
288 {
289 struct drm_i915_gem_execbuffer2 execbuf = {
290 .buffers_ptr = (uintptr_t)(void *)util_dynarray_begin(execbuffer_bos),
291 .buffer_count = util_dynarray_num_elements(execbuffer_bos,
292 struct drm_i915_gem_exec_object2),
293 .batch_start_offset = exec_offset - exec_bo->offset,
294 .batch_len = exec_bo->size,
295 .flags = I915_EXEC_HANDLE_LUT,
296 .rsvd1 = context_id,
297 };
298
299 int ret = intel_ioctl(drm_fd, DRM_IOCTL_I915_GEM_EXECBUFFER2_WR, &execbuf);
300 if (ret == 0) {
301 struct drm_i915_gem_wait gem_wait = {
302 .bo_handle = exec_bo->gem_handle,
303 .timeout_ns = INT64_MAX,
304 };
305 ret = intel_ioctl(drm_fd, DRM_IOCTL_I915_GEM_WAIT, &gem_wait);
306 if (ret)
307 fprintf(stderr, "wait failed: %m\n");
308 } else {
309 fprintf(stderr, "execbuffer failed: %m\n");
310 }
311
312 return ret;
313 }
314
315 int
main(int argc,char * argv[])316 main(int argc, char *argv[])
317 {
318 bool help = false, list = false;
319 const struct option aubinator_opts[] = {
320 { "address", required_argument, NULL, 'a' },
321 { "dump", required_argument, NULL, 'd' },
322 { "shader", required_argument, NULL, 's' },
323 { "list", no_argument, NULL, 'l' },
324 { "help", no_argument, NULL, 'h' },
325 { NULL, 0, NULL, 0 },
326 };
327
328 void *mem_ctx = ralloc_context(NULL);
329
330 struct util_dynarray shader_addresses;
331
332 util_dynarray_init(&shader_addresses, mem_ctx);
333
334 const char *file = NULL;
335 uint64_t check_addr = -1;
336 int c, i;
337 while ((c = getopt_long(argc, argv, "a:d:hls:", aubinator_opts, &i)) != -1) {
338 switch (c) {
339 case 'a':
340 check_addr = strtol(optarg, NULL, 0);
341 break;
342 case 'd':
343 file = optarg;
344 break;
345 case 's': {
346 uint64_t *addr = util_dynarray_grow(&shader_addresses, uint64_t, 1);
347 *addr = strtol(optarg, NULL, 0);
348 fprintf(stderr, "shader addr=0x%016"PRIx64"\n", *addr);
349 break;
350 }
351 case 'h':
352 help = true;
353 break;
354 case 'l':
355 list = true;
356 break;
357 default:
358 break;
359 }
360 }
361
362 if (help) {
363 print_help(argv[0], stderr);
364 exit(EXIT_SUCCESS);
365 }
366
367 int file_fd = open(file, O_RDONLY);
368 if (file_fd < 0)
369 exit(EXIT_FAILURE);
370
371 struct stat file_stats;
372 if (fstat(file_fd, &file_stats) != 0)
373 exit(EXIT_FAILURE);
374
375 struct intel_device_info devinfo;
376 int drm_fd = get_drm_device(&devinfo);
377 if (drm_fd < 0)
378 exit(EXIT_FAILURE);
379
380 struct util_dynarray buffers;
381 uint64_t total_vma = 0;
382
383 util_dynarray_init(&buffers, mem_ctx);
384
385 union intel_hang_dump_block_all block_header;
386 struct intel_hang_dump_block_exec init = {
387 .offset = -1,
388 }, exec = {
389 .offset = -1,
390 };
391
392 while (read(file_fd, &block_header.base, sizeof(block_header.base)) ==
393 sizeof(block_header.base)) {
394
395 static const size_t block_size[] = {
396 [INTEL_HANG_DUMP_BLOCK_TYPE_HEADER] = sizeof(struct intel_hang_dump_block_header),
397 [INTEL_HANG_DUMP_BLOCK_TYPE_BO] = sizeof(struct intel_hang_dump_block_bo),
398 [INTEL_HANG_DUMP_BLOCK_TYPE_MAP] = sizeof(struct intel_hang_dump_block_map),
399 [INTEL_HANG_DUMP_BLOCK_TYPE_EXEC] = sizeof(struct intel_hang_dump_block_exec),
400 [INTEL_HANG_DUMP_BLOCK_TYPE_HW_IMAGE] = sizeof(struct intel_hang_dump_block_hw_image),
401 };
402
403 assert(block_header.base.type < ARRAY_SIZE(block_size));
404
405 size_t remaining_size = block_size[block_header.base.type] - sizeof(block_header.base);
406 ssize_t ret = read(file_fd, &block_header.base + 1, remaining_size);
407 bool has_hw_image = false;
408 assert(ret == remaining_size);
409
410 switch (block_header.base.type) {
411 case INTEL_HANG_DUMP_BLOCK_TYPE_HEADER:
412 assert(block_header.header.magic == INTEL_HANG_DUMP_MAGIC);
413 assert(block_header.header.version == INTEL_HANG_DUMP_VERSION);
414 break;
415
416 case INTEL_HANG_DUMP_BLOCK_TYPE_BO: {
417 struct gem_bo *bo = util_dynarray_grow(&buffers, struct gem_bo, 1);
418 *bo = (struct gem_bo) {
419 .file_offset = lseek(file_fd, 0, SEEK_CUR),
420 .offset = block_header.bo.offset,
421 .size = block_header.bo.size,
422 };
423 total_vma += bo->size;
424 skip_data(file_fd, bo->size);
425 if (list) {
426 fprintf(stderr, "buffer: offset=0x%016"PRIx64" size=0x%016"PRIx64" name=%s\n",
427 bo->offset, bo->size, block_header.bo.name);
428 }
429 break;
430 }
431
432 case INTEL_HANG_DUMP_BLOCK_TYPE_HW_IMAGE: {
433 struct gem_bo *bo = util_dynarray_grow(&buffers, struct gem_bo, 1);
434 *bo = (struct gem_bo) {
435 .file_offset = lseek(file_fd, 0, SEEK_CUR),
436 .offset = 0,
437 .size = block_header.hw_img.size,
438 .hw_img = true,
439 };
440 total_vma += bo->size;
441 skip_data(file_fd, bo->size);
442 if (list) {
443 fprintf(stderr, "buffer: offset=0x%016"PRIx64" size=0x%016"PRIx64" name=hw_img\n",
444 bo->offset, bo->size);
445 }
446 has_hw_image = true;
447 break;
448 }
449
450 case INTEL_HANG_DUMP_BLOCK_TYPE_MAP: {
451 struct gem_bo *bo = util_dynarray_grow(&buffers, struct gem_bo, 1);
452 *bo = (struct gem_bo) {
453 .file_offset = 0,
454 .offset = block_header.map.offset,
455 .size = block_header.map.size,
456 };
457 total_vma += bo->size;
458 if (list) {
459 fprintf(stderr, "map : offset=0x%016"PRIx64" size=0x%016"PRIx64" name=%s\n",
460 bo->offset, bo->size, block_header.map.name);
461 }
462 break;
463 }
464
465 case INTEL_HANG_DUMP_BLOCK_TYPE_EXEC: {
466 if (init.offset == 0 && !has_hw_image) {
467 if (list)
468 fprintf(stderr, "init : offset=0x%016"PRIx64"\n", block_header.exec.offset);
469 init = block_header.exec;
470 } else {
471 if (list)
472 fprintf(stderr, "exec : offset=0x%016"PRIx64"\n", block_header.exec.offset);
473 exec = block_header.exec;
474 }
475 break;
476 }
477
478 default:
479 unreachable("Invalid block type");
480 }
481 }
482
483 fprintf(stderr, "total_vma: 0x%016"PRIx64"\n", total_vma);
484
485 if (check_addr != -1) {
486 struct gem_bo *check_bo = NULL;
487 util_dynarray_foreach(&buffers, struct gem_bo, bo) {
488 if (check_addr >= bo->offset && check_addr < (bo->offset + bo->size)) {
489 check_bo = bo;
490 break;
491 }
492 }
493
494 if (check_bo) {
495 fprintf(stderr, "address=0x%016"PRIx64" found in buffer 0x%016"PRIx64" size=0x%016"PRIx64"\n",
496 check_addr, check_bo->offset, check_bo->size);
497 } else {
498 fprintf(stderr, "address=0x%016"PRIx64" not found in buffer list\n", check_addr);
499 }
500 }
501
502 util_dynarray_foreach(&shader_addresses, uint64_t, addr) {
503 bool found = false;
504 util_dynarray_foreach(&buffers, struct gem_bo, bo) {
505 if (*addr < bo->offset || *addr >= (bo->offset + bo->size))
506 continue;
507 if (!bo->file_offset)
508 break;
509
510 uint64_t aligned_offset = ROUND_DOWN_TO(bo->file_offset, 4096);
511 uint64_t remaining_length = file_stats.st_size - aligned_offset;
512 void *map = mmap(NULL, remaining_length, PROT_READ, MAP_PRIVATE,
513 file_fd, aligned_offset);
514 if (map == MAP_FAILED)
515 break;
516
517 found = true;
518 fprintf(stderr, "shader at 0x%016"PRIx64" file_offset=0%016"PRIx64" addr_offset=%016"PRIx64":\n", *addr,
519 (bo->file_offset - aligned_offset), (*addr - bo->offset));
520 if (devinfo.ver >= 9) {
521 struct brw_isa_info _isa, *isa = &_isa;
522 brw_init_isa_info(isa, &devinfo);
523 brw_disassemble_with_errors(isa,
524 map + (bo->file_offset - aligned_offset) + (*addr - bo->offset),
525 0, stderr);
526 } else {
527 struct elk_isa_info _isa, *isa = &_isa;
528 elk_init_isa_info(isa, &devinfo);
529 elk_disassemble_with_errors(isa,
530 map + (bo->file_offset - aligned_offset) + (*addr - bo->offset),
531 0, stderr);
532 }
533
534 munmap(map, remaining_length);
535 }
536
537 if (!found)
538 fprintf(stderr, "shader at 0x%016"PRIx64" not found\n", *addr);
539 }
540
541 if (!list && util_dynarray_num_elements(&shader_addresses, uint64_t) == 0) {
542 /* Sort buffers by size */
543 qsort(util_dynarray_begin(&buffers),
544 util_dynarray_num_elements(&buffers, struct gem_bo),
545 sizeof(struct gem_bo),
546 compare_bos);
547
548 void *hw_img = NULL;
549 uint32_t hw_img_size = 0;
550
551 /* Allocate BOs populate them */
552 uint64_t gem_allocated = 0;
553 util_dynarray_foreach(&buffers, struct gem_bo, bo) {
554 lseek(file_fd, bo->file_offset, SEEK_SET);
555 if (bo->hw_img) {
556 hw_img = malloc(bo->size);
557 write_malloc_data(hw_img, file_fd, bo->size);
558 hw_img_size = bo->size;
559 } else {
560 bo->gem_handle = gem_create(drm_fd, bo->size);
561 write_gem_bo_data(drm_fd, bo->gem_handle, file_fd, bo->size);
562 }
563
564 gem_allocated += bo->size;
565 }
566
567 uint32_t ctx_id = gem_context_create(drm_fd);
568 if (ctx_id == 0) {
569 fprintf(stderr, "fail to create context: %s\n", strerror(errno));
570 return EXIT_FAILURE;
571 }
572
573 if (hw_img != NULL) {
574 if (!gem_context_set_hw_image(drm_fd, ctx_id, hw_img, hw_img_size)) {
575 fprintf(stderr, "fail to set context hw img: %s\n", strerror(errno));
576 return EXIT_FAILURE;
577 }
578 }
579
580 struct util_dynarray execbuffer_bos;
581 util_dynarray_init(&execbuffer_bos, mem_ctx);
582
583 struct gem_bo *init_bo = NULL, *batch_bo = NULL;
584 util_dynarray_foreach(&buffers, struct gem_bo, bo) {
585 if (bo->offset <= init.offset &&
586 (bo->offset + bo->size) > init.offset) {
587 init_bo = bo;
588 continue;
589 }
590
591 if (bo->offset <= exec.offset &&
592 (bo->offset + bo->size) > exec.offset) {
593 batch_bo = bo;
594 continue;
595 }
596
597 if (bo->hw_img)
598 continue;
599
600 struct drm_i915_gem_exec_object2 *execbuf_bo =
601 util_dynarray_grow(&execbuffer_bos, struct drm_i915_gem_exec_object2, 1);
602 *execbuf_bo = (struct drm_i915_gem_exec_object2) {
603 .handle = bo->gem_handle,
604 .relocation_count = 0,
605 .relocs_ptr = 0,
606 .flags = EXEC_OBJECT_SUPPORTS_48B_ADDRESS |
607 EXEC_OBJECT_PINNED |
608 EXEC_OBJECT_CAPTURE,
609 .offset = intel_canonical_address(bo->offset),
610 };
611 }
612
613 assert(batch_bo != NULL);
614
615 struct drm_i915_gem_exec_object2 *execbuf_bo =
616 util_dynarray_grow(&execbuffer_bos, struct drm_i915_gem_exec_object2, 1);
617
618 int ret;
619
620 if (init_bo) {
621 fprintf(stderr, "init: 0x%016"PRIx64"\n", init_bo->offset);
622 *execbuf_bo = (struct drm_i915_gem_exec_object2) {
623 .handle = init_bo->gem_handle,
624 .relocation_count = 0,
625 .relocs_ptr = 0,
626 .flags = EXEC_OBJECT_SUPPORTS_48B_ADDRESS |
627 EXEC_OBJECT_PINNED |
628 EXEC_OBJECT_CAPTURE,
629 .offset = intel_canonical_address(init_bo->offset),
630 };
631 ret = execbuffer(drm_fd, ctx_id, &execbuffer_bos, init_bo, init.offset);
632 if (ret != 0) {
633 fprintf(stderr, "initialization buffer failed to execute errno=%i\n", errno);
634 exit(-1);
635 }
636 } else {
637 fprintf(stderr, "no init BO\n");
638 }
639
640 if (batch_bo) {
641 fprintf(stderr, "exec: 0x%016"PRIx64" aperture=%.2fMb\n", batch_bo->offset,
642 gem_allocated / 1024.0 / 1024.0);
643 *execbuf_bo = (struct drm_i915_gem_exec_object2) {
644 .handle = batch_bo->gem_handle,
645 .relocation_count = 0,
646 .relocs_ptr = 0,
647 .flags = EXEC_OBJECT_SUPPORTS_48B_ADDRESS |
648 EXEC_OBJECT_PINNED |
649 EXEC_OBJECT_CAPTURE,
650 .offset = intel_canonical_address(batch_bo->offset),
651 };
652 ret = execbuffer(drm_fd, ctx_id, &execbuffer_bos, batch_bo, exec.offset);
653 if (ret != 0) {
654 fprintf(stderr, "replayed buffer failed to execute errno=%i\n", errno);
655 exit(-1);
656 } else {
657 fprintf(stderr, "exec completed successfully\n");
658 }
659 } else {
660 fprintf(stderr, "no exec BO\n");
661 }
662 }
663
664 close(drm_fd);
665 close(file_fd);
666
667 ralloc_free(mem_ctx);
668
669 return EXIT_SUCCESS;
670 }
671