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
36 #include <sys/types.h>
41 #include "util/list.h"
42 #include "util/macros.h"
43 #include "util/rb_tree.h"
45 #include "common/gen_decoder.h"
46 #include "common/gen_disasm.h"
47 #include "common/gen_gem.h"
48 #include "intel_aub.h"
50 #ifndef HAVE_MEMFD_CREATE
51 #include <sys/syscall.h>
54 memfd_create(const char *name
, unsigned int flags
)
56 return syscall(SYS_memfd_create
, name
, flags
);
60 /* Below is the only command missing from intel_aub.h in libdrm
61 * So, reuse intel_aub.h from libdrm and #define the
62 * AUB_MI_BATCH_BUFFER_END as below
64 #define AUB_MI_BATCH_BUFFER_END (0x0500 << 16)
67 #define BLUE_HEADER CSI "0;44m"
68 #define GREEN_HEADER CSI "1;42m"
69 #define NORMAL CSI "0m"
73 static int option_full_decode
= true;
74 static int option_print_offsets
= true;
75 static int max_vbo_lines
= -1;
76 static enum { COLOR_AUTO
, COLOR_ALWAYS
, COLOR_NEVER
} option_color
;
81 char *input_file
= NULL
, *xml_path
= NULL
;
82 struct gen_device_info devinfo
;
83 struct gen_batch_decode_ctx batch_ctx
;
86 struct list_head link
;
87 struct gen_batch_decode_bo bo
;
104 static struct list_head maps
;
105 static struct rb_tree ggtt
= {NULL
};
106 static struct rb_tree mem
= {NULL
};
108 off_t mem_fd_len
= 0;
112 struct brw_instruction
;
115 add_gtt_bo_map(struct gen_batch_decode_bo bo
, bool unmap_after_use
)
117 struct bo_map
*m
= calloc(1, sizeof(*m
));
120 m
->unmap_after_use
= unmap_after_use
;
121 list_add(&m
->link
, &maps
);
127 list_for_each_entry_safe(struct bo_map
, i
, &maps
, link
) {
128 if (i
->unmap_after_use
)
129 munmap((void *)i
->bo
.map
, i
->bo
.size
);
135 static inline struct ggtt_entry
*
136 ggtt_entry_next(struct ggtt_entry
*entry
)
140 struct rb_node
*node
= rb_node_next(&entry
->node
);
143 return rb_node_data(struct ggtt_entry
, node
, node
);
147 cmp_uint64(uint64_t a
, uint64_t b
)
157 cmp_ggtt_entry(const struct rb_node
*node
, const void *addr
)
159 struct ggtt_entry
*entry
= rb_node_data(struct ggtt_entry
, node
, node
);
160 return cmp_uint64(entry
->virt_addr
, *(const uint64_t *)addr
);
163 static struct ggtt_entry
*
164 ensure_ggtt_entry(struct rb_tree
*tree
, uint64_t virt_addr
)
166 struct rb_node
*node
= rb_tree_search_sloppy(&ggtt
, &virt_addr
,
169 if (!node
|| (cmp
= cmp_ggtt_entry(node
, &virt_addr
))) {
170 struct ggtt_entry
*new_entry
= calloc(1, sizeof(*new_entry
));
171 new_entry
->virt_addr
= virt_addr
;
172 rb_tree_insert_at(&ggtt
, node
, &new_entry
->node
, cmp
> 0);
173 node
= &new_entry
->node
;
176 return rb_node_data(struct ggtt_entry
, node
, node
);
179 static struct ggtt_entry
*
180 search_ggtt_entry(uint64_t virt_addr
)
184 struct rb_node
*node
= rb_tree_search(&ggtt
, &virt_addr
, cmp_ggtt_entry
);
189 return rb_node_data(struct ggtt_entry
, node
, node
);
193 cmp_phys_mem(const struct rb_node
*node
, const void *addr
)
195 struct phys_mem
*mem
= rb_node_data(struct phys_mem
, node
, node
);
196 return cmp_uint64(mem
->phys_addr
, *(uint64_t *)addr
);
199 static struct phys_mem
*
200 ensure_phys_mem(uint64_t phys_addr
)
202 struct rb_node
*node
= rb_tree_search_sloppy(&mem
, &phys_addr
, cmp_phys_mem
);
204 if (!node
|| (cmp
= cmp_phys_mem(node
, &phys_addr
))) {
205 struct phys_mem
*new_mem
= calloc(1, sizeof(*new_mem
));
206 new_mem
->phys_addr
= phys_addr
;
207 new_mem
->fd_offset
= mem_fd_len
;
209 int ftruncate_res
= ftruncate(mem_fd
, mem_fd_len
+= 4096);
210 assert(ftruncate_res
== 0);
212 new_mem
->data
= mmap(NULL
, 4096, PROT_READ
| PROT_WRITE
, MAP_SHARED
,
213 mem_fd
, new_mem
->fd_offset
);
214 assert(new_mem
->data
!= MAP_FAILED
);
216 rb_tree_insert_at(&mem
, node
, &new_mem
->node
, cmp
> 0);
217 node
= &new_mem
->node
;
220 return rb_node_data(struct phys_mem
, node
, node
);
223 static struct phys_mem
*
224 search_phys_mem(uint64_t phys_addr
)
228 struct rb_node
*node
= rb_tree_search(&mem
, &phys_addr
, cmp_phys_mem
);
233 return rb_node_data(struct phys_mem
, node
, node
);
237 handle_ggtt_entry_write(uint64_t address
, const void *_data
, uint32_t _size
)
239 uint64_t virt_addr
= (address
/ sizeof(uint64_t)) << 12;
240 const uint64_t *data
= _data
;
241 size_t size
= _size
/ sizeof(*data
);
242 for (const uint64_t *entry
= data
;
244 entry
++, virt_addr
+= 4096) {
245 struct ggtt_entry
*pt
= ensure_ggtt_entry(&ggtt
, virt_addr
);
246 pt
->phys_addr
= *entry
;
251 handle_physical_write(uint64_t phys_address
, const void *data
, uint32_t size
)
253 uint32_t to_write
= size
;
254 for (uint64_t page
= phys_address
& ~0xfff; page
< phys_address
+ size
; page
+= 4096) {
255 struct phys_mem
*mem
= ensure_phys_mem(page
);
256 uint64_t offset
= MAX2(page
, phys_address
) - page
;
257 uint32_t size_this_page
= MIN2(to_write
, 4096 - offset
);
258 to_write
-= size_this_page
;
259 memcpy(mem
->data
+ offset
, data
, size_this_page
);
260 data
= (const uint8_t *)data
+ size_this_page
;
265 handle_ggtt_write(uint64_t virt_address
, const void *data
, uint32_t size
)
267 uint32_t to_write
= size
;
268 for (uint64_t page
= virt_address
& ~0xfff; page
< virt_address
+ size
; page
+= 4096) {
269 struct ggtt_entry
*entry
= search_ggtt_entry(page
);
270 assert(entry
&& entry
->phys_addr
& 0x1);
272 uint64_t offset
= MAX2(page
, virt_address
) - page
;
273 uint32_t size_this_page
= MIN2(to_write
, 4096 - offset
);
274 to_write
-= size_this_page
;
276 uint64_t phys_page
= entry
->phys_addr
& ~0xfff; /* Clear the validity bits. */
277 handle_physical_write(phys_page
+ offset
, data
, size_this_page
);
278 data
= (const uint8_t *)data
+ size_this_page
;
282 static struct gen_batch_decode_bo
283 get_ggtt_batch_bo(void *user_data
, uint64_t address
)
285 struct gen_batch_decode_bo bo
= {0};
287 list_for_each_entry(struct bo_map
, i
, &maps
, link
)
288 if (i
->bo
.addr
<= address
&& i
->bo
.addr
+ i
->bo
.size
> address
)
293 struct ggtt_entry
*start
=
294 (struct ggtt_entry
*)rb_tree_search_sloppy(&ggtt
, &address
,
296 if (start
&& start
->virt_addr
< address
)
297 start
= ggtt_entry_next(start
);
301 struct ggtt_entry
*last
= start
;
302 for (struct ggtt_entry
*i
= ggtt_entry_next(last
);
303 i
&& last
->virt_addr
+ 4096 == i
->virt_addr
;
304 last
= i
, i
= ggtt_entry_next(last
))
307 bo
.addr
= MIN2(address
, start
->virt_addr
);
308 bo
.size
= last
->virt_addr
- bo
.addr
+ 4096;
309 bo
.map
= mmap(NULL
, bo
.size
, PROT_READ
, MAP_SHARED
| MAP_ANONYMOUS
, -1, 0);
310 assert(bo
.map
!= MAP_FAILED
);
312 for (struct ggtt_entry
*i
= start
;
314 i
= i
== last
? NULL
: ggtt_entry_next(i
)) {
315 uint64_t phys_addr
= i
->phys_addr
& ~0xfff;
316 struct phys_mem
*phys_mem
= search_phys_mem(phys_addr
);
321 uint32_t map_offset
= i
->virt_addr
- address
;
322 void *res
= mmap((uint8_t *)bo
.map
+ map_offset
, 4096, PROT_READ
,
323 MAP_SHARED
| MAP_FIXED
, mem_fd
, phys_mem
->fd_offset
);
324 assert(res
!= MAP_FAILED
);
327 add_gtt_bo_map(bo
, true);
332 static struct phys_mem
*
333 ppgtt_walk(uint64_t pml4
, uint64_t address
)
336 uint64_t addr
= pml4
;
337 for (int level
= 4; level
> 0; level
--) {
338 struct phys_mem
*table
= search_phys_mem(addr
);
341 int index
= (address
>> shift
) & 0x1ff;
342 uint64_t entry
= ((uint64_t *)table
->data
)[index
];
345 addr
= entry
& ~0xfff;
348 return search_phys_mem(addr
);
352 ppgtt_mapped(uint64_t pml4
, uint64_t address
)
354 return ppgtt_walk(pml4
, address
) != NULL
;
357 static struct gen_batch_decode_bo
358 get_ppgtt_batch_bo(void *user_data
, uint64_t address
)
360 struct gen_batch_decode_bo bo
= {0};
361 uint64_t pml4
= *(uint64_t *)user_data
;
365 if (!ppgtt_mapped(pml4
, address
))
368 /* Map everything until the first gap since we don't know how much the
369 * decoder actually needs.
371 uint64_t end
= address
;
372 while (ppgtt_mapped(pml4
, end
))
376 bo
.size
= end
- address
;
377 bo
.map
= mmap(NULL
, bo
.size
, PROT_READ
, MAP_SHARED
| MAP_ANONYMOUS
, -1, 0);
378 assert(bo
.map
!= MAP_FAILED
);
380 for (uint64_t page
= address
; page
< end
; page
+= 4096) {
381 struct phys_mem
*phys_mem
= ppgtt_walk(pml4
, page
);
383 void *res
= mmap((uint8_t *)bo
.map
+ (page
- bo
.addr
), 4096, PROT_READ
,
384 MAP_SHARED
| MAP_FIXED
, mem_fd
, phys_mem
->fd_offset
);
385 assert(res
!= MAP_FAILED
);
388 add_gtt_bo_map(bo
, true);
393 #define GEN_ENGINE_RENDER 1
394 #define GEN_ENGINE_BLITTER 2
397 handle_trace_block(uint32_t *p
)
399 int operation
= p
[1] & AUB_TRACE_OPERATION_MASK
;
400 int type
= p
[1] & AUB_TRACE_TYPE_MASK
;
401 int address_space
= p
[1] & AUB_TRACE_ADDRESS_SPACE_MASK
;
402 int header_length
= p
[0] & 0xffff;
403 int engine
= GEN_ENGINE_RENDER
;
404 struct gen_batch_decode_bo bo
= {
405 .map
= p
+ header_length
+ 2,
406 /* Addresses written by aubdump here are in canonical form but the batch
407 * decoder always gives us addresses with the top 16bits zeroed, so do
410 .addr
= gen_48b_address((devinfo
.gen
>= 8 ? ((uint64_t) p
[5] << 32) : 0) |
416 case AUB_TRACE_OP_DATA_WRITE
:
417 if (address_space
== AUB_TRACE_MEMTYPE_GTT
)
418 add_gtt_bo_map(bo
, false);
420 case AUB_TRACE_OP_COMMAND_WRITE
:
422 case AUB_TRACE_TYPE_RING_PRB0
:
423 engine
= GEN_ENGINE_RENDER
;
425 case AUB_TRACE_TYPE_RING_PRB2
:
426 engine
= GEN_ENGINE_BLITTER
;
429 fprintf(outfile
, "command write to unknown ring %d\n", type
);
433 (void)engine
; /* TODO */
434 batch_ctx
.get_bo
= get_ggtt_batch_bo
;
435 gen_print_batch(&batch_ctx
, bo
.map
, bo
.size
, 0);
443 aubinator_init(uint16_t aub_pci_id
, const char *app_name
)
445 if (!gen_get_device_info(pci_id
, &devinfo
)) {
446 fprintf(stderr
, "can't find device information: pci_id=0x%x\n", pci_id
);
450 enum gen_batch_decode_flags batch_flags
= 0;
451 if (option_color
== COLOR_ALWAYS
)
452 batch_flags
|= GEN_BATCH_DECODE_IN_COLOR
;
453 if (option_full_decode
)
454 batch_flags
|= GEN_BATCH_DECODE_FULL
;
455 if (option_print_offsets
)
456 batch_flags
|= GEN_BATCH_DECODE_OFFSETS
;
457 batch_flags
|= GEN_BATCH_DECODE_FLOATS
;
459 gen_batch_decode_ctx_init(&batch_ctx
, &devinfo
, outfile
, batch_flags
,
460 xml_path
, NULL
, NULL
, NULL
);
461 batch_ctx
.max_vbo_decoded_lines
= max_vbo_lines
;
463 char *color
= GREEN_HEADER
, *reset_color
= NORMAL
;
464 if (option_color
== COLOR_NEVER
)
465 color
= reset_color
= "";
467 fprintf(outfile
, "%sAubinator: Intel AUB file decoder.%-80s%s\n",
468 color
, "", reset_color
);
471 fprintf(outfile
, "File name: %s\n", input_file
);
474 fprintf(outfile
, "PCI ID: 0x%x\n", aub_pci_id
);
476 fprintf(outfile
, "Application name: %s\n", app_name
);
478 fprintf(outfile
, "Decoding as: %s\n", gen_get_device_name(pci_id
));
480 /* Throw in a new line before the first batch */
481 fprintf(outfile
, "\n");
485 handle_trace_header(uint32_t *p
)
487 /* The intel_aubdump tool from IGT is kind enough to put a PCI-ID= tag in
488 * the AUB header comment. If the user hasn't specified a hardware
489 * generation, try to use the one from the AUB file.
491 uint32_t *end
= p
+ (p
[0] & 0xffff) + 2;
493 if (end
> &p
[12] && p
[12] > 0)
494 sscanf((char *)&p
[13], "PCI-ID=%i", &aub_pci_id
);
500 strncpy(app_name
, (char *)&p
[2], 32);
503 aubinator_init(aub_pci_id
, app_name
);
507 handle_memtrace_version(uint32_t *p
)
509 int header_length
= p
[0] & 0xffff;
511 int app_name_len
= MIN2(4 * (header_length
+ 1 - 5), ARRAY_SIZE(app_name
) - 1);
515 strncpy(app_name
, (char *)&p
[5], app_name_len
);
516 app_name
[app_name_len
] = 0;
517 sscanf(app_name
, "PCI-ID=%i %n", &aub_pci_id
, &pci_id_len
);
520 aubinator_init(aub_pci_id
, app_name
+ pci_id_len
);
524 handle_memtrace_reg_write(uint32_t *p
)
526 static struct execlist_regs
{
527 uint32_t render_elsp
[4];
528 int render_elsp_index
;
529 uint32_t blitter_elsp
[4];
530 int blitter_elsp_index
;
533 uint32_t offset
= p
[1];
534 uint32_t value
= p
[5];
537 uint64_t context_descriptor
;
540 case 0x2230: /* render elsp */
541 state
.render_elsp
[state
.render_elsp_index
++] = value
;
542 if (state
.render_elsp_index
< 4)
545 state
.render_elsp_index
= 0;
546 engine
= GEN_ENGINE_RENDER
;
547 context_descriptor
= (uint64_t)state
.render_elsp
[2] << 32 |
548 state
.render_elsp
[3];
550 case 0x22230: /* blitter elsp */
551 state
.blitter_elsp
[state
.blitter_elsp_index
++] = value
;
552 if (state
.blitter_elsp_index
< 4)
555 state
.blitter_elsp_index
= 0;
556 engine
= GEN_ENGINE_BLITTER
;
557 context_descriptor
= (uint64_t)state
.blitter_elsp
[2] << 32 |
558 state
.blitter_elsp
[3];
560 case 0x2510: /* render elsq0 lo */
561 state
.render_elsp
[3] = value
;
564 case 0x2514: /* render elsq0 hi */
565 state
.render_elsp
[2] = value
;
568 case 0x22510: /* blitter elsq0 lo */
569 state
.blitter_elsp
[3] = value
;
572 case 0x22514: /* blitter elsq0 hi */
573 state
.blitter_elsp
[2] = value
;
576 case 0x2550: /* render elsc */
577 engine
= GEN_ENGINE_RENDER
;
578 context_descriptor
= (uint64_t)state
.render_elsp
[2] << 32 |
579 state
.render_elsp
[3];
581 case 0x22550: /* blitter elsc */
582 engine
= GEN_ENGINE_BLITTER
;
583 context_descriptor
= (uint64_t)state
.blitter_elsp
[2] << 32 |
584 state
.blitter_elsp
[3];
590 const uint32_t pphwsp_size
= 4096;
591 uint32_t pphwsp_addr
= context_descriptor
& 0xfffff000;
592 struct gen_batch_decode_bo pphwsp_bo
= get_ggtt_batch_bo(NULL
, pphwsp_addr
);
593 uint32_t *context
= (uint32_t *)((uint8_t *)pphwsp_bo
.map
+
594 (pphwsp_addr
- pphwsp_bo
.addr
) +
597 uint32_t ring_buffer_head
= context
[5];
598 uint32_t ring_buffer_tail
= context
[7];
599 uint32_t ring_buffer_start
= context
[9];
600 uint64_t pml4
= (uint64_t)context
[49] << 32 | context
[51];
602 struct gen_batch_decode_bo ring_bo
= get_ggtt_batch_bo(NULL
,
604 assert(ring_bo
.size
> 0);
605 void *commands
= (uint8_t *)ring_bo
.map
+ (ring_buffer_start
- ring_bo
.addr
);
607 if (context_descriptor
& 0x100 /* ppgtt */) {
608 batch_ctx
.get_bo
= get_ppgtt_batch_bo
;
609 batch_ctx
.user_data
= &pml4
;
611 batch_ctx
.get_bo
= get_ggtt_batch_bo
;
614 (void)engine
; /* TODO */
615 gen_print_batch(&batch_ctx
, commands
, ring_buffer_tail
- ring_buffer_head
,
621 handle_memtrace_mem_write(uint32_t *p
)
623 struct gen_batch_decode_bo bo
= {
625 /* Addresses written by aubdump here are in canonical form but the batch
626 * decoder always gives us addresses with the top 16bits zeroed, so do
629 .addr
= gen_48b_address(*(uint64_t*)&p
[1]),
632 uint32_t address_space
= p
[3] >> 28;
634 switch (address_space
) {
636 handle_ggtt_write(bo
.addr
, bo
.map
, bo
.size
);
639 add_gtt_bo_map(bo
, false);
641 case 2: /* Physical */
642 handle_physical_write(bo
.addr
, bo
.map
, bo
.size
);
644 case 4: /* GGTT Entry */
645 handle_ggtt_entry_write(bo
.addr
, bo
.map
, bo
.size
);
653 uint32_t *map
, *end
, *cursor
;
657 static struct aub_file
*
658 aub_file_open(const char *filename
)
660 struct aub_file
*file
;
664 file
= calloc(1, sizeof *file
);
665 fd
= open(filename
, O_RDONLY
);
667 fprintf(stderr
, "open %s failed: %s\n", filename
, strerror(errno
));
671 if (fstat(fd
, &sb
) == -1) {
672 fprintf(stderr
, "stat failed: %s\n", strerror(errno
));
676 file
->map
= mmap(NULL
, sb
.st_size
,
677 PROT_READ
, MAP_SHARED
, fd
, 0);
678 if (file
->map
== MAP_FAILED
) {
679 fprintf(stderr
, "mmap failed: %s\n", strerror(errno
));
685 file
->cursor
= file
->map
;
686 file
->end
= file
->map
+ sb
.st_size
/ 4;
691 #define TYPE(dw) (((dw) >> 29) & 7)
692 #define OPCODE(dw) (((dw) >> 23) & 0x3f)
693 #define SUBOPCODE(dw) (((dw) >> 16) & 0x7f)
695 #define MAKE_HEADER(type, opcode, subopcode) \
696 (((type) << 29) | ((opcode) << 23) | ((subopcode) << 16))
700 /* Classic AUB opcodes */
701 #define OPCODE_AUB 0x01
702 #define SUBOPCODE_HEADER 0x05
703 #define SUBOPCODE_BLOCK 0x41
704 #define SUBOPCODE_BMP 0x1e
706 /* Newer version AUB opcode */
707 #define OPCODE_NEW_AUB 0x2e
708 #define SUBOPCODE_REG_POLL 0x02
709 #define SUBOPCODE_REG_WRITE 0x03
710 #define SUBOPCODE_MEM_POLL 0x05
711 #define SUBOPCODE_MEM_WRITE 0x06
712 #define SUBOPCODE_VERSION 0x0e
714 #define MAKE_GEN(major, minor) ( ((major) << 8) | (minor) )
717 aub_file_decode_batch(struct aub_file
*file
)
719 uint32_t *p
, h
, *new_cursor
;
720 int header_length
, bias
;
722 assert(file
->cursor
< file
->end
);
726 header_length
= h
& 0xffff;
736 fprintf(outfile
, "unknown opcode %d at %td/%td\n",
737 OPCODE(h
), file
->cursor
- file
->map
,
738 file
->end
- file
->map
);
742 new_cursor
= p
+ header_length
+ bias
;
743 if ((h
& 0xffff0000) == MAKE_HEADER(TYPE_AUB
, OPCODE_AUB
, SUBOPCODE_BLOCK
)) {
744 assert(file
->end
- file
->cursor
>= 4);
745 new_cursor
+= p
[4] / 4;
748 assert(new_cursor
<= file
->end
);
750 switch (h
& 0xffff0000) {
751 case MAKE_HEADER(TYPE_AUB
, OPCODE_AUB
, SUBOPCODE_HEADER
):
752 handle_trace_header(p
);
754 case MAKE_HEADER(TYPE_AUB
, OPCODE_AUB
, SUBOPCODE_BLOCK
):
755 handle_trace_block(p
);
757 case MAKE_HEADER(TYPE_AUB
, OPCODE_AUB
, SUBOPCODE_BMP
):
759 case MAKE_HEADER(TYPE_AUB
, OPCODE_NEW_AUB
, SUBOPCODE_VERSION
):
760 handle_memtrace_version(p
);
762 case MAKE_HEADER(TYPE_AUB
, OPCODE_NEW_AUB
, SUBOPCODE_REG_WRITE
):
763 handle_memtrace_reg_write(p
);
765 case MAKE_HEADER(TYPE_AUB
, OPCODE_NEW_AUB
, SUBOPCODE_MEM_WRITE
):
766 handle_memtrace_mem_write(p
);
768 case MAKE_HEADER(TYPE_AUB
, OPCODE_NEW_AUB
, SUBOPCODE_MEM_POLL
):
769 fprintf(outfile
, "memory poll block (dwords %d):\n", h
& 0xffff);
771 case MAKE_HEADER(TYPE_AUB
, OPCODE_NEW_AUB
, SUBOPCODE_REG_POLL
):
774 fprintf(outfile
, "unknown block type=0x%x, opcode=0x%x, "
775 "subopcode=0x%x (%08x)\n", TYPE(h
), OPCODE(h
), SUBOPCODE(h
), h
);
778 file
->cursor
= new_cursor
;
784 aub_file_more_stuff(struct aub_file
*file
)
786 return file
->cursor
< file
->end
|| (file
->stream
&& !feof(file
->stream
));
808 execlp("less", "less", "-FRSi", NULL
);
817 print_help(const char *progname
, FILE *file
)
820 "Usage: %s [OPTION]... FILE\n"
821 "Decode aub file contents from FILE.\n\n"
822 " --help display this help and exit\n"
823 " --gen=platform decode for given platform (3 letter platform name)\n"
824 " --headers decode only command headers\n"
825 " --color[=WHEN] colorize the output; WHEN can be 'auto' (default\n"
826 " if omitted), 'always', or 'never'\n"
827 " --max-vbo-lines=N limit the number of decoded VBO lines\n"
828 " --no-pager don't launch pager\n"
829 " --no-offsets don't print instruction offsets\n"
830 " --xml=DIR load hardware xml description from directory DIR\n",
834 int main(int argc
, char *argv
[])
836 struct aub_file
*file
;
838 bool help
= false, pager
= true;
839 const struct option aubinator_opts
[] = {
840 { "help", no_argument
, (int *) &help
, true },
841 { "no-pager", no_argument
, (int *) &pager
, false },
842 { "no-offsets", no_argument
, (int *) &option_print_offsets
, false },
843 { "gen", required_argument
, NULL
, 'g' },
844 { "headers", no_argument
, (int *) &option_full_decode
, false },
845 { "color", required_argument
, NULL
, 'c' },
846 { "xml", required_argument
, NULL
, 'x' },
847 { "max-vbo-lines", required_argument
, NULL
, 'v' },
854 while ((c
= getopt_long(argc
, argv
, "", aubinator_opts
, &i
)) != -1) {
857 const int id
= gen_device_name_to_pci_device_id(optarg
);
859 fprintf(stderr
, "can't parse gen: '%s', expected ivb, byt, hsw, "
860 "bdw, chv, skl, kbl or bxt\n", optarg
);
868 if (optarg
== NULL
|| strcmp(optarg
, "always") == 0)
869 option_color
= COLOR_ALWAYS
;
870 else if (strcmp(optarg
, "never") == 0)
871 option_color
= COLOR_NEVER
;
872 else if (strcmp(optarg
, "auto") == 0)
873 option_color
= COLOR_AUTO
;
875 fprintf(stderr
, "invalid value for --color: %s", optarg
);
880 xml_path
= strdup(optarg
);
883 max_vbo_lines
= atoi(optarg
);
891 input_file
= argv
[optind
];
893 if (help
|| !input_file
) {
894 print_help(argv
[0], stderr
);
898 /* Do this before we redirect stdout to pager. */
899 if (option_color
== COLOR_AUTO
)
900 option_color
= isatty(1) ? COLOR_ALWAYS
: COLOR_NEVER
;
902 if (isatty(1) && pager
)
905 mem_fd
= memfd_create("phys memory", 0);
907 list_inithead(&maps
);
909 file
= aub_file_open(input_file
);
911 while (aub_file_more_stuff(file
) &&
912 aub_file_decode_batch(file
));
915 /* close the stdout which is opened to write the output */