X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fintel%2Ftools%2Faubinator.c;h=68fd18cd684b64db49c448ec83da4b4c13cb8208;hb=7d84bb32aa6698211bfe4697609501ad94a266b9;hp=fe1f369ec21aa29ece0927c350434dbb1fae3835;hpb=d50c56f8687036fdb345d6def3262fd0929a04ad;p=mesa.git diff --git a/src/intel/tools/aubinator.c b/src/intel/tools/aubinator.c index fe1f369ec21..68fd18cd684 100644 --- a/src/intel/tools/aubinator.c +++ b/src/intel/tools/aubinator.c @@ -24,19 +24,22 @@ #include #include #include +#include #include #include #include #include #include -#include +#include #include #include #include #include -#include "decoder.h" +#include "util/macros.h" + +#include "common/gen_decoder.h" #include "intel_aub.h" #include "gen_disasm.h" @@ -47,9 +50,9 @@ #define AUB_MI_BATCH_BUFFER_END (0x0500 << 16) #define CSI "\e[" -#define HEADER CSI "37;44m" -#define NORMAL CSI "0m" -#define CLEAR_TO_EOL CSI "0K" +#define BLUE_HEADER CSI "0;44m" +#define GREEN_HEADER CSI "1;42m" +#define NORMAL CSI "0m" /* options */ @@ -59,6 +62,9 @@ static enum { COLOR_AUTO, COLOR_ALWAYS, COLOR_NEVER } option_color; /* state */ +uint16_t pci_id = 0; +char *input_file = NULL, *xml_path = NULL; +struct gen_spec *spec; struct gen_disasm *disasm; uint64_t gtt_size, gtt_end; @@ -69,6 +75,8 @@ uint64_t dynamic_state_base; uint64_t instruction_base; uint64_t instruction_bound; +FILE *outfile; + static inline uint32_t field(uint32_t value, int start, int end) { @@ -88,78 +96,11 @@ valid_offset(uint32_t offset) } static void -print_dword_val(struct gen_field_iterator *iter, uint64_t offset, - int *dword_num) -{ - struct gen_field *f; - union { - uint32_t dw; - float f; - } v; - - f = iter->group->fields[iter->i - 1]; - v.dw = iter->p[f->start / 32]; - - if (*dword_num != (f->start / 32)) { - printf("0x%08lx: 0x%08x : Dword %d\n", - offset + 4 * (f->start / 32), v.dw, f->start / 32); - *dword_num = (f->start / 32); - } -} - -static char * -print_iterator_values(struct gen_field_iterator *iter, int *idx) -{ - char *token = NULL; - if (strstr(iter->value, "struct") == NULL) { - printf(" %s: %s\n", iter->name, iter->value); - } else { - token = strtok(iter->value, " "); - if (token != NULL) { - token = strtok(NULL, " "); - *idx = atoi(strtok(NULL, ">")); - } else { - token = NULL; - } - printf(" %s:\n", iter->name, token); - } - return token; -} - -static void -decode_structure(struct gen_spec *spec, struct gen_group *strct, - const uint32_t *p) +decode_group(struct gen_group *strct, const uint32_t *p, int starting_dword) { - struct gen_field_iterator iter; - char *token = NULL; - int idx = 0, dword_num = 0; - uint64_t offset = 0; - - if (option_print_offsets) - offset = (void *) p - gtt; - else - offset = 0; - - gen_field_iterator_init(&iter, strct, p); - while (gen_field_iterator_next(&iter)) { - idx = 0; - print_dword_val(&iter, offset, &dword_num); - token = print_iterator_values(&iter, &idx); - if (token != NULL) { - struct gen_group *struct_val = gen_spec_find_struct(spec, token); - decode_structure(spec, struct_val, &p[idx]); - token = NULL; - } - } -} - -static void -handle_struct_decode(struct gen_spec *spec, char *struct_name, uint32_t *p) -{ - if (struct_name == NULL) - return; - struct gen_group *struct_val = gen_spec_find_struct(spec, struct_name); - decode_structure(spec, struct_val, p); + uint64_t offset = option_print_offsets ? (void *) p - gtt : 0; + gen_print_group(outfile, strct, offset, p, starting_dword, + option_color == COLOR_ALWAYS); } static void @@ -171,7 +112,7 @@ dump_binding_table(struct gen_spec *spec, uint32_t offset) surface_state = gen_spec_find_struct(spec, "RENDER_SURFACE_STATE"); if (surface_state == NULL) { - printf("did not find RENDER_SURFACE_STATE info\n"); + fprintf(outfile, "did not find RENDER_SURFACE_STATE info\n"); return; } @@ -182,14 +123,14 @@ dump_binding_table(struct gen_spec *spec, uint32_t offset) continue; start = pointers[i] + surface_state_base; if (!valid_offset(start)) { - printf("pointer %u: %08x \n", - i, pointers[i]); + fprintf(outfile, "pointer %u: %08x \n", + i, pointers[i]); continue; } else { - printf("pointer %u: %08x\n", i, pointers[i]); + fprintf(outfile, "pointer %u: %08x\n", i, pointers[i]); } - decode_structure(spec, surface_state, gtt + start); + decode_group(surface_state, gtt + start, 0); } } @@ -206,58 +147,86 @@ handle_3dstate_index_buffer(struct gen_spec *spec, uint32_t *p) if (length > 10) length = 10; - printf("\t"); + fprintf(outfile, "\t"); for (i = 0; i < length; i++) { switch (type) { case 0: - printf("%3d ", ((uint8_t *)start)[i]); + fprintf(outfile, "%3d ", ((uint8_t *)start)[i]); break; case 1: - printf("%3d ", ((uint16_t *)start)[i]); + fprintf(outfile, "%3d ", ((uint16_t *)start)[i]); break; case 2: - printf("%3d ", ((uint32_t *)start)[i]); + fprintf(outfile, "%3d ", ((uint32_t *)start)[i]); break; } } if (length < p[4] / size) - printf("...\n"); + fprintf(outfile, "...\n"); else - printf("\n"); + fprintf(outfile, "\n"); } static inline uint64_t -get_qword(uint32_t *p) +get_address(struct gen_spec *spec, uint32_t *p) { - return ((uint64_t) p[1] << 32) | p[0]; + /* Addresses are always guaranteed to be page-aligned and sometimes + * hardware packets have extra stuff stuffed in the bottom 12 bits. + */ + uint64_t addr = p[0] & ~0xfffu; + + if (gen_spec_get_gen(spec) >= gen_make_gen(8,0)) { + /* On Broadwell and above, we have 48-bit addresses which consume two + * dwords. Some packets require that these get stored in a "canonical + * form" which means that bit 47 is sign-extended through the upper + * bits. In order to correctly handle those aub dumps, we need to mask + * off the top 16 bits. + */ + addr |= ((uint64_t)p[1] & 0xffff) << 32; + } + + return addr; +} + +static inline uint64_t +get_offset(uint32_t *p, uint32_t start, uint32_t end) +{ + assert(start <= end); + assert(end < 64); + + uint64_t mask = (~0ull >> (64 - (end - start + 1))) << start; + + uint64_t offset = p[0]; + if (end >= 32) + offset |= (uint64_t) p[1] << 32; + + return offset & mask; } static void handle_state_base_address(struct gen_spec *spec, uint32_t *p) { - uint64_t mask = ~((1 << 12) - 1); - if (gen_spec_get_gen(spec) >= gen_make_gen(8,0)) { if (p[1] & 1) - general_state_base = get_qword(&p[1]) & mask; + general_state_base = get_address(spec, &p[1]); if (p[4] & 1) - surface_state_base = get_qword(&p[4]) & mask; + surface_state_base = get_address(spec, &p[4]); if (p[6] & 1) - dynamic_state_base = get_qword(&p[6]) & mask; + dynamic_state_base = get_address(spec, &p[6]); if (p[10] & 1) - instruction_base = get_qword(&p[10]) & mask; + instruction_base = get_address(spec, &p[10]); if (p[15] & 1) - instruction_bound = p[15] & mask; + instruction_bound = p[15] & 0xfff; } else { if (p[2] & 1) - surface_state_base = p[2] & mask; + surface_state_base = get_address(spec, &p[2]); if (p[3] & 1) - dynamic_state_base = p[3] & mask; + dynamic_state_base = get_address(spec, &p[3]); if (p[5] & 1) - instruction_base = p[5] & mask; + instruction_base = get_address(spec, &p[5]); if (p[9] & 1) - instruction_bound = p[9] & mask; + instruction_bound = get_address(spec, &p[9]); } } @@ -272,8 +241,8 @@ dump_samplers(struct gen_spec *spec, uint32_t offset) start = dynamic_state_base + offset; for (i = 0; i < 4; i++) { - printf("sampler state %d\n", i); - decode_structure(spec, sampler_state, gtt + start + i * 16); + fprintf(outfile, "sampler state %d\n", i); + decode_group(sampler_state, gtt + start + i * 16, 0); } } @@ -289,26 +258,26 @@ handle_media_interface_descriptor_load(struct gen_spec *spec, uint32_t *p) descriptor_structure = gen_spec_find_struct(spec, "INTERFACE_DESCRIPTOR_DATA"); if (descriptor_structure == NULL) { - printf("did not find INTERFACE_DESCRIPTOR_DATA info\n"); + fprintf(outfile, "did not find INTERFACE_DESCRIPTOR_DATA info\n"); return; } start = dynamic_state_base + p[3]; descriptors = gtt + start; for (i = 0; i < length; i++, descriptors += 8) { - printf("descriptor %u: %08x\n", i, *descriptors); - decode_structure(spec, descriptor_structure, descriptors); + fprintf(outfile, "descriptor %u: %08x\n", i, *descriptors); + decode_group(descriptor_structure, descriptors, 0); start = instruction_base + descriptors[0]; if (!valid_offset(start)) { - printf("kernel: %08lx \n", start); + fprintf(outfile, "kernel: %08"PRIx64" \n", start); continue; } else { - printf("kernel: %08lx\n", start); + fprintf(outfile, "kernel: %08"PRIx64"\n", start); } insns = (struct brw_instruction *) (gtt + start); - gen_disasm_disassemble(disasm, insns, 0, 8192, stdout); + gen_disasm_disassemble(disasm, insns, 0, stdout); dump_samplers(spec, descriptors[3] & ~0x1f); dump_binding_table(spec, descriptors[4] & ~0x1f); @@ -359,30 +328,30 @@ handle_3dstate_vertex_buffers(struct gen_spec *spec, uint32_t *p) stride = field(s[0], 0, 11); count = 0; - printf("vertex buffer %d, size %d\n", n, s[3]); + fprintf(outfile, "vertex buffer %d, size %d\n", n, s[3]); for (dw = gtt + offset, i = 0; dw < dwend && i < 256; dw++) { if (count == 0 && count % (8 * 4) == 0) - printf(" "); + fprintf(outfile, " "); if (probably_float(*dw)) - printf(" %8.2f", *(float *) dw); + fprintf(outfile, " %8.2f", *(float *) dw); else - printf(" 0x%08x", *dw); + fprintf(outfile, " 0x%08x", *dw); i++; count += 4; if (count == stride) { - printf("\n"); + fprintf(outfile, "\n"); count = 0; } else if (count % (8 * 4) == 0) { - printf("\n"); + fprintf(outfile, "\n"); } else { - printf(" "); + fprintf(outfile, " "); } } if (count > 0 && count % (8 * 4) != 0) - printf("\n"); + fprintf(outfile, "\n"); } } @@ -394,19 +363,19 @@ handle_3dstate_vs(struct gen_spec *spec, uint32_t *p) int vs_enable; if (gen_spec_get_gen(spec) >= gen_make_gen(8, 0)) { - start = get_qword(&p[1]); + start = get_offset(&p[1], 6, 63); vs_enable = p[7] & 1; } else { - start = p[1]; + start = get_offset(&p[1], 6, 31); vs_enable = p[5] & 1; } if (vs_enable) { - printf("instruction_base %08lx, start %08lx\n", - instruction_base, start); + fprintf(outfile, "instruction_base %08"PRIx64", start %08"PRIx64"\n", + instruction_base, start); insns = (struct brw_instruction *) (gtt + instruction_base + start); - gen_disasm_disassemble(disasm, insns, 0, 8192, stdout); + gen_disasm_disassemble(disasm, insns, 0, stdout); } } @@ -418,19 +387,19 @@ handle_3dstate_hs(struct gen_spec *spec, uint32_t *p) int hs_enable; if (gen_spec_get_gen(spec) >= gen_make_gen(8, 0)) { - start = get_qword(&p[4]); + start = get_offset(&p[3], 6, 63); } else { - start = p[4]; + start = get_offset(&p[3], 6, 31); } hs_enable = p[2] & 0x80000000; if (hs_enable) { - printf("instruction_base %08lx, start %08lx\n", - instruction_base, start); + fprintf(outfile, "instruction_base %08"PRIx64", start %08"PRIx64"\n", + instruction_base, start); insns = (struct brw_instruction *) (gtt + instruction_base + start); - gen_disasm_disassemble(disasm, insns, 0, 8192, stdout); + gen_disasm_disassemble(disasm, insns, 0, stdout); } } @@ -447,12 +416,12 @@ handle_3dstate_constant(struct gen_spec *spec, uint32_t *p) dw = (uint32_t *) f; for (j = 0; j < length * 8; j++) { if (probably_float(dw[j])) - printf(" %04.3f", f[j]); + fprintf(outfile, " %04.3f", f[j]); else - printf(" 0x%08x", dw[j]); + fprintf(outfile, " 0x%08x", dw[j]); if ((j & 7) == 7) - printf("\n"); + fprintf(outfile, "\n"); } } } @@ -521,24 +490,24 @@ handle_3dstate_ps(struct gen_spec *spec, uint32_t *p) } start = instruction_base + (p[1] & mask); - printf(" Kernel[0] %s\n", k0); + fprintf(outfile, " Kernel[0] %s\n", k0); if (k0 != unused) { insns = (struct brw_instruction *) (gtt + start); - gen_disasm_disassemble(disasm, insns, 0, 8192, stdout); + gen_disasm_disassemble(disasm, insns, 0, stdout); } start = instruction_base + (p[k1_offset] & mask); - printf(" Kernel[1] %s\n", k1); + fprintf(outfile, " Kernel[1] %s\n", k1); if (k1 != unused) { insns = (struct brw_instruction *) (gtt + start); - gen_disasm_disassemble(disasm, insns, 0, 8192, stdout); + gen_disasm_disassemble(disasm, insns, 0, stdout); } start = instruction_base + (p[k2_offset] & mask); - printf(" Kernel[2] %s\n", k2); + fprintf(outfile, " Kernel[2] %s\n", k2); if (k2 != unused) { insns = (struct brw_instruction *) (gtt + start); - gen_disasm_disassemble(disasm, insns, 0, 8192, stdout); + gen_disasm_disassemble(disasm, insns, 0, stdout); } } @@ -564,8 +533,8 @@ handle_3dstate_viewport_state_pointers_cc(struct gen_spec *spec, uint32_t *p) start = dynamic_state_base + (p[1] & ~0x1fu); for (uint32_t i = 0; i < 4; i++) { - printf("viewport %d\n", i); - decode_structure(spec, cc_viewport, gtt + start + i * 8); + fprintf(outfile, "viewport %d\n", i); + decode_group(cc_viewport, gtt + start + i * 8, 0); } } @@ -580,8 +549,8 @@ handle_3dstate_viewport_state_pointers_sf_clip(struct gen_spec *spec, start = dynamic_state_base + (p[1] & ~0x3fu); for (uint32_t i = 0; i < 4; i++) { - printf("viewport %d\n", i); - decode_structure(spec, sf_clip_viewport, gtt + start + i * 64); + fprintf(outfile, "viewport %d\n", i); + decode_group(sf_clip_viewport, gtt + start + i * 64, 0); } } @@ -594,7 +563,7 @@ handle_3dstate_blend_state_pointers(struct gen_spec *spec, uint32_t *p) blend_state = gen_spec_find_struct(spec, "BLEND_STATE"); start = dynamic_state_base + (p[1] & ~0x3fu); - decode_structure(spec, blend_state, gtt + start); + decode_group(blend_state, gtt + start, 0); } static void @@ -606,7 +575,7 @@ handle_3dstate_cc_state_pointers(struct gen_spec *spec, uint32_t *p) cc_state = gen_spec_find_struct(spec, "COLOR_CALC_STATE"); start = dynamic_state_base + (p[1] & ~0x3fu); - decode_structure(spec, cc_state, gtt + start); + decode_group(cc_state, gtt + start, 0); } static void @@ -618,7 +587,19 @@ handle_3dstate_scissor_state_pointers(struct gen_spec *spec, uint32_t *p) scissor_rect = gen_spec_find_struct(spec, "SCISSOR_RECT"); start = dynamic_state_base + (p[1] & ~0x1fu); - decode_structure(spec, scissor_rect, gtt + start); + decode_group(scissor_rect, gtt + start, 0); +} + +static void +handle_load_register_imm(struct gen_spec *spec, uint32_t *p) +{ + struct gen_group *reg = gen_spec_find_register(spec, p[1]); + + if (reg != NULL) { + fprintf(outfile, "register %s (0x%x): 0x%x\n", + reg->name, reg->register_offset, p[2]); + decode_group(reg, &p[2], 0); + } } #define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0]) @@ -659,6 +640,8 @@ handle_3dstate_scissor_state_pointers(struct gen_spec *spec, uint32_t *p) #define _3DSTATE_CC_STATE_POINTERS 0x780e0000 #define _3DSTATE_SCISSOR_STATE_POINTERS 0x780f0000 +#define _MI_LOAD_REGISTER_IMM 0x11000000 + struct custom_handler { uint32_t opcode; void (*handle)(struct gen_spec *spec, uint32_t *p); @@ -692,7 +675,8 @@ struct custom_handler { { _3DSTATE_VIEWPORT_STATE_POINTERS_SF_CLIP, handle_3dstate_viewport_state_pointers_sf_clip }, { _3DSTATE_BLEND_STATE_POINTERS, handle_3dstate_blend_state_pointers }, { _3DSTATE_CC_STATE_POINTERS, handle_3dstate_cc_state_pointers }, - { _3DSTATE_SCISSOR_STATE_POINTERS, handle_3dstate_scissor_state_pointers } + { _3DSTATE_SCISSOR_STATE_POINTERS, handle_3dstate_scissor_state_pointers }, + { _MI_LOAD_REGISTER_IMM, handle_load_register_imm } }; static void @@ -705,18 +689,22 @@ parse_commands(struct gen_spec *spec, uint32_t *cmds, int size, int engine) for (p = cmds; p < end; p += length) { inst = gen_spec_find_instruction(spec, p); if (inst == NULL) { - printf("unknown instruction %08x\n", p[0]); + fprintf(outfile, "unknown instruction %08x\n", p[0]); length = (p[0] & 0xff) + 2; continue; } length = gen_group_get_length(inst, p); - const char *color, *reset_color = CLEAR_TO_EOL NORMAL; + const char *color, *reset_color = NORMAL; uint64_t offset; - if (option_full_decode) - color = HEADER; - else + if (option_full_decode) { + if ((p[0] & 0xffff0000) == AUB_MI_BATCH_BUFFER_START || + (p[0] & 0xffff0000) == AUB_MI_BATCH_BUFFER_END) + color = GREEN_HEADER; + else + color = BLUE_HEADER; + } else color = NORMAL; if (option_color == COLOR_NEVER) { @@ -729,43 +717,41 @@ parse_commands(struct gen_spec *spec, uint32_t *cmds, int size, int engine) else offset = 0; - printf("%s0x%08lx: 0x%08x: %s%s\n", - color, offset, p[0], - gen_group_get_name(inst), reset_color); + fprintf(outfile, "%s0x%08"PRIx64": 0x%08x: %-80s%s\n", + color, offset, p[0], + gen_group_get_name(inst), reset_color); if (option_full_decode) { - struct gen_field_iterator iter; - char *token = NULL; - int idx = 0, dword_num = 0; - gen_field_iterator_init(&iter, inst, p); - while (gen_field_iterator_next(&iter)) { - idx = 0; - print_dword_val(&iter, offset, &dword_num); - if (dword_num > 0) - token = print_iterator_values(&iter, &idx); - if (token != NULL) { - printf("0x%08lx: 0x%08x : Dword %d\n", - offset + 4 * idx, p[idx], idx); - handle_struct_decode(spec,token, &p[idx]); - token = NULL; - } - } + decode_group(inst, p, 1); for (i = 0; i < ARRAY_LENGTH(custom_handlers); i++) { - if (gen_group_get_opcode(inst) == - custom_handlers[i].opcode) + if (gen_group_get_opcode(inst) == custom_handlers[i].opcode) custom_handlers[i].handle(spec, p); } } if ((p[0] & 0xffff0000) == AUB_MI_BATCH_BUFFER_START) { - uint64_t start; - if (gen_spec_get_gen(spec) >= gen_make_gen(8,0)) - start = get_qword(&p[1]); - else - start = p[1]; - - parse_commands(spec, gtt + start, 1 << 20, engine); + uint64_t start = get_address(spec, &p[1]); + + if (p[0] & (1 << 22)) { + /* MI_BATCH_BUFFER_START with "2nd Level Batch Buffer" set acts + * like a subroutine call. Commands that come afterwards get + * processed once the 2nd level batch buffer returns with + * MI_BATCH_BUFFER_END. + */ + parse_commands(spec, gtt + start, gtt_end - start, engine); + } else { + /* MI_BATCH_BUFFER_START with "2nd Level Batch Buffer" unset acts + * like a goto. Nothing after it will ever get processed. In + * order to prevent the recursion from growing, we just reset the + * loop and continue; + */ + p = gtt + start; + /* We don't know where secondaries end so use the GTT end */ + end = gtt + gtt_end; + length = 0; + continue; + } } else if ((p[0] & 0xffff0000) == AUB_MI_BATCH_BUFFER_END) { break; } @@ -776,7 +762,7 @@ parse_commands(struct gen_spec *spec, uint32_t *cmds, int size, int engine) #define GEN_ENGINE_BLITTER 2 static void -handle_trace_block(struct gen_spec *spec, uint32_t *p) +handle_trace_block(uint32_t *p) { int operation = p[1] & AUB_TRACE_OPERATION_MASK; int type = p[1] & AUB_TRACE_TYPE_MASK; @@ -795,7 +781,7 @@ handle_trace_block(struct gen_spec *spec, uint32_t *p) if (address_space != AUB_TRACE_MEMTYPE_GTT) break; if (gtt_size < offset + size) { - fprintf(stderr, "overflow gtt space: %s", strerror(errno)); + fprintf(stderr, "overflow gtt space: %s\n", strerror(errno)); exit(EXIT_FAILURE); } memcpy((char *) gtt + offset, data, size); @@ -811,7 +797,7 @@ handle_trace_block(struct gen_spec *spec, uint32_t *p) engine = GEN_ENGINE_BLITTER; break; default: - printf("command write to unknown ring %d\n", type); + fprintf(outfile, "command write to unknown ring %d\n", type); break; } @@ -821,49 +807,102 @@ handle_trace_block(struct gen_spec *spec, uint32_t *p) } } +static void +handle_trace_header(uint32_t *p) +{ + /* The intel_aubdump tool from IGT is kind enough to put a PCI-ID= tag in + * the AUB header comment. If the user hasn't specified a hardware + * generation, try to use the one from the AUB file. + */ + uint32_t *end = p + (p[0] & 0xffff) + 2; + int aub_pci_id = 0; + if (end > &p[12] && p[12] > 0) + sscanf((char *)&p[13], "PCI-ID=%i", &aub_pci_id); + + if (pci_id == 0) + pci_id = aub_pci_id; + + struct gen_device_info devinfo; + if (!gen_get_device_info(pci_id, &devinfo)) { + fprintf(stderr, "can't find device information: pci_id=0x%x\n", pci_id); + exit(EXIT_FAILURE); + } + + if (xml_path == NULL) + spec = gen_spec_load(&devinfo); + else + spec = gen_spec_load_from_path(&devinfo, xml_path); + disasm = gen_disasm_create(pci_id); + + if (spec == NULL || disasm == NULL) + exit(EXIT_FAILURE); + + fprintf(outfile, "%sAubinator: Intel AUB file decoder.%-80s%s\n", + GREEN_HEADER, "", NORMAL); + + if (input_file) + fprintf(outfile, "File name: %s\n", input_file); + + if (aub_pci_id) + fprintf(outfile, "PCI ID: 0x%x\n", aub_pci_id); + + char app_name[33]; + strncpy(app_name, (char *)&p[2], 32); + app_name[32] = 0; + fprintf(outfile, "Application name: %s\n", app_name); + + fprintf(outfile, "Decoding as: %s\n", gen_get_device_name(pci_id)); + + /* Throw in a new line before the first batch */ + fprintf(outfile, "\n"); +} + struct aub_file { - char *filename; - int fd; - struct stat sb; + FILE *stream; + uint32_t *map, *end, *cursor; + uint32_t *mem_end; }; static struct aub_file * aub_file_open(const char *filename) { struct aub_file *file; + struct stat sb; + int fd; - file = malloc(sizeof *file); - file->filename = strdup(filename); - file->fd = open(file->filename, O_RDONLY); - if (file->fd == -1) { - fprintf(stderr, "open %s failed: %s", file->filename, strerror(errno)); + file = calloc(1, sizeof *file); + fd = open(filename, O_RDONLY); + if (fd == -1) { + fprintf(stderr, "open %s failed: %s\n", filename, strerror(errno)); exit(EXIT_FAILURE); } - if (fstat(file->fd, &file->sb) == -1) { - fprintf(stderr, "stat failed: %s", strerror(errno)); + if (fstat(fd, &sb) == -1) { + fprintf(stderr, "stat failed: %s\n", strerror(errno)); exit(EXIT_FAILURE); } - file->map = mmap(NULL, file->sb.st_size, - PROT_READ, MAP_SHARED, file->fd, 0); + file->map = mmap(NULL, sb.st_size, + PROT_READ, MAP_SHARED, fd, 0); if (file->map == MAP_FAILED) { - fprintf(stderr, "mmap failed: %s", strerror(errno)); + fprintf(stderr, "mmap failed: %s\n", strerror(errno)); exit(EXIT_FAILURE); } file->cursor = file->map; - file->end = file->map + file->sb.st_size / 4; + file->end = file->map + sb.st_size / 4; - /* mmap a terabyte for our gtt space. */ - gtt_size = 1ul << 40; - gtt = mmap(NULL, gtt_size, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0); - if (gtt == MAP_FAILED) { - fprintf(stderr, "failed to alloc gtt space: %s", strerror(errno)); - exit(1); - } + return file; +} + +static struct aub_file * +aub_file_stdin(void) +{ + struct aub_file *file; + + file = calloc(1, sizeof *file); + file->stream = stdin; return file; } @@ -913,11 +952,20 @@ struct { { "bxt", MAKE_GEN(9, 0) } }; -static void -aub_file_decode_batch(struct aub_file *file, struct gen_spec *spec) +enum { + AUB_ITEM_DECODE_OK, + AUB_ITEM_DECODE_FAILED, + AUB_ITEM_DECODE_NEED_MORE_DATA, +}; + +static int +aub_file_decode_batch(struct aub_file *file) { - uint32_t *p, h, device, data_type; - int header_length, payload_size, bias; + uint32_t *p, h, device, data_type, *new_cursor; + int header_length, bias; + + if (file->end - file->cursor < 1) + return AUB_ITEM_DECODE_NEED_MORE_DATA; p = file->cursor; h = *p; @@ -931,57 +979,107 @@ aub_file_decode_batch(struct aub_file *file, struct gen_spec *spec) bias = 1; break; default: - printf("unknown opcode %d at %ld/%ld\n", - OPCODE(h), file->cursor - file->map, - file->end - file->map); - file->cursor = file->end; - return; + fprintf(outfile, "unknown opcode %d at %td/%td\n", + OPCODE(h), file->cursor - file->map, + file->end - file->map); + return AUB_ITEM_DECODE_FAILED; } - payload_size = 0; + new_cursor = p + header_length + bias; + if ((h & 0xffff0000) == MAKE_HEADER(TYPE_AUB, OPCODE_AUB, SUBOPCODE_BLOCK)) { + if (file->end - file->cursor < 4) + return AUB_ITEM_DECODE_NEED_MORE_DATA; + new_cursor += p[4] / 4; + } + + if (new_cursor > file->end) + return AUB_ITEM_DECODE_NEED_MORE_DATA; + switch (h & 0xffff0000) { case MAKE_HEADER(TYPE_AUB, OPCODE_AUB, SUBOPCODE_HEADER): - payload_size = p[12]; + handle_trace_header(p); break; case MAKE_HEADER(TYPE_AUB, OPCODE_AUB, SUBOPCODE_BLOCK): - payload_size = p[4]; - handle_trace_block(spec, p); + handle_trace_block(p); break; case MAKE_HEADER(TYPE_AUB, OPCODE_AUB, SUBOPCODE_BMP): break; - case MAKE_HEADER(TYPE_AUB, OPCODE_NEW_AUB, SUBOPCODE_VERSION): - printf("version block: dw1 %08x\n", p[1]); + fprintf(outfile, "version block: dw1 %08x\n", p[1]); device = (p[1] >> 8) & 0xff; - printf(" device %s\n", device_map[device].name); + fprintf(outfile, " device %s\n", device_map[device].name); break; case MAKE_HEADER(TYPE_AUB, OPCODE_NEW_AUB, SUBOPCODE_REG_WRITE): - printf("register write block: (dwords %d)\n", h & 0xffff); - printf(" reg 0x%x, data 0x%x\n", p[1], p[5]); + fprintf(outfile, "register write block: (dwords %d)\n", h & 0xffff); + fprintf(outfile, " reg 0x%x, data 0x%x\n", p[1], p[5]); break; case MAKE_HEADER(TYPE_AUB, OPCODE_NEW_AUB, SUBOPCODE_MEM_WRITE): - printf("memory write block (dwords %d):\n", h & 0xffff); - printf(" address 0x%lx\n", *(uint64_t *) &p[1]); + fprintf(outfile, "memory write block (dwords %d):\n", h & 0xffff); + fprintf(outfile, " address 0x%"PRIx64"\n", *(uint64_t *) &p[1]); data_type = (p[3] >> 20) & 0xff; if (data_type != 0) - printf(" data type 0x%x\n", data_type); - printf(" address space 0x%x\n", (p[3] >> 28) & 0xf); + fprintf(outfile, " data type 0x%x\n", data_type); + fprintf(outfile, " address space 0x%x\n", (p[3] >> 28) & 0xf); break; case MAKE_HEADER(TYPE_AUB, OPCODE_NEW_AUB, SUBOPCODE_MEM_POLL): - printf("memory poll block (dwords %d):\n", h & 0xffff); + fprintf(outfile, "memory poll block (dwords %d):\n", h & 0xffff); break; default: - printf("unknown block type=0x%x, opcode=0x%x, " + fprintf(outfile, "unknown block type=0x%x, opcode=0x%x, " "subopcode=0x%x (%08x)\n", TYPE(h), OPCODE(h), SUBOPCODE(h), h); break; } - file->cursor = p + header_length + bias + payload_size / 4; + file->cursor = new_cursor; + + return AUB_ITEM_DECODE_OK; } static int aub_file_more_stuff(struct aub_file *file) { - return file->cursor < file->end; + return file->cursor < file->end || (file->stream && !feof(file->stream)); +} + +#define AUB_READ_BUFFER_SIZE (4096) +#define MAX(a, b) ((a) < (b) ? (b) : (a)) + +static void +aub_file_data_grow(struct aub_file *file) +{ + size_t old_size = (file->mem_end - file->map) * 4; + size_t new_size = MAX(old_size * 2, AUB_READ_BUFFER_SIZE); + uint32_t *new_start = realloc(file->map, new_size); + + file->cursor = new_start + (file->cursor - file->map); + file->end = new_start + (file->end - file->map); + file->map = new_start; + file->mem_end = file->map + (new_size / 4); +} + +static bool +aub_file_data_load(struct aub_file *file) +{ + size_t r; + + if (file->stream == NULL) + return false; + + /* First remove any consumed data */ + if (file->cursor > file->map) { + memmove(file->map, file->cursor, + (file->end - file->cursor) * 4); + file->end -= file->cursor - file->map; + file->cursor = file->map; + } + + /* Then load some new data in */ + if ((file->mem_end - file->end) < (AUB_READ_BUFFER_SIZE / 4)) + aub_file_data_grow(file); + + r = fread(file->end, 1, (file->mem_end - file->end) * 4, file->stream); + file->end += r / 4; + + return r != 0; } static void @@ -1003,7 +1101,7 @@ setup_pager(void) if (pid == 0) { close(fds[1]); dup2(fds[0], 0); - execlp("less", "less", "-rFi", NULL); + execlp("less", "less", "-FRSi", NULL); } close(fds[0]); @@ -1012,17 +1110,11 @@ setup_pager(void) } static void -print_help(FILE *file) +print_help(const char *progname, FILE *file) { - const char *progname; -#if defined(__GLIBC__) || defined(__CYGWIN__) - progname = program_invocation_short_name; -#else - progname = getprogname(); -#endif fprintf(file, - "Usage: %s [OPTION]... FILE\n" - "Decode aub file contents.\n\n" + "Usage: %s [OPTION]... [FILE]\n" + "Decode aub file contents from either FILE or the standard input.\n\n" "A valid --gen option must be provided.\n\n" " --help display this help and exit\n" " --gen=platform decode for given platform (ivb, byt, hsw, bdw, chv, skl, kbl or bxt)\n" @@ -1030,131 +1122,85 @@ print_help(FILE *file) " --color[=WHEN] colorize the output; WHEN can be 'auto' (default\n" " if omitted), 'always', or 'never'\n" " --no-pager don't launch pager\n" - " --no-offsets don't print instruction offsets\n", - basename(progname)); -} - -static bool -is_prefix(const char *arg, const char *prefix, const char **value) -{ - int l = strlen(prefix); - - if (strncmp(arg, prefix, l) == 0 && (arg[l] == '\0' || arg[l] == '=')) { - if (arg[l] == '=') - *value = arg + l + 1; - else - *value = NULL; - - return true; - } - - return false; + " --no-offsets don't print instruction offsets\n" + " --xml=DIR load hardware xml description from directory DIR\n", + progname); } int main(int argc, char *argv[]) { - struct gen_spec *spec; struct aub_file *file; - int i, pci_id = 0; - bool found_arg_gen = false, pager = true; - int gen_major, gen_minor; - const char *value; - char gen_file[256], gen_val[24]; - - if (argc == 1) { - print_help(stderr); - exit(EXIT_FAILURE); - } - - for (i = 1; i < argc; ++i) { - if (strcmp(argv[i], "--no-pager") == 0) { - pager = false; - } else if (strcmp(argv[i], "--no-offsets") == 0) { - option_print_offsets = false; - } else if (is_prefix(argv[i], "--gen", &value)) { - if (value == NULL) { - fprintf(stderr, "option '--gen' requires an argument\n"); + int c, i; + bool help = false, pager = true; + const struct { + const char *name; + int pci_id; + } gens[] = { + { "ivb", 0x0166 }, /* Intel(R) Ivybridge Mobile GT2 */ + { "hsw", 0x0416 }, /* Intel(R) Haswell Mobile GT2 */ + { "byt", 0x0155 }, /* Intel(R) Bay Trail */ + { "bdw", 0x1616 }, /* Intel(R) HD Graphics 5500 (Broadwell GT2) */ + { "chv", 0x22B3 }, /* Intel(R) HD Graphics (Cherryview) */ + { "skl", 0x1912 }, /* Intel(R) HD Graphics 530 (Skylake GT2) */ + { "kbl", 0x591D }, /* Intel(R) Kabylake GT2 */ + { "bxt", 0x0A84 } /* Intel(R) HD Graphics (Broxton) */ + }; + const struct option aubinator_opts[] = { + { "help", no_argument, (int *) &help, true }, + { "no-pager", no_argument, (int *) &pager, false }, + { "no-offsets", no_argument, (int *) &option_print_offsets, false }, + { "gen", required_argument, NULL, 'g' }, + { "headers", no_argument, (int *) &option_full_decode, false }, + { "color", required_argument, NULL, 'c' }, + { "xml", required_argument, NULL, 'x' }, + { NULL, 0, NULL, 0 } + }; + + outfile = stdout; + + i = 0; + while ((c = getopt_long(argc, argv, "", aubinator_opts, &i)) != -1) { + switch (c) { + case 'g': + for (i = 0; i < ARRAY_SIZE(gens); i++) { + if (!strcmp(optarg, gens[i].name)) { + pci_id = gens[i].pci_id; + break; + } + } + if (i == ARRAY_SIZE(gens)) { + fprintf(stderr, "can't parse gen: '%s', expected ivb, byt, hsw, " + "bdw, chv, skl, kbl or bxt\n", optarg); exit(EXIT_FAILURE); } - found_arg_gen = true; - gen_major = 0; - gen_minor = 0; - snprintf(gen_val, sizeof(gen_val), "%s", value); - } else if (strcmp(argv[i], "--headers") == 0) { - option_full_decode = false; - } else if (is_prefix(argv[i], "--color", &value)) { - if (value == NULL || strcmp(value, "always") == 0) + break; + case 'c': + if (optarg == NULL || strcmp(optarg, "always") == 0) option_color = COLOR_ALWAYS; - else if (strcmp(value, "never") == 0) + else if (strcmp(optarg, "never") == 0) option_color = COLOR_NEVER; - else if (strcmp(value, "auto") == 0) + else if (strcmp(optarg, "auto") == 0) option_color = COLOR_AUTO; else { - fprintf(stderr, "invalid value for --color: %s", value); - exit(EXIT_FAILURE); - } - } else if (strcmp(argv[i], "--help") == 0) { - print_help(stdout); - exit(EXIT_SUCCESS); - } else { - if (argv[i][0] == '-') { - fprintf(stderr, "unknown option %s\n", argv[i]); + fprintf(stderr, "invalid value for --color: %s", optarg); exit(EXIT_FAILURE); } break; + case 'x': + xml_path = strdup(optarg); + break; + default: + break; } } - if (!found_arg_gen) { - fprintf(stderr, "argument --gen is required\n"); - exit(EXIT_FAILURE); + if (help || argc == 1) { + print_help(argv[0], stderr); + exit(0); } - if (strstr(gen_val, "ivb") != NULL) { - /* Intel(R) Ivybridge Mobile GT2 */ - pci_id = 0x0166; - gen_major = 7; - gen_minor = 0; - } else if (strstr(gen_val, "hsw") != NULL) { - /* Intel(R) Haswell Mobile GT2 */ - pci_id = 0x0416; - gen_major = 7; - gen_minor = 5; - } else if (strstr(gen_val, "byt") != NULL) { - /* Intel(R) Bay Trail */ - pci_id = 0x0155; - gen_major = 7; - gen_minor = 5; - } else if (strstr(gen_val, "bdw") != NULL) { - /* Intel(R) HD Graphics 5500 (Broadwell GT2) */ - pci_id = 0x1616; - gen_major = 8; - gen_minor = 0; - } else if (strstr(gen_val, "chv") != NULL) { - /* Intel(R) HD Graphics (Cherryview) */ - pci_id = 0x22B3; - gen_major = 8; - gen_minor = 0; - } else if (strstr(gen_val, "skl") != NULL) { - /* Intel(R) HD Graphics 530 (Skylake GT2) */ - pci_id = 0x1912; - gen_major = 9; - gen_minor = 0; - } else if (strstr(gen_val, "kbl") != NULL) { - /* Intel(R) Kabylake GT2 */ - pci_id = 0x591D; - gen_major = 9; - gen_minor = 0; - } else if (strstr(gen_val, "bxt") != NULL) { - /* Intel(R) HD Graphics (Broxton) */ - pci_id = 0x0A84; - gen_major = 9; - gen_minor = 0; - } else { - fprintf(stderr, "can't parse gen: %s, expected ivb, byt, hsw, " - "bdw, chv, skl, kbl or bxt\n", gen_val); - exit(EXIT_FAILURE); - } + if (optind < argc) + input_file = argv[optind]; /* Do this before we redirect stdout to pager. */ if (option_color == COLOR_AUTO) @@ -1163,29 +1209,45 @@ int main(int argc, char *argv[]) if (isatty(1) && pager) setup_pager(); - if (gen_minor > 0) { - snprintf(gen_file, sizeof(gen_file), "../genxml/gen%d%d.xml", - gen_major, gen_minor); - } else { - snprintf(gen_file, sizeof(gen_file), "../genxml/gen%d.xml", gen_major); - } + if (input_file == NULL) + file = aub_file_stdin(); + else + file = aub_file_open(input_file); - spec = gen_spec_load(gen_file); - disasm = gen_disasm_create(pci_id); + /* mmap a terabyte for our gtt space. */ + gtt_size = 1ull << 40; + gtt = mmap(NULL, gtt_size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0); + if (gtt == MAP_FAILED) { + fprintf(stderr, "failed to alloc gtt space: %s\n", strerror(errno)); + exit(EXIT_FAILURE); + } - if (argv[i] == NULL) { - print_help(stderr); - exit(EXIT_FAILURE); - } else { - file = aub_file_open(argv[i]); + while (aub_file_more_stuff(file)) { + switch (aub_file_decode_batch(file)) { + case AUB_ITEM_DECODE_OK: + break; + case AUB_ITEM_DECODE_NEED_MORE_DATA: + if (!file->stream) { + file->cursor = file->end; + break; + } + if (aub_file_more_stuff(file) && !aub_file_data_load(file)) { + fprintf(stderr, "failed to load data from stdin\n"); + exit(EXIT_FAILURE); + } + break; + default: + fprintf(stderr, "failed to parse aubdump data\n"); + exit(EXIT_FAILURE); + } } - while (aub_file_more_stuff(file)) - aub_file_decode_batch(file, spec); fflush(stdout); /* close the stdout which is opened to write the output */ close(1); + free(xml_path); wait(NULL);