2 * Copyright © 2016 Intel Corporation
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:
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
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
35 #include <sys/types.h>
40 #include "util/macros.h"
42 #include "common/gen_decoder.h"
43 #include "intel_aub.h"
44 #include "gen_disasm.h"
46 /* Below is the only command missing from intel_aub.h in libdrm
47 * So, reuse intel_aub.h from libdrm and #define the
48 * AUB_MI_BATCH_BUFFER_END as below
50 #define AUB_MI_BATCH_BUFFER_END (0x0500 << 16)
53 #define BLUE_HEADER CSI "0;44m"
54 #define GREEN_HEADER CSI "1;42m"
55 #define NORMAL CSI "0m"
59 static bool option_full_decode
= true;
60 static bool option_print_offsets
= true;
61 static enum { COLOR_AUTO
, COLOR_ALWAYS
, COLOR_NEVER
} option_color
;
66 char *input_file
= NULL
, *xml_path
= NULL
;
67 struct gen_device_info devinfo
;
68 struct gen_batch_decode_ctx batch_ctx
;
70 uint64_t gtt_size
, gtt_end
;
72 uint64_t general_state_base
;
73 uint64_t surface_state_base
;
74 uint64_t dynamic_state_base
;
75 uint64_t instruction_base
;
76 uint64_t instruction_bound
;
80 static inline uint32_t
81 field(uint32_t value
, int start
, int end
)
85 mask
= ~0U >> (31 - end
+ start
);
87 return (value
>> start
) & mask
;
90 struct brw_instruction
;
93 valid_offset(uint32_t offset
)
95 return offset
< gtt_end
;
98 #define GEN_ENGINE_RENDER 1
99 #define GEN_ENGINE_BLITTER 2
102 handle_trace_block(uint32_t *p
)
104 int operation
= p
[1] & AUB_TRACE_OPERATION_MASK
;
105 int type
= p
[1] & AUB_TRACE_TYPE_MASK
;
106 int address_space
= p
[1] & AUB_TRACE_ADDRESS_SPACE_MASK
;
107 uint64_t offset
= p
[3];
108 uint32_t size
= p
[4];
109 int header_length
= p
[0] & 0xffff;
110 uint32_t *data
= p
+ header_length
+ 2;
111 int engine
= GEN_ENGINE_RENDER
;
113 if (devinfo
.gen
>= 8)
114 offset
+= (uint64_t) p
[5] << 32;
117 case AUB_TRACE_OP_DATA_WRITE
:
118 if (address_space
!= AUB_TRACE_MEMTYPE_GTT
)
120 if (gtt_size
< offset
+ size
) {
121 fprintf(stderr
, "overflow gtt space: %s\n", strerror(errno
));
124 memcpy((char *) gtt
+ offset
, data
, size
);
125 if (gtt_end
< offset
+ size
)
126 gtt_end
= offset
+ size
;
128 case AUB_TRACE_OP_COMMAND_WRITE
:
130 case AUB_TRACE_TYPE_RING_PRB0
:
131 engine
= GEN_ENGINE_RENDER
;
133 case AUB_TRACE_TYPE_RING_PRB2
:
134 engine
= GEN_ENGINE_BLITTER
;
137 fprintf(outfile
, "command write to unknown ring %d\n", type
);
141 (void)engine
; /* TODO */
142 gen_print_batch(&batch_ctx
, data
, size
, 0);
149 static struct gen_batch_decode_bo
150 get_gen_batch_bo(void *user_data
, uint64_t address
)
152 if (address
> gtt_end
)
153 return (struct gen_batch_decode_bo
) { .map
= NULL
};
155 /* We really only have one giant address range */
156 return (struct gen_batch_decode_bo
) {
164 aubinator_init(uint16_t aub_pci_id
, const char *app_name
)
166 if (!gen_get_device_info(pci_id
, &devinfo
)) {
167 fprintf(stderr
, "can't find device information: pci_id=0x%x\n", pci_id
);
171 enum gen_batch_decode_flags batch_flags
= 0;
172 if (option_color
== COLOR_ALWAYS
)
173 batch_flags
|= GEN_BATCH_DECODE_IN_COLOR
;
174 if (option_full_decode
)
175 batch_flags
|= GEN_BATCH_DECODE_FULL
;
176 if (option_print_offsets
)
177 batch_flags
|= GEN_BATCH_DECODE_OFFSETS
;
178 batch_flags
|= GEN_BATCH_DECODE_FLOATS
;
180 gen_batch_decode_ctx_init(&batch_ctx
, &devinfo
, outfile
, batch_flags
,
181 xml_path
, get_gen_batch_bo
, NULL
);
183 char *color
= GREEN_HEADER
, *reset_color
= NORMAL
;
184 if (option_color
== COLOR_NEVER
)
185 color
= reset_color
= "";
187 fprintf(outfile
, "%sAubinator: Intel AUB file decoder.%-80s%s\n",
188 color
, "", reset_color
);
191 fprintf(outfile
, "File name: %s\n", input_file
);
194 fprintf(outfile
, "PCI ID: 0x%x\n", aub_pci_id
);
196 fprintf(outfile
, "Application name: %s\n", app_name
);
198 fprintf(outfile
, "Decoding as: %s\n", gen_get_device_name(pci_id
));
200 /* Throw in a new line before the first batch */
201 fprintf(outfile
, "\n");
205 handle_trace_header(uint32_t *p
)
207 /* The intel_aubdump tool from IGT is kind enough to put a PCI-ID= tag in
208 * the AUB header comment. If the user hasn't specified a hardware
209 * generation, try to use the one from the AUB file.
211 uint32_t *end
= p
+ (p
[0] & 0xffff) + 2;
213 if (end
> &p
[12] && p
[12] > 0)
214 sscanf((char *)&p
[13], "PCI-ID=%i", &aub_pci_id
);
220 strncpy(app_name
, (char *)&p
[2], 32);
223 aubinator_init(aub_pci_id
, app_name
);
227 handle_memtrace_version(uint32_t *p
)
229 int header_length
= p
[0] & 0xffff;
231 int app_name_len
= MIN2(4 * (header_length
+ 1 - 5), ARRAY_SIZE(app_name
) - 1);
235 strncpy(app_name
, (char *)&p
[5], app_name_len
);
236 app_name
[app_name_len
] = 0;
237 sscanf(app_name
, "PCI-ID=%i %n", &aub_pci_id
, &pci_id_len
);
240 aubinator_init(aub_pci_id
, app_name
+ pci_id_len
);
244 handle_memtrace_reg_write(uint32_t *p
)
246 uint32_t offset
= p
[1];
247 uint32_t value
= p
[5];
249 static int render_elsp_writes
= 0;
250 static int blitter_elsp_writes
= 0;
251 static int render_elsq0
= 0;
252 static int blitter_elsq0
= 0;
255 if (offset
== 0x2230) {
256 render_elsp_writes
++;
257 engine
= GEN_ENGINE_RENDER
;
258 } else if (offset
== 0x22230) {
259 blitter_elsp_writes
++;
260 engine
= GEN_ENGINE_BLITTER
;
261 } else if (offset
== 0x2510) {
262 render_elsq0
= value
;
263 } else if (offset
== 0x22510) {
264 blitter_elsq0
= value
;
265 } else if (offset
== 0x2550 || offset
== 0x22550) {
271 if (render_elsp_writes
> 3 || blitter_elsp_writes
> 3) {
272 render_elsp_writes
= blitter_elsp_writes
= 0;
273 pphwsp
= (uint8_t*)gtt
+ (value
& 0xfffff000);
274 } else if (offset
== 0x2550) {
275 engine
= GEN_ENGINE_RENDER
;
276 pphwsp
= (uint8_t*)gtt
+ (render_elsq0
& 0xfffff000);
277 } else if (offset
== 0x22550) {
278 engine
= GEN_ENGINE_BLITTER
;
279 pphwsp
= (uint8_t*)gtt
+ (blitter_elsq0
& 0xfffff000);
284 const uint32_t pphwsp_size
= 4096;
285 uint32_t *context
= (uint32_t*)(pphwsp
+ pphwsp_size
);
286 uint32_t ring_buffer_head
= context
[5];
287 uint32_t ring_buffer_tail
= context
[7];
288 uint32_t ring_buffer_start
= context
[9];
289 uint32_t *commands
= (uint32_t*)((uint8_t*)gtt
+ ring_buffer_start
+ ring_buffer_head
);
290 (void)engine
; /* TODO */
291 gen_print_batch(&batch_ctx
, commands
, ring_buffer_tail
- ring_buffer_head
, 0);
295 handle_memtrace_mem_write(uint32_t *p
)
297 uint64_t address
= *(uint64_t*)&p
[1];
298 uint32_t address_space
= p
[3] >> 28;
299 uint32_t size
= p
[4];
300 uint32_t *data
= p
+ 5;
302 if (address_space
!= 1)
305 if (gtt_size
< address
+ size
) {
306 fprintf(stderr
, "overflow gtt space: %s\n", strerror(errno
));
310 memcpy((char *) gtt
+ address
, data
, size
);
311 if (gtt_end
< address
+ size
)
312 gtt_end
= address
+ size
;
318 uint32_t *map
, *end
, *cursor
;
322 static struct aub_file
*
323 aub_file_open(const char *filename
)
325 struct aub_file
*file
;
329 file
= calloc(1, sizeof *file
);
330 fd
= open(filename
, O_RDONLY
);
332 fprintf(stderr
, "open %s failed: %s\n", filename
, strerror(errno
));
336 if (fstat(fd
, &sb
) == -1) {
337 fprintf(stderr
, "stat failed: %s\n", strerror(errno
));
341 file
->map
= mmap(NULL
, sb
.st_size
,
342 PROT_READ
, MAP_SHARED
, fd
, 0);
343 if (file
->map
== MAP_FAILED
) {
344 fprintf(stderr
, "mmap failed: %s\n", strerror(errno
));
350 file
->cursor
= file
->map
;
351 file
->end
= file
->map
+ sb
.st_size
/ 4;
356 static struct aub_file
*
359 struct aub_file
*file
;
361 file
= calloc(1, sizeof *file
);
362 file
->stream
= stdin
;
367 #define TYPE(dw) (((dw) >> 29) & 7)
368 #define OPCODE(dw) (((dw) >> 23) & 0x3f)
369 #define SUBOPCODE(dw) (((dw) >> 16) & 0x7f)
371 #define MAKE_HEADER(type, opcode, subopcode) \
372 (((type) << 29) | ((opcode) << 23) | ((subopcode) << 16))
376 /* Classic AUB opcodes */
377 #define OPCODE_AUB 0x01
378 #define SUBOPCODE_HEADER 0x05
379 #define SUBOPCODE_BLOCK 0x41
380 #define SUBOPCODE_BMP 0x1e
382 /* Newer version AUB opcode */
383 #define OPCODE_NEW_AUB 0x2e
384 #define SUBOPCODE_REG_POLL 0x02
385 #define SUBOPCODE_REG_WRITE 0x03
386 #define SUBOPCODE_MEM_POLL 0x05
387 #define SUBOPCODE_MEM_WRITE 0x06
388 #define SUBOPCODE_VERSION 0x0e
390 #define MAKE_GEN(major, minor) ( ((major) << 8) | (minor) )
394 AUB_ITEM_DECODE_FAILED
,
395 AUB_ITEM_DECODE_NEED_MORE_DATA
,
399 aub_file_decode_batch(struct aub_file
*file
)
401 uint32_t *p
, h
, *new_cursor
;
402 int header_length
, bias
;
404 if (file
->end
- file
->cursor
< 1)
405 return AUB_ITEM_DECODE_NEED_MORE_DATA
;
409 header_length
= h
& 0xffff;
419 fprintf(outfile
, "unknown opcode %d at %td/%td\n",
420 OPCODE(h
), file
->cursor
- file
->map
,
421 file
->end
- file
->map
);
422 return AUB_ITEM_DECODE_FAILED
;
425 new_cursor
= p
+ header_length
+ bias
;
426 if ((h
& 0xffff0000) == MAKE_HEADER(TYPE_AUB
, OPCODE_AUB
, SUBOPCODE_BLOCK
)) {
427 if (file
->end
- file
->cursor
< 4)
428 return AUB_ITEM_DECODE_NEED_MORE_DATA
;
429 new_cursor
+= p
[4] / 4;
432 if (new_cursor
> file
->end
)
433 return AUB_ITEM_DECODE_NEED_MORE_DATA
;
435 switch (h
& 0xffff0000) {
436 case MAKE_HEADER(TYPE_AUB
, OPCODE_AUB
, SUBOPCODE_HEADER
):
437 handle_trace_header(p
);
439 case MAKE_HEADER(TYPE_AUB
, OPCODE_AUB
, SUBOPCODE_BLOCK
):
440 handle_trace_block(p
);
442 case MAKE_HEADER(TYPE_AUB
, OPCODE_AUB
, SUBOPCODE_BMP
):
444 case MAKE_HEADER(TYPE_AUB
, OPCODE_NEW_AUB
, SUBOPCODE_VERSION
):
445 handle_memtrace_version(p
);
447 case MAKE_HEADER(TYPE_AUB
, OPCODE_NEW_AUB
, SUBOPCODE_REG_WRITE
):
448 handle_memtrace_reg_write(p
);
450 case MAKE_HEADER(TYPE_AUB
, OPCODE_NEW_AUB
, SUBOPCODE_MEM_WRITE
):
451 handle_memtrace_mem_write(p
);
453 case MAKE_HEADER(TYPE_AUB
, OPCODE_NEW_AUB
, SUBOPCODE_MEM_POLL
):
454 fprintf(outfile
, "memory poll block (dwords %d):\n", h
& 0xffff);
456 case MAKE_HEADER(TYPE_AUB
, OPCODE_NEW_AUB
, SUBOPCODE_REG_POLL
):
459 fprintf(outfile
, "unknown block type=0x%x, opcode=0x%x, "
460 "subopcode=0x%x (%08x)\n", TYPE(h
), OPCODE(h
), SUBOPCODE(h
), h
);
463 file
->cursor
= new_cursor
;
465 return AUB_ITEM_DECODE_OK
;
469 aub_file_more_stuff(struct aub_file
*file
)
471 return file
->cursor
< file
->end
|| (file
->stream
&& !feof(file
->stream
));
474 #define AUB_READ_BUFFER_SIZE (4096)
475 #define MAX(a, b) ((a) < (b) ? (b) : (a))
478 aub_file_data_grow(struct aub_file
*file
)
480 size_t old_size
= (file
->mem_end
- file
->map
) * 4;
481 size_t new_size
= MAX(old_size
* 2, AUB_READ_BUFFER_SIZE
);
482 uint32_t *new_start
= realloc(file
->map
, new_size
);
484 file
->cursor
= new_start
+ (file
->cursor
- file
->map
);
485 file
->end
= new_start
+ (file
->end
- file
->map
);
486 file
->map
= new_start
;
487 file
->mem_end
= file
->map
+ (new_size
/ 4);
491 aub_file_data_load(struct aub_file
*file
)
495 if (file
->stream
== NULL
)
498 /* First remove any consumed data */
499 if (file
->cursor
> file
->map
) {
500 memmove(file
->map
, file
->cursor
,
501 (file
->end
- file
->cursor
) * 4);
502 file
->end
-= file
->cursor
- file
->map
;
503 file
->cursor
= file
->map
;
506 /* Then load some new data in */
507 if ((file
->mem_end
- file
->end
) < (AUB_READ_BUFFER_SIZE
/ 4))
508 aub_file_data_grow(file
);
510 r
= fread(file
->end
, 1, (file
->mem_end
- file
->end
) * 4, file
->stream
);
535 execlp("less", "less", "-FRSi", NULL
);
544 print_help(const char *progname
, FILE *file
)
547 "Usage: %s [OPTION]... [FILE]\n"
548 "Decode aub file contents from either FILE or the standard input.\n\n"
549 "A valid --gen option must be provided.\n\n"
550 " --help display this help and exit\n"
551 " --gen=platform decode for given platform (3 letter platform name)\n"
552 " --headers decode only command headers\n"
553 " --color[=WHEN] colorize the output; WHEN can be 'auto' (default\n"
554 " if omitted), 'always', or 'never'\n"
555 " --no-pager don't launch pager\n"
556 " --no-offsets don't print instruction offsets\n"
557 " --xml=DIR load hardware xml description from directory DIR\n",
561 int main(int argc
, char *argv
[])
563 struct aub_file
*file
;
565 bool help
= false, pager
= true;
566 const struct option aubinator_opts
[] = {
567 { "help", no_argument
, (int *) &help
, true },
568 { "no-pager", no_argument
, (int *) &pager
, false },
569 { "no-offsets", no_argument
, (int *) &option_print_offsets
, false },
570 { "gen", required_argument
, NULL
, 'g' },
571 { "headers", no_argument
, (int *) &option_full_decode
, false },
572 { "color", required_argument
, NULL
, 'c' },
573 { "xml", required_argument
, NULL
, 'x' },
580 while ((c
= getopt_long(argc
, argv
, "", aubinator_opts
, &i
)) != -1) {
583 const int id
= gen_device_name_to_pci_device_id(optarg
);
585 fprintf(stderr
, "can't parse gen: '%s', expected ivb, byt, hsw, "
586 "bdw, chv, skl, kbl or bxt\n", optarg
);
594 if (optarg
== NULL
|| strcmp(optarg
, "always") == 0)
595 option_color
= COLOR_ALWAYS
;
596 else if (strcmp(optarg
, "never") == 0)
597 option_color
= COLOR_NEVER
;
598 else if (strcmp(optarg
, "auto") == 0)
599 option_color
= COLOR_AUTO
;
601 fprintf(stderr
, "invalid value for --color: %s", optarg
);
606 xml_path
= strdup(optarg
);
613 if (help
|| argc
== 1) {
614 print_help(argv
[0], stderr
);
619 input_file
= argv
[optind
];
621 /* Do this before we redirect stdout to pager. */
622 if (option_color
== COLOR_AUTO
)
623 option_color
= isatty(1) ? COLOR_ALWAYS
: COLOR_NEVER
;
625 if (isatty(1) && pager
)
628 if (input_file
== NULL
)
629 file
= aub_file_stdin();
631 file
= aub_file_open(input_file
);
633 /* mmap a terabyte for our gtt space. */
634 gtt_size
= 1ull << 40;
635 gtt
= mmap(NULL
, gtt_size
, PROT_READ
| PROT_WRITE
,
636 MAP_PRIVATE
| MAP_ANONYMOUS
| MAP_NORESERVE
, -1, 0);
637 if (gtt
== MAP_FAILED
) {
638 fprintf(stderr
, "failed to alloc gtt space: %s\n", strerror(errno
));
642 while (aub_file_more_stuff(file
)) {
643 switch (aub_file_decode_batch(file
)) {
644 case AUB_ITEM_DECODE_OK
:
646 case AUB_ITEM_DECODE_NEED_MORE_DATA
:
648 file
->cursor
= file
->end
;
651 if (aub_file_more_stuff(file
) && !aub_file_data_load(file
)) {
652 fprintf(stderr
, "failed to load data from stdin\n");
657 fprintf(stderr
, "failed to parse aubdump data\n");
664 /* close the stdout which is opened to write the output */