101e04c3fSmrg/* 201e04c3fSmrg * Copyright © 2016 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 <stdio.h> 2501e04c3fSmrg#include <stdlib.h> 2601e04c3fSmrg#include <stdint.h> 2701e04c3fSmrg#include <stdbool.h> 2801e04c3fSmrg#include <getopt.h> 2901e04c3fSmrg 3001e04c3fSmrg#include <unistd.h> 3101e04c3fSmrg#include <fcntl.h> 3201e04c3fSmrg#include <string.h> 3301e04c3fSmrg#include <signal.h> 3401e04c3fSmrg#include <errno.h> 3501e04c3fSmrg#include <inttypes.h> 3601e04c3fSmrg#include <sys/types.h> 3701e04c3fSmrg#include <sys/stat.h> 3801e04c3fSmrg#include <sys/wait.h> 3901e04c3fSmrg#include <sys/mman.h> 4001e04c3fSmrg 4101e04c3fSmrg#include "util/macros.h" 4201e04c3fSmrg 4301e04c3fSmrg#include "aub_read.h" 4401e04c3fSmrg#include "aub_mem.h" 4501e04c3fSmrg 4601e04c3fSmrg#define CSI "\e[" 4701e04c3fSmrg#define GREEN_HEADER CSI "1;42m" 4801e04c3fSmrg#define NORMAL CSI "0m" 4901e04c3fSmrg 5001e04c3fSmrg/* options */ 5101e04c3fSmrg 5201e04c3fSmrgstatic int option_full_decode = true; 5301e04c3fSmrgstatic int option_print_offsets = true; 5401e04c3fSmrgstatic int max_vbo_lines = -1; 5501e04c3fSmrgstatic enum { COLOR_AUTO, COLOR_ALWAYS, COLOR_NEVER } option_color; 5601e04c3fSmrg 5701e04c3fSmrg/* state */ 5801e04c3fSmrg 5901e04c3fSmrguint16_t pci_id = 0; 6001e04c3fSmrgchar *input_file = NULL, *xml_path = NULL; 617ec681f3Smrgstruct intel_device_info devinfo; 627ec681f3Smrgstruct intel_batch_decode_ctx batch_ctx; 6301e04c3fSmrgstruct aub_mem mem; 6401e04c3fSmrg 6501e04c3fSmrgFILE *outfile; 6601e04c3fSmrg 6701e04c3fSmrgstruct brw_instruction; 6801e04c3fSmrg 6901e04c3fSmrgstatic void 7001e04c3fSmrgaubinator_error(void *user_data, const void *aub_data, const char *msg) 7101e04c3fSmrg{ 7201e04c3fSmrg fprintf(stderr, "%s", msg); 7301e04c3fSmrg} 7401e04c3fSmrg 7501e04c3fSmrgstatic void 7601e04c3fSmrgaubinator_init(void *user_data, int aub_pci_id, const char *app_name) 7701e04c3fSmrg{ 7801e04c3fSmrg pci_id = aub_pci_id; 7901e04c3fSmrg 807ec681f3Smrg if (!intel_get_device_info_from_pci_id(pci_id, &devinfo)) { 8101e04c3fSmrg fprintf(stderr, "can't find device information: pci_id=0x%x\n", pci_id); 8201e04c3fSmrg exit(EXIT_FAILURE); 8301e04c3fSmrg } 8401e04c3fSmrg 857ec681f3Smrg enum intel_batch_decode_flags batch_flags = 0; 8601e04c3fSmrg if (option_color == COLOR_ALWAYS) 877ec681f3Smrg batch_flags |= INTEL_BATCH_DECODE_IN_COLOR; 8801e04c3fSmrg if (option_full_decode) 897ec681f3Smrg batch_flags |= INTEL_BATCH_DECODE_FULL; 9001e04c3fSmrg if (option_print_offsets) 917ec681f3Smrg batch_flags |= INTEL_BATCH_DECODE_OFFSETS; 927ec681f3Smrg batch_flags |= INTEL_BATCH_DECODE_FLOATS; 9301e04c3fSmrg 947ec681f3Smrg intel_batch_decode_ctx_init(&batch_ctx, &devinfo, outfile, batch_flags, 957ec681f3Smrg xml_path, NULL, NULL, NULL); 9601e04c3fSmrg 9701e04c3fSmrg /* Check for valid spec instance, if wrong xml_path is passed then spec 9801e04c3fSmrg * instance is not initialized properly 9901e04c3fSmrg */ 10001e04c3fSmrg if (!batch_ctx.spec) { 1017ec681f3Smrg fprintf(stderr, "Failed to initialize intel_batch_decode_ctx " 10201e04c3fSmrg "spec instance\n"); 10301e04c3fSmrg free(xml_path); 1047ec681f3Smrg intel_batch_decode_ctx_finish(&batch_ctx); 10501e04c3fSmrg exit(EXIT_FAILURE); 10601e04c3fSmrg } 10701e04c3fSmrg 10801e04c3fSmrg batch_ctx.max_vbo_decoded_lines = max_vbo_lines; 10901e04c3fSmrg 11001e04c3fSmrg char *color = GREEN_HEADER, *reset_color = NORMAL; 11101e04c3fSmrg if (option_color == COLOR_NEVER) 11201e04c3fSmrg color = reset_color = ""; 11301e04c3fSmrg 11401e04c3fSmrg fprintf(outfile, "%sAubinator: Intel AUB file decoder.%-80s%s\n", 11501e04c3fSmrg color, "", reset_color); 11601e04c3fSmrg 11701e04c3fSmrg if (input_file) 11801e04c3fSmrg fprintf(outfile, "File name: %s\n", input_file); 11901e04c3fSmrg 12001e04c3fSmrg if (aub_pci_id) 12101e04c3fSmrg fprintf(outfile, "PCI ID: 0x%x\n", aub_pci_id); 12201e04c3fSmrg 12301e04c3fSmrg fprintf(outfile, "Application name: %s\n", app_name); 12401e04c3fSmrg 1257ec681f3Smrg fprintf(outfile, "Decoding as: %s\n", devinfo.name); 12601e04c3fSmrg 12701e04c3fSmrg /* Throw in a new line before the first batch */ 12801e04c3fSmrg fprintf(outfile, "\n"); 12901e04c3fSmrg} 13001e04c3fSmrg 1317ec681f3Smrgstatic struct intel_batch_decode_bo 1329f464c52Smayaget_bo(void *user_data, bool ppgtt, uint64_t addr) 1339f464c52Smaya{ 1349f464c52Smaya if (ppgtt) 1359f464c52Smaya return aub_mem_get_ppgtt_bo(user_data, addr); 1369f464c52Smaya else 1379f464c52Smaya return aub_mem_get_ggtt_bo(user_data, addr); 1389f464c52Smaya} 1399f464c52Smaya 14001e04c3fSmrgstatic void 1419f464c52Smayahandle_execlist_write(void *user_data, enum drm_i915_gem_engine_class engine, uint64_t context_descriptor) 14201e04c3fSmrg{ 14301e04c3fSmrg const uint32_t pphwsp_size = 4096; 14401e04c3fSmrg uint32_t pphwsp_addr = context_descriptor & 0xfffff000; 1457ec681f3Smrg struct intel_batch_decode_bo pphwsp_bo = aub_mem_get_ggtt_bo(&mem, pphwsp_addr); 14601e04c3fSmrg uint32_t *context = (uint32_t *)((uint8_t *)pphwsp_bo.map + 14701e04c3fSmrg (pphwsp_addr - pphwsp_bo.addr) + 14801e04c3fSmrg pphwsp_size); 14901e04c3fSmrg 15001e04c3fSmrg uint32_t ring_buffer_head = context[5]; 15101e04c3fSmrg uint32_t ring_buffer_tail = context[7]; 15201e04c3fSmrg uint32_t ring_buffer_start = context[9]; 1539f464c52Smaya uint32_t ring_buffer_length = (context[11] & 0x1ff000) + 4096; 15401e04c3fSmrg 15501e04c3fSmrg mem.pml4 = (uint64_t)context[49] << 32 | context[51]; 15601e04c3fSmrg batch_ctx.user_data = &mem; 15701e04c3fSmrg 1587ec681f3Smrg struct intel_batch_decode_bo ring_bo = aub_mem_get_ggtt_bo(&mem, 1597ec681f3Smrg ring_buffer_start); 16001e04c3fSmrg assert(ring_bo.size > 0); 1619f464c52Smaya void *commands = (uint8_t *)ring_bo.map + (ring_buffer_start - ring_bo.addr) + ring_buffer_head; 16201e04c3fSmrg 1639f464c52Smaya batch_ctx.get_bo = get_bo; 16401e04c3fSmrg 1659f464c52Smaya batch_ctx.engine = engine; 1667ec681f3Smrg intel_print_batch(&batch_ctx, commands, 1679f464c52Smaya MIN2(ring_buffer_tail - ring_buffer_head, ring_buffer_length), 1689f464c52Smaya ring_bo.addr + ring_buffer_head, true); 16901e04c3fSmrg aub_mem_clear_bo_maps(&mem); 17001e04c3fSmrg} 17101e04c3fSmrg 1727ec681f3Smrgstatic struct intel_batch_decode_bo 1739f464c52Smayaget_legacy_bo(void *user_data, bool ppgtt, uint64_t addr) 1749f464c52Smaya{ 1759f464c52Smaya return aub_mem_get_ggtt_bo(user_data, addr); 1769f464c52Smaya} 1779f464c52Smaya 17801e04c3fSmrgstatic void 1799f464c52Smayahandle_ring_write(void *user_data, enum drm_i915_gem_engine_class engine, 18001e04c3fSmrg const void *data, uint32_t data_len) 18101e04c3fSmrg{ 18201e04c3fSmrg batch_ctx.user_data = &mem; 1839f464c52Smaya batch_ctx.get_bo = get_legacy_bo; 18401e04c3fSmrg 1859f464c52Smaya batch_ctx.engine = engine; 1867ec681f3Smrg intel_print_batch(&batch_ctx, data, data_len, 0, false); 18701e04c3fSmrg 18801e04c3fSmrg aub_mem_clear_bo_maps(&mem); 18901e04c3fSmrg} 19001e04c3fSmrg 19101e04c3fSmrgstruct aub_file { 19201e04c3fSmrg FILE *stream; 19301e04c3fSmrg 19401e04c3fSmrg void *map, *end, *cursor; 19501e04c3fSmrg}; 19601e04c3fSmrg 19701e04c3fSmrgstatic struct aub_file * 19801e04c3fSmrgaub_file_open(const char *filename) 19901e04c3fSmrg{ 20001e04c3fSmrg struct aub_file *file; 20101e04c3fSmrg struct stat sb; 20201e04c3fSmrg int fd; 20301e04c3fSmrg 20401e04c3fSmrg file = calloc(1, sizeof *file); 20501e04c3fSmrg if (file == NULL) 20601e04c3fSmrg return NULL; 20701e04c3fSmrg 20801e04c3fSmrg fd = open(filename, O_RDONLY); 20901e04c3fSmrg if (fd == -1) { 21001e04c3fSmrg fprintf(stderr, "open %s failed: %s\n", filename, strerror(errno)); 21101e04c3fSmrg free(file); 21201e04c3fSmrg exit(EXIT_FAILURE); 21301e04c3fSmrg } 21401e04c3fSmrg 21501e04c3fSmrg if (fstat(fd, &sb) == -1) { 21601e04c3fSmrg fprintf(stderr, "stat failed: %s\n", strerror(errno)); 21701e04c3fSmrg free(file); 21801e04c3fSmrg exit(EXIT_FAILURE); 21901e04c3fSmrg } 22001e04c3fSmrg 22101e04c3fSmrg file->map = mmap(NULL, sb.st_size, 22201e04c3fSmrg PROT_READ, MAP_SHARED, fd, 0); 22301e04c3fSmrg if (file->map == MAP_FAILED) { 22401e04c3fSmrg fprintf(stderr, "mmap failed: %s\n", strerror(errno)); 22501e04c3fSmrg free(file); 22601e04c3fSmrg exit(EXIT_FAILURE); 22701e04c3fSmrg } 22801e04c3fSmrg 22901e04c3fSmrg close(fd); 23001e04c3fSmrg 23101e04c3fSmrg file->cursor = file->map; 23201e04c3fSmrg file->end = file->map + sb.st_size; 23301e04c3fSmrg 23401e04c3fSmrg return file; 23501e04c3fSmrg} 23601e04c3fSmrg 23701e04c3fSmrgstatic int 23801e04c3fSmrgaub_file_more_stuff(struct aub_file *file) 23901e04c3fSmrg{ 24001e04c3fSmrg return file->cursor < file->end || (file->stream && !feof(file->stream)); 24101e04c3fSmrg} 24201e04c3fSmrg 24301e04c3fSmrgstatic void 24401e04c3fSmrgsetup_pager(void) 24501e04c3fSmrg{ 24601e04c3fSmrg int fds[2]; 24701e04c3fSmrg pid_t pid; 24801e04c3fSmrg 24901e04c3fSmrg if (!isatty(1)) 25001e04c3fSmrg return; 25101e04c3fSmrg 25201e04c3fSmrg if (pipe(fds) == -1) 25301e04c3fSmrg return; 25401e04c3fSmrg 25501e04c3fSmrg pid = fork(); 25601e04c3fSmrg if (pid == -1) 25701e04c3fSmrg return; 25801e04c3fSmrg 25901e04c3fSmrg if (pid == 0) { 26001e04c3fSmrg close(fds[1]); 26101e04c3fSmrg dup2(fds[0], 0); 26201e04c3fSmrg execlp("less", "less", "-FRSi", NULL); 26301e04c3fSmrg } 26401e04c3fSmrg 26501e04c3fSmrg close(fds[0]); 26601e04c3fSmrg dup2(fds[1], 1); 26701e04c3fSmrg close(fds[1]); 26801e04c3fSmrg} 26901e04c3fSmrg 27001e04c3fSmrgstatic void 27101e04c3fSmrgprint_help(const char *progname, FILE *file) 27201e04c3fSmrg{ 27301e04c3fSmrg fprintf(file, 27401e04c3fSmrg "Usage: %s [OPTION]... FILE\n" 27501e04c3fSmrg "Decode aub file contents from FILE.\n\n" 27601e04c3fSmrg " --help display this help and exit\n" 27701e04c3fSmrg " --gen=platform decode for given platform (3 letter platform name)\n" 27801e04c3fSmrg " --headers decode only command headers\n" 27901e04c3fSmrg " --color[=WHEN] colorize the output; WHEN can be 'auto' (default\n" 28001e04c3fSmrg " if omitted), 'always', or 'never'\n" 28101e04c3fSmrg " --max-vbo-lines=N limit the number of decoded VBO lines\n" 28201e04c3fSmrg " --no-pager don't launch pager\n" 28301e04c3fSmrg " --no-offsets don't print instruction offsets\n" 28401e04c3fSmrg " --xml=DIR load hardware xml description from directory DIR\n", 28501e04c3fSmrg progname); 28601e04c3fSmrg} 28701e04c3fSmrg 28801e04c3fSmrgint main(int argc, char *argv[]) 28901e04c3fSmrg{ 29001e04c3fSmrg struct aub_file *file; 29101e04c3fSmrg int c, i; 29201e04c3fSmrg bool help = false, pager = true; 29301e04c3fSmrg const struct option aubinator_opts[] = { 29401e04c3fSmrg { "help", no_argument, (int *) &help, true }, 29501e04c3fSmrg { "no-pager", no_argument, (int *) &pager, false }, 29601e04c3fSmrg { "no-offsets", no_argument, (int *) &option_print_offsets, false }, 29701e04c3fSmrg { "gen", required_argument, NULL, 'g' }, 29801e04c3fSmrg { "headers", no_argument, (int *) &option_full_decode, false }, 2997ec681f3Smrg { "color", optional_argument, NULL, 'c' }, 30001e04c3fSmrg { "xml", required_argument, NULL, 'x' }, 30101e04c3fSmrg { "max-vbo-lines", required_argument, NULL, 'v' }, 30201e04c3fSmrg { NULL, 0, NULL, 0 } 30301e04c3fSmrg }; 30401e04c3fSmrg 30501e04c3fSmrg outfile = stdout; 30601e04c3fSmrg 30701e04c3fSmrg i = 0; 30801e04c3fSmrg while ((c = getopt_long(argc, argv, "", aubinator_opts, &i)) != -1) { 30901e04c3fSmrg switch (c) { 31001e04c3fSmrg case 'g': { 3117ec681f3Smrg const int id = intel_device_name_to_pci_device_id(optarg); 31201e04c3fSmrg if (id < 0) { 31301e04c3fSmrg fprintf(stderr, "can't parse gen: '%s', expected brw, g4x, ilk, " 31401e04c3fSmrg "snb, ivb, hsw, byt, bdw, chv, skl, bxt, kbl, " 31501e04c3fSmrg "aml, glk, cfl, whl, cnl, icl", optarg); 31601e04c3fSmrg exit(EXIT_FAILURE); 31701e04c3fSmrg } else { 31801e04c3fSmrg pci_id = id; 31901e04c3fSmrg } 32001e04c3fSmrg break; 32101e04c3fSmrg } 32201e04c3fSmrg case 'c': 32301e04c3fSmrg if (optarg == NULL || strcmp(optarg, "always") == 0) 32401e04c3fSmrg option_color = COLOR_ALWAYS; 32501e04c3fSmrg else if (strcmp(optarg, "never") == 0) 32601e04c3fSmrg option_color = COLOR_NEVER; 32701e04c3fSmrg else if (strcmp(optarg, "auto") == 0) 32801e04c3fSmrg option_color = COLOR_AUTO; 32901e04c3fSmrg else { 33001e04c3fSmrg fprintf(stderr, "invalid value for --color: %s", optarg); 33101e04c3fSmrg exit(EXIT_FAILURE); 33201e04c3fSmrg } 33301e04c3fSmrg break; 33401e04c3fSmrg case 'x': 33501e04c3fSmrg xml_path = strdup(optarg); 33601e04c3fSmrg break; 33701e04c3fSmrg case 'v': 33801e04c3fSmrg max_vbo_lines = atoi(optarg); 33901e04c3fSmrg break; 34001e04c3fSmrg default: 34101e04c3fSmrg break; 34201e04c3fSmrg } 34301e04c3fSmrg } 34401e04c3fSmrg 34501e04c3fSmrg if (optind < argc) 34601e04c3fSmrg input_file = argv[optind]; 34701e04c3fSmrg 34801e04c3fSmrg if (help || !input_file) { 34901e04c3fSmrg print_help(argv[0], stderr); 35001e04c3fSmrg exit(0); 35101e04c3fSmrg } 35201e04c3fSmrg 35301e04c3fSmrg /* Do this before we redirect stdout to pager. */ 35401e04c3fSmrg if (option_color == COLOR_AUTO) 35501e04c3fSmrg option_color = isatty(1) ? COLOR_ALWAYS : COLOR_NEVER; 35601e04c3fSmrg 35701e04c3fSmrg if (isatty(1) && pager) 35801e04c3fSmrg setup_pager(); 35901e04c3fSmrg 36001e04c3fSmrg if (!aub_mem_init(&mem)) { 36101e04c3fSmrg fprintf(stderr, "Unable to create GTT\n"); 36201e04c3fSmrg exit(EXIT_FAILURE); 36301e04c3fSmrg } 36401e04c3fSmrg 36501e04c3fSmrg file = aub_file_open(input_file); 36601e04c3fSmrg if (!file) { 36701e04c3fSmrg fprintf(stderr, "Unable to allocate buffer to open aub file\n"); 36801e04c3fSmrg free(xml_path); 36901e04c3fSmrg exit(EXIT_FAILURE); 37001e04c3fSmrg } 37101e04c3fSmrg 37201e04c3fSmrg struct aub_read aub_read = { 37301e04c3fSmrg .user_data = &mem, 37401e04c3fSmrg .error = aubinator_error, 37501e04c3fSmrg .info = aubinator_init, 37601e04c3fSmrg 37701e04c3fSmrg .local_write = aub_mem_local_write, 37801e04c3fSmrg .phys_write = aub_mem_phys_write, 37901e04c3fSmrg .ggtt_write = aub_mem_ggtt_write, 38001e04c3fSmrg .ggtt_entry_write = aub_mem_ggtt_entry_write, 38101e04c3fSmrg 38201e04c3fSmrg .execlist_write = handle_execlist_write, 38301e04c3fSmrg .ring_write = handle_ring_write, 38401e04c3fSmrg }; 38501e04c3fSmrg int consumed; 38601e04c3fSmrg while (aub_file_more_stuff(file) && 38701e04c3fSmrg (consumed = aub_read_command(&aub_read, file->cursor, 38801e04c3fSmrg file->end - file->cursor)) > 0) { 38901e04c3fSmrg file->cursor += consumed; 39001e04c3fSmrg } 39101e04c3fSmrg 39201e04c3fSmrg aub_mem_fini(&mem); 39301e04c3fSmrg 39401e04c3fSmrg fflush(stdout); 39501e04c3fSmrg /* close the stdout which is opened to write the output */ 39601e04c3fSmrg close(1); 39701e04c3fSmrg free(file); 39801e04c3fSmrg free(xml_path); 39901e04c3fSmrg 40001e04c3fSmrg wait(NULL); 4017ec681f3Smrg intel_batch_decode_ctx_finish(&batch_ctx); 40201e04c3fSmrg 40301e04c3fSmrg return EXIT_SUCCESS; 40401e04c3fSmrg} 405