#include "util/macros.h"
-#include "decoder.h"
+#include "common/gen_decoder.h"
#include "intel_aub.h"
#include "gen_disasm.h"
#define AUB_MI_BATCH_BUFFER_END (0x0500 << 16)
#define CSI "\e["
-#define HEADER CSI "37;44m"
-#define NORMAL CSI "0m"
+#define BLUE_HEADER CSI "0;44m"
+#define GREEN_HEADER CSI "1;42m"
+#define NORMAL CSI "0m"
/* options */
/* 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;
uint64_t instruction_base;
uint64_t instruction_bound;
+FILE *outfile;
+
static inline uint32_t
field(uint32_t value, int start, int end)
{
}
static void
-print_dword_val(struct gen_field_iterator *iter, uint64_t offset,
- int *dword_num)
-{
- struct gen_field *f;
-
- f = iter->group->fields[iter->i - 1];
- const int dword = f->start / 32;
-
- if (*dword_num != dword) {
- printf("0x%08"PRIx64": 0x%08x : Dword %d\n",
- offset + 4 * dword, iter->p[dword], dword);
- *dword_num = dword;
- }
-}
-
-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:<struct %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;
- }
- }
-}
+ uint64_t offset = option_print_offsets ? (void *) p - gtt : 0;
-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);
+ gen_print_group(outfile, strct, offset, p, option_color == COLOR_ALWAYS);
}
static void
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;
}
continue;
start = pointers[i] + surface_state_base;
if (!valid_offset(start)) {
- printf("pointer %u: %08x <not valid>\n",
- i, pointers[i]);
+ fprintf(outfile, "pointer %u: %08x <not valid>\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);
}
}
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]);
}
}
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);
}
}
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: %08"PRIx64" <not valid>\n", start);
+ fprintf(outfile, "kernel: %08"PRIx64" <not valid>\n", start);
continue;
} else {
- printf("kernel: %08"PRIx64"\n", start);
+ fprintf(outfile, "kernel: %08"PRIx64"\n", start);
}
insns = (struct brw_instruction *) (gtt + start);
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");
}
}
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 %08"PRIx64", start %08"PRIx64"\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, stdout);
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 %08"PRIx64", start %08"PRIx64"\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, stdout);
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");
}
}
}
}
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, 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, 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, stdout);
dump_samplers(spec, p[1]);
}
+static void
+handle_3dstate_sampler_state_pointers_gen6(struct gen_spec *spec, uint32_t *p)
+{
+ dump_samplers(spec, p[1]);
+ dump_samplers(spec, p[2]);
+ dump_samplers(spec, p[3]);
+}
+
static void
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);
}
}
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);
}
}
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
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
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
struct gen_group *reg = gen_spec_find_register(spec, p[1]);
if (reg != NULL) {
- printf("register %s (0x%x): 0x%x\n",
- reg->name, reg->register_offset, p[2]);
- decode_structure(spec, reg, &p[2]);
+ fprintf(outfile, "register %s (0x%x): 0x%x\n",
+ reg->name, reg->register_offset, p[2]);
+ decode_group(reg, &p[2], 0);
}
}
#define _3DSTATE_SAMPLER_STATE_POINTERS_GS 0x782e0000
#define _3DSTATE_SAMPLER_STATE_POINTERS_PS 0x782f0000
+#define _3DSTATE_SAMPLER_STATE_POINTERS 0x78020000
+
#define _3DSTATE_VIEWPORT_STATE_POINTERS_CC 0x78230000
#define _3DSTATE_VIEWPORT_STATE_POINTERS_SF_CLIP 0x78210000
#define _3DSTATE_BLEND_STATE_POINTERS 0x78240000
{ _3DSTATE_SAMPLER_STATE_POINTERS_VS, handle_3dstate_sampler_state_pointers },
{ _3DSTATE_SAMPLER_STATE_POINTERS_GS, handle_3dstate_sampler_state_pointers },
{ _3DSTATE_SAMPLER_STATE_POINTERS_PS, handle_3dstate_sampler_state_pointers },
+ { _3DSTATE_SAMPLER_STATE_POINTERS, handle_3dstate_sampler_state_pointers_gen6 },
{ _3DSTATE_VIEWPORT_STATE_POINTERS_CC, handle_3dstate_viewport_state_pointers_cc },
{ _3DSTATE_VIEWPORT_STATE_POINTERS_SF_CLIP, handle_3dstate_viewport_state_pointers_sf_clip },
parse_commands(struct gen_spec *spec, uint32_t *cmds, int size, int engine)
{
uint32_t *p, *end = cmds + size / 4;
- unsigned int length, i;
+ int length, i;
struct gen_group *inst;
for (p = cmds; p < end; p += length) {
inst = gen_spec_find_instruction(spec, p);
+ length = gen_group_get_length(inst, p);
+ assert(inst == NULL || length > 0);
+ length = MAX2(1, length);
if (inst == NULL) {
- printf("unknown instruction %08x\n", p[0]);
- length = (p[0] & 0xff) + 2;
+ fprintf(outfile, "unknown instruction %08x\n", p[0]);
continue;
}
- length = gen_group_get_length(inst, p);
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) {
else
offset = 0;
- printf("%s0x%08"PRIx64": 0x%08x: %-80s%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%08"PRIx64": 0x%08x : Dword %d\n",
- offset + 4 * idx, p[idx], idx);
- handle_struct_decode(spec,token, &p[idx]);
- token = NULL;
- }
- }
+ decode_group(inst, p, 0);
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);
+ break;
+ }
}
}
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;
}
#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;
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;
}
}
}
+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\n", 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) {
+ 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\n", strerror(errno));
exit(EXIT_FAILURE);
}
+ close(fd);
+
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\n", 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;
}
{ "bdw", MAKE_GEN(8, 0) },
{ "skl", MAKE_GEN(9, 0) },
{ "chv", MAKE_GEN(8, 0) },
- { "bxt", MAKE_GEN(9, 0) }
+ { "bxt", MAKE_GEN(9, 0) },
+ { "cnl", MAKE_GEN(10, 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;
bias = 1;
break;
default:
- printf("unknown opcode %d at %td/%td\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%"PRIx64"\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
print_help(const char *progname, FILE *file)
{
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"
+ " --gen=platform decode for given platform (ivb, byt, hsw, bdw, chv, skl, kbl, bxt or cnl)\n"
" --headers decode only command headers\n"
" --color[=WHEN] colorize the output; WHEN can be 'auto' (default\n"
" if omitted), 'always', or 'never'\n"
int main(int argc, char *argv[])
{
- struct gen_spec *spec;
struct aub_file *file;
int c, i;
bool help = false, pager = true;
- char *input_file = NULL, *xml_path = NULL;
- char gen_val[24];
const struct {
const char *name;
int pci_id;
} gens[] = {
+ { "ilk", 0x0046 }, /* Intel(R) Ironlake Mobile */
+ { "snb", 0x0126 }, /* Intel(R) Sandybridge Mobile GT2 */
{ "ivb", 0x0166 }, /* Intel(R) Ivybridge Mobile GT2 */
{ "hsw", 0x0416 }, /* Intel(R) Haswell Mobile GT2 */
{ "byt", 0x0155 }, /* Intel(R) Bay Trail */
{ "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) */
- }, *gen = NULL;
+ { "bxt", 0x0A84 }, /* Intel(R) HD Graphics (Broxton) */
+ { "cnl", 0x5A52 }, /* Intel(R) HD Graphics (Cannonlake) */
+ };
const struct option aubinator_opts[] = {
{ "help", no_argument, (int *) &help, true },
{ "no-pager", no_argument, (int *) &pager, false },
{ "xml", required_argument, NULL, 'x' },
{ NULL, 0, NULL, 0 }
};
- struct gen_device_info devinfo;
+
+ outfile = stdout;
i = 0;
while ((c = getopt_long(argc, argv, "", aubinator_opts, &i)) != -1) {
switch (c) {
case 'g':
- snprintf(gen_val, sizeof(gen_val), "%s", optarg);
+ 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);
+ }
break;
case 'c':
if (optarg == NULL || strcmp(optarg, "always") == 0)
if (optind < argc)
input_file = argv[optind];
- for (i = 0; i < ARRAY_SIZE(gens); i++) {
- if (!strcmp(gen_val, gens[i].name)) {
- gen = &gens[i];
- break;
- }
- }
-
- if (gen == NULL) {
- fprintf(stderr, "can't parse gen: %s, expected ivb, byt, hsw, "
- "bdw, chv, skl, kbl or bxt\n", gen_val);
- exit(EXIT_FAILURE);
- }
-
- if (!gen_get_device_info(gen->pci_id, &devinfo)) {
- fprintf(stderr, "can't find device information: pci_id=0x%x name=%s\n",
- gen->pci_id, gen->name);
- exit(EXIT_FAILURE);
- }
-
-
/* Do this before we redirect stdout to pager. */
if (option_color == COLOR_AUTO)
option_color = isatty(1) ? COLOR_ALWAYS : COLOR_NEVER;
if (isatty(1) && pager)
setup_pager();
- if (xml_path == NULL)
- spec = gen_spec_load(&devinfo);
+ if (input_file == NULL)
+ file = aub_file_stdin();
else
- spec = gen_spec_load_from_path(&devinfo, xml_path);
- disasm = gen_disasm_create(gen->pci_id);
+ file = aub_file_open(input_file);
- if (spec == NULL || disasm == NULL)
+ /* 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 (input_file == NULL) {
- print_help(input_file, stderr);
- exit(EXIT_FAILURE);
- } else {
- file = aub_file_open(input_file);
+ 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 */