mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-05-05 09:38:07 +02:00
intel: tools: split aub parsing from aubinator
v2: add parsing error callback (Lionel) Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com> Reviewed-by: Rafael Antognolli <rafael.antognolli@intel.com> (v1)
This commit is contained in:
parent
e15686567c
commit
4616639b49
5 changed files with 459 additions and 278 deletions
|
|
@ -26,6 +26,8 @@ noinst_PROGRAMS += \
|
||||||
|
|
||||||
|
|
||||||
tools_aubinator_SOURCES = \
|
tools_aubinator_SOURCES = \
|
||||||
|
tools/aub_read.c \
|
||||||
|
tools/aub_read.h \
|
||||||
tools/aubinator.c \
|
tools/aubinator.c \
|
||||||
tools/intel_aub.h
|
tools/intel_aub.h
|
||||||
|
|
||||||
|
|
|
||||||
333
src/intel/tools/aub_read.c
Normal file
333
src/intel/tools/aub_read.c
Normal file
|
|
@ -0,0 +1,333 @@
|
||||||
|
/*
|
||||||
|
* Copyright © 2016-2018 Intel Corporation
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice (including the next
|
||||||
|
* paragraph) shall be included in all copies or substantial portions of the
|
||||||
|
* Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
* IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
#include "common/gen_gem.h"
|
||||||
|
#include "util/macros.h"
|
||||||
|
|
||||||
|
#include "aub_read.h"
|
||||||
|
#include "intel_aub.h"
|
||||||
|
|
||||||
|
#define TYPE(dw) (((dw) >> 29) & 7)
|
||||||
|
#define OPCODE(dw) (((dw) >> 23) & 0x3f)
|
||||||
|
#define SUBOPCODE(dw) (((dw) >> 16) & 0x7f)
|
||||||
|
|
||||||
|
#define MAKE_HEADER(type, opcode, subopcode) \
|
||||||
|
(((type) << 29) | ((opcode) << 23) | ((subopcode) << 16))
|
||||||
|
|
||||||
|
#define TYPE_AUB 0x7
|
||||||
|
|
||||||
|
/* Classic AUB opcodes */
|
||||||
|
#define OPCODE_AUB 0x01
|
||||||
|
#define SUBOPCODE_HEADER 0x05
|
||||||
|
#define SUBOPCODE_BLOCK 0x41
|
||||||
|
#define SUBOPCODE_BMP 0x1e
|
||||||
|
|
||||||
|
/* Newer version AUB opcode */
|
||||||
|
#define OPCODE_NEW_AUB 0x2e
|
||||||
|
#define SUBOPCODE_REG_POLL 0x02
|
||||||
|
#define SUBOPCODE_REG_WRITE 0x03
|
||||||
|
#define SUBOPCODE_MEM_POLL 0x05
|
||||||
|
#define SUBOPCODE_MEM_WRITE 0x06
|
||||||
|
#define SUBOPCODE_VERSION 0x0e
|
||||||
|
|
||||||
|
#define MAKE_GEN(major, minor) (((major) << 8) | (minor))
|
||||||
|
|
||||||
|
static void
|
||||||
|
parse_error(struct aub_read *read, const uint32_t *p, const char *fmt, ...)
|
||||||
|
{
|
||||||
|
if (!read->error)
|
||||||
|
return;
|
||||||
|
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, fmt);
|
||||||
|
|
||||||
|
char msg[80];
|
||||||
|
vsnprintf(msg, sizeof(msg), fmt, ap);
|
||||||
|
read->error(read->user_data, p, msg);
|
||||||
|
|
||||||
|
va_end(ap);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
handle_trace_header(struct aub_read *read, const 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.
|
||||||
|
*/
|
||||||
|
const uint32_t *end = p + (p[0] & 0xffff) + 2;
|
||||||
|
int aub_pci_id = 0;
|
||||||
|
|
||||||
|
if (end > &p[12] && p[12] > 0) {
|
||||||
|
if (sscanf((char *)&p[13], "PCI-ID=%i", &aub_pci_id) > 0) {
|
||||||
|
if (!gen_get_device_info(aub_pci_id, &read->devinfo)) {
|
||||||
|
parse_error(read, p,
|
||||||
|
"can't find device information: pci_id=0x%x\n", aub_pci_id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char app_name[33];
|
||||||
|
strncpy(app_name, (const char *)&p[2], 32);
|
||||||
|
app_name[32] = 0;
|
||||||
|
|
||||||
|
if (read->info)
|
||||||
|
read->info(read->user_data, aub_pci_id, app_name);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
handle_memtrace_version(struct aub_read *read, const uint32_t *p)
|
||||||
|
{
|
||||||
|
int header_length = p[0] & 0xffff;
|
||||||
|
char app_name[64];
|
||||||
|
int app_name_len = MIN2(4 * (header_length + 1 - 5), ARRAY_SIZE(app_name) - 1);
|
||||||
|
int pci_id_len = 0;
|
||||||
|
int aub_pci_id = 0;
|
||||||
|
|
||||||
|
strncpy(app_name, (const char *)&p[5], app_name_len);
|
||||||
|
app_name[app_name_len] = 0;
|
||||||
|
|
||||||
|
if (sscanf(app_name, "PCI-ID=%i %n", &aub_pci_id, &pci_id_len) > 0) {
|
||||||
|
if (!gen_get_device_info(aub_pci_id, &read->devinfo)) {
|
||||||
|
parse_error(read, p, "can't find device information: pci_id=0x%x\n", aub_pci_id);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (read->info)
|
||||||
|
read->info(read->user_data, aub_pci_id, app_name + pci_id_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
handle_trace_block(struct aub_read *read, const uint32_t *p)
|
||||||
|
{
|
||||||
|
int operation = p[1] & AUB_TRACE_OPERATION_MASK;
|
||||||
|
int type = p[1] & AUB_TRACE_TYPE_MASK;
|
||||||
|
int address_space = p[1] & AUB_TRACE_ADDRESS_SPACE_MASK;
|
||||||
|
int header_length = p[0] & 0xffff;
|
||||||
|
int engine = GEN_ENGINE_RENDER;
|
||||||
|
const void *data = p + header_length + 2;
|
||||||
|
uint64_t address = gen_48b_address((read->devinfo.gen >= 8 ? ((uint64_t) p[5] << 32) : 0) |
|
||||||
|
((uint64_t) p[3]));
|
||||||
|
uint32_t size = p[4];
|
||||||
|
|
||||||
|
switch (operation) {
|
||||||
|
case AUB_TRACE_OP_DATA_WRITE:
|
||||||
|
if (address_space == AUB_TRACE_MEMTYPE_GTT) {
|
||||||
|
if (read->local_write)
|
||||||
|
read->local_write(read->user_data, address, data, size);
|
||||||
|
break;
|
||||||
|
case AUB_TRACE_OP_COMMAND_WRITE:
|
||||||
|
switch (type) {
|
||||||
|
case AUB_TRACE_TYPE_RING_PRB0:
|
||||||
|
engine = GEN_ENGINE_RENDER;
|
||||||
|
break;
|
||||||
|
case AUB_TRACE_TYPE_RING_PRB2:
|
||||||
|
engine = GEN_ENGINE_BLITTER;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
parse_error(read, p, "command write to unknown ring %d\n", type);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (read->ring_write)
|
||||||
|
read->ring_write(read->user_data, engine, data, size);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
handle_memtrace_reg_write(struct aub_read *read, const uint32_t *p)
|
||||||
|
{
|
||||||
|
uint32_t offset = p[1];
|
||||||
|
uint32_t value = p[5];
|
||||||
|
|
||||||
|
if (read->reg_write)
|
||||||
|
read->reg_write(read->user_data, offset, value);
|
||||||
|
|
||||||
|
int engine;
|
||||||
|
uint64_t context_descriptor;
|
||||||
|
|
||||||
|
switch (offset) {
|
||||||
|
case 0x2230: /* render elsp */
|
||||||
|
read->render_elsp[read->render_elsp_index++] = value;
|
||||||
|
if (read->render_elsp_index < 4)
|
||||||
|
return;
|
||||||
|
|
||||||
|
read->render_elsp_index = 0;
|
||||||
|
engine = GEN_ENGINE_RENDER;
|
||||||
|
context_descriptor = (uint64_t)read->render_elsp[2] << 32 |
|
||||||
|
read->render_elsp[3];
|
||||||
|
break;
|
||||||
|
case 0x22230: /* blitter elsp */
|
||||||
|
read->blitter_elsp[read->blitter_elsp_index++] = value;
|
||||||
|
if (read->blitter_elsp_index < 4)
|
||||||
|
return;
|
||||||
|
|
||||||
|
read->blitter_elsp_index = 0;
|
||||||
|
engine = GEN_ENGINE_BLITTER;
|
||||||
|
context_descriptor = (uint64_t)read->blitter_elsp[2] << 32 |
|
||||||
|
read->blitter_elsp[3];
|
||||||
|
break;
|
||||||
|
case 0x2510: /* render elsq0 lo */
|
||||||
|
read->render_elsp[3] = value;
|
||||||
|
return;
|
||||||
|
break;
|
||||||
|
case 0x2514: /* render elsq0 hi */
|
||||||
|
read->render_elsp[2] = value;
|
||||||
|
return;
|
||||||
|
break;
|
||||||
|
case 0x22510: /* blitter elsq0 lo */
|
||||||
|
read->blitter_elsp[3] = value;
|
||||||
|
return;
|
||||||
|
break;
|
||||||
|
case 0x22514: /* blitter elsq0 hi */
|
||||||
|
read->blitter_elsp[2] = value;
|
||||||
|
return;
|
||||||
|
break;
|
||||||
|
case 0x2550: /* render elsc */
|
||||||
|
engine = GEN_ENGINE_RENDER;
|
||||||
|
context_descriptor = (uint64_t)read->render_elsp[2] << 32 |
|
||||||
|
read->render_elsp[3];
|
||||||
|
break;
|
||||||
|
case 0x22550: /* blitter elsc */
|
||||||
|
engine = GEN_ENGINE_BLITTER;
|
||||||
|
context_descriptor = (uint64_t)read->blitter_elsp[2] << 32 |
|
||||||
|
read->blitter_elsp[3];
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (read->execlist_write)
|
||||||
|
read->execlist_write(read->user_data, engine, context_descriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
handle_memtrace_mem_write(struct aub_read *read, const uint32_t *p)
|
||||||
|
{
|
||||||
|
const void *data = p + 5;
|
||||||
|
uint64_t addr = gen_48b_address(*(uint64_t*)&p[1]);
|
||||||
|
uint32_t size = p[4];
|
||||||
|
uint32_t address_space = p[3] >> 28;
|
||||||
|
|
||||||
|
switch (address_space) {
|
||||||
|
case 0: /* GGTT */
|
||||||
|
if (read->ggtt_write)
|
||||||
|
read->ggtt_write(read->user_data, addr, data, size);
|
||||||
|
break;
|
||||||
|
case 1: /* Local */
|
||||||
|
if (read->local_write)
|
||||||
|
read->local_write(read->user_data, addr, data, size);
|
||||||
|
break;
|
||||||
|
case 2: /* Physical */
|
||||||
|
if (read->phys_write)
|
||||||
|
read->phys_write(read->user_data, addr, data, size);
|
||||||
|
break;
|
||||||
|
case 4: /* GGTT Entry */
|
||||||
|
if (read->ggtt_entry_write)
|
||||||
|
read->ggtt_entry_write(read->user_data, addr, data, size);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
aub_read_command(struct aub_read *read, const void *data, uint32_t data_len)
|
||||||
|
{
|
||||||
|
const uint32_t *p = data, *end = data + data_len, *next;
|
||||||
|
uint32_t h, header_length, bias;
|
||||||
|
|
||||||
|
assert(data_len >= 4);
|
||||||
|
|
||||||
|
h = *p;
|
||||||
|
header_length = h & 0xffff;
|
||||||
|
|
||||||
|
switch (OPCODE(h)) {
|
||||||
|
case OPCODE_AUB:
|
||||||
|
bias = 2;
|
||||||
|
break;
|
||||||
|
case OPCODE_NEW_AUB:
|
||||||
|
bias = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
parse_error(read, data, "unknown opcode %d\n", OPCODE(h));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
next = p + header_length + bias;
|
||||||
|
if ((h & 0xffff0000) == MAKE_HEADER(TYPE_AUB, OPCODE_AUB, SUBOPCODE_BLOCK)) {
|
||||||
|
assert(end - p >= 4);
|
||||||
|
next += p[4] / 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(next <= end);
|
||||||
|
|
||||||
|
switch (h & 0xffff0000) {
|
||||||
|
case MAKE_HEADER(TYPE_AUB, OPCODE_AUB, SUBOPCODE_HEADER):
|
||||||
|
if (!handle_trace_header(read, p))
|
||||||
|
return -1;
|
||||||
|
break;
|
||||||
|
case MAKE_HEADER(TYPE_AUB, OPCODE_AUB, SUBOPCODE_BLOCK):
|
||||||
|
if (!handle_trace_block(read, p))
|
||||||
|
return -1;
|
||||||
|
break;
|
||||||
|
case MAKE_HEADER(TYPE_AUB, OPCODE_AUB, SUBOPCODE_BMP):
|
||||||
|
break;
|
||||||
|
case MAKE_HEADER(TYPE_AUB, OPCODE_NEW_AUB, SUBOPCODE_VERSION):
|
||||||
|
if (!handle_memtrace_version(read, p))
|
||||||
|
return -1;
|
||||||
|
break;
|
||||||
|
case MAKE_HEADER(TYPE_AUB, OPCODE_NEW_AUB, SUBOPCODE_REG_WRITE):
|
||||||
|
handle_memtrace_reg_write(read, p);
|
||||||
|
break;
|
||||||
|
case MAKE_HEADER(TYPE_AUB, OPCODE_NEW_AUB, SUBOPCODE_MEM_WRITE):
|
||||||
|
handle_memtrace_mem_write(read, p);
|
||||||
|
break;
|
||||||
|
case MAKE_HEADER(TYPE_AUB, OPCODE_NEW_AUB, SUBOPCODE_MEM_POLL):
|
||||||
|
/* fprintf(outfile, "memory poll block (dwords %d):\n", h & 0xffff); */
|
||||||
|
break;
|
||||||
|
case MAKE_HEADER(TYPE_AUB, OPCODE_NEW_AUB, SUBOPCODE_REG_POLL):
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
parse_error(read, p,
|
||||||
|
"unknown block type=0x%x, opcode=0x%x, subopcode=0x%x (%08x)\n",
|
||||||
|
TYPE(h), OPCODE(h), SUBOPCODE(h), h);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (next - p) * sizeof(*p);
|
||||||
|
}
|
||||||
77
src/intel/tools/aub_read.h
Normal file
77
src/intel/tools/aub_read.h
Normal file
|
|
@ -0,0 +1,77 @@
|
||||||
|
/*
|
||||||
|
* Copyright © 2018 Intel Corporation
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice (including the next
|
||||||
|
* paragraph) shall be included in all copies or substantial portions of the
|
||||||
|
* Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
* IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef INTEL_AUB_READ
|
||||||
|
#define INTEL_AUB_READ
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "dev/gen_device_info.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum gen_engine {
|
||||||
|
GEN_ENGINE_RENDER = 1,
|
||||||
|
GEN_ENGINE_BLITTER = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct aub_read {
|
||||||
|
/* Caller's data */
|
||||||
|
void *user_data;
|
||||||
|
|
||||||
|
void (*error)(void *user_data, const void *aub_data, const char *msg);
|
||||||
|
|
||||||
|
void (*info)(void *user_data, int pci_id, const char *app_name);
|
||||||
|
|
||||||
|
void (*local_write)(void *user_data, uint64_t phys_addr, const void *data, uint32_t data_len);
|
||||||
|
void (*phys_write)(void *user_data, uint64_t phys_addr, const void *data, uint32_t data_len);
|
||||||
|
void (*ggtt_write)(void *user_data, uint64_t phys_addr, const void *data, uint32_t data_len);
|
||||||
|
void (*ggtt_entry_write)(void *user_data, uint64_t phys_addr,
|
||||||
|
const void *data, uint32_t data_len);
|
||||||
|
|
||||||
|
void (*reg_write)(void *user_data, uint32_t reg_offset, uint32_t reg_value);
|
||||||
|
|
||||||
|
void (*ring_write)(void *user_data, enum gen_engine engine,
|
||||||
|
const void *data, uint32_t data_len);
|
||||||
|
void (*execlist_write)(void *user_data, enum gen_engine engine,
|
||||||
|
uint64_t context_descriptor);
|
||||||
|
|
||||||
|
/* Reader's data */
|
||||||
|
uint32_t render_elsp[4];
|
||||||
|
int render_elsp_index;
|
||||||
|
uint32_t blitter_elsp[4];
|
||||||
|
int blitter_elsp_index;
|
||||||
|
|
||||||
|
struct gen_device_info devinfo;
|
||||||
|
};
|
||||||
|
|
||||||
|
int aub_read_command(struct aub_read *read, const void *data, uint32_t data_len);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* INTEL_AUB_READ */
|
||||||
|
|
@ -43,9 +43,8 @@
|
||||||
#include "util/rb_tree.h"
|
#include "util/rb_tree.h"
|
||||||
|
|
||||||
#include "common/gen_decoder.h"
|
#include "common/gen_decoder.h"
|
||||||
#include "common/gen_disasm.h"
|
|
||||||
#include "common/gen_gem.h"
|
|
||||||
#include "intel_aub.h"
|
#include "intel_aub.h"
|
||||||
|
#include "aub_read.h"
|
||||||
|
|
||||||
#ifndef HAVE_MEMFD_CREATE
|
#ifndef HAVE_MEMFD_CREATE
|
||||||
#include <sys/syscall.h>
|
#include <sys/syscall.h>
|
||||||
|
|
@ -234,7 +233,18 @@ search_phys_mem(uint64_t phys_addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
handle_ggtt_entry_write(uint64_t address, const void *_data, uint32_t _size)
|
handle_local_write(void *user_data, uint64_t address, const void *data, uint32_t size)
|
||||||
|
{
|
||||||
|
struct gen_batch_decode_bo bo = {
|
||||||
|
.map = data,
|
||||||
|
.addr = address,
|
||||||
|
.size = size,
|
||||||
|
};
|
||||||
|
add_gtt_bo_map(bo, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
handle_ggtt_entry_write(void *user_data, uint64_t address, const void *_data, uint32_t _size)
|
||||||
{
|
{
|
||||||
uint64_t virt_addr = (address / sizeof(uint64_t)) << 12;
|
uint64_t virt_addr = (address / sizeof(uint64_t)) << 12;
|
||||||
const uint64_t *data = _data;
|
const uint64_t *data = _data;
|
||||||
|
|
@ -248,7 +258,7 @@ handle_ggtt_entry_write(uint64_t address, const void *_data, uint32_t _size)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
handle_physical_write(uint64_t phys_address, const void *data, uint32_t size)
|
handle_physical_write(void *user_data, uint64_t phys_address, const void *data, uint32_t size)
|
||||||
{
|
{
|
||||||
uint32_t to_write = size;
|
uint32_t to_write = size;
|
||||||
for (uint64_t page = phys_address & ~0xfff; page < phys_address + size; page += 4096) {
|
for (uint64_t page = phys_address & ~0xfff; page < phys_address + size; page += 4096) {
|
||||||
|
|
@ -262,7 +272,7 @@ handle_physical_write(uint64_t phys_address, const void *data, uint32_t size)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
handle_ggtt_write(uint64_t virt_address, const void *data, uint32_t size)
|
handle_ggtt_write(void *user_data, uint64_t virt_address, const void *data, uint32_t size)
|
||||||
{
|
{
|
||||||
uint32_t to_write = size;
|
uint32_t to_write = size;
|
||||||
for (uint64_t page = virt_address & ~0xfff; page < virt_address + size; page += 4096) {
|
for (uint64_t page = virt_address & ~0xfff; page < virt_address + size; page += 4096) {
|
||||||
|
|
@ -274,7 +284,7 @@ handle_ggtt_write(uint64_t virt_address, const void *data, uint32_t size)
|
||||||
to_write -= size_this_page;
|
to_write -= size_this_page;
|
||||||
|
|
||||||
uint64_t phys_page = entry->phys_addr & ~0xfff; /* Clear the validity bits. */
|
uint64_t phys_page = entry->phys_addr & ~0xfff; /* Clear the validity bits. */
|
||||||
handle_physical_write(phys_page + offset, data, size_this_page);
|
handle_physical_write(user_data, phys_page + offset, data, size_this_page);
|
||||||
data = (const uint8_t *)data + size_this_page;
|
data = (const uint8_t *)data + size_this_page;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -390,58 +400,17 @@ get_ppgtt_batch_bo(void *user_data, uint64_t address)
|
||||||
return bo;
|
return bo;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define GEN_ENGINE_RENDER 1
|
|
||||||
#define GEN_ENGINE_BLITTER 2
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
handle_trace_block(uint32_t *p)
|
aubinator_error(void *user_data, const void *aub_data, const char *msg)
|
||||||
{
|
{
|
||||||
int operation = p[1] & AUB_TRACE_OPERATION_MASK;
|
fprintf(stderr, msg);
|
||||||
int type = p[1] & AUB_TRACE_TYPE_MASK;
|
|
||||||
int address_space = p[1] & AUB_TRACE_ADDRESS_SPACE_MASK;
|
|
||||||
int header_length = p[0] & 0xffff;
|
|
||||||
int engine = GEN_ENGINE_RENDER;
|
|
||||||
struct gen_batch_decode_bo bo = {
|
|
||||||
.map = p + header_length + 2,
|
|
||||||
/* Addresses written by aubdump here are in canonical form but the batch
|
|
||||||
* decoder always gives us addresses with the top 16bits zeroed, so do
|
|
||||||
* the same here.
|
|
||||||
*/
|
|
||||||
.addr = gen_48b_address((devinfo.gen >= 8 ? ((uint64_t) p[5] << 32) : 0) |
|
|
||||||
((uint64_t) p[3])),
|
|
||||||
.size = p[4],
|
|
||||||
};
|
|
||||||
|
|
||||||
switch (operation) {
|
|
||||||
case AUB_TRACE_OP_DATA_WRITE:
|
|
||||||
if (address_space == AUB_TRACE_MEMTYPE_GTT)
|
|
||||||
add_gtt_bo_map(bo, false);
|
|
||||||
break;
|
|
||||||
case AUB_TRACE_OP_COMMAND_WRITE:
|
|
||||||
switch (type) {
|
|
||||||
case AUB_TRACE_TYPE_RING_PRB0:
|
|
||||||
engine = GEN_ENGINE_RENDER;
|
|
||||||
break;
|
|
||||||
case AUB_TRACE_TYPE_RING_PRB2:
|
|
||||||
engine = GEN_ENGINE_BLITTER;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fprintf(outfile, "command write to unknown ring %d\n", type);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
(void)engine; /* TODO */
|
|
||||||
batch_ctx.get_bo = get_ggtt_batch_bo;
|
|
||||||
gen_print_batch(&batch_ctx, bo.map, bo.size, 0);
|
|
||||||
|
|
||||||
clear_bo_maps();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
aubinator_init(uint16_t aub_pci_id, const char *app_name)
|
aubinator_init(void *user_data, int aub_pci_id, const char *app_name)
|
||||||
{
|
{
|
||||||
|
pci_id = aub_pci_id;
|
||||||
|
|
||||||
if (!gen_get_device_info(pci_id, &devinfo)) {
|
if (!gen_get_device_info(pci_id, &devinfo)) {
|
||||||
fprintf(stderr, "can't find device information: pci_id=0x%x\n", pci_id);
|
fprintf(stderr, "can't find device information: pci_id=0x%x\n", pci_id);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
|
|
@ -482,111 +451,8 @@ aubinator_init(uint16_t aub_pci_id, const char *app_name)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
handle_trace_header(uint32_t *p)
|
handle_execlist_write(void *user_data, enum gen_engine engine, uint64_t context_descriptor)
|
||||||
{
|
{
|
||||||
/* 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;
|
|
||||||
|
|
||||||
char app_name[33];
|
|
||||||
strncpy(app_name, (char *)&p[2], 32);
|
|
||||||
app_name[32] = 0;
|
|
||||||
|
|
||||||
aubinator_init(aub_pci_id, app_name);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
handle_memtrace_version(uint32_t *p)
|
|
||||||
{
|
|
||||||
int header_length = p[0] & 0xffff;
|
|
||||||
char app_name[64];
|
|
||||||
int app_name_len = MIN2(4 * (header_length + 1 - 5), ARRAY_SIZE(app_name) - 1);
|
|
||||||
int pci_id_len = 0;
|
|
||||||
int aub_pci_id = 0;
|
|
||||||
|
|
||||||
strncpy(app_name, (char *)&p[5], app_name_len);
|
|
||||||
app_name[app_name_len] = 0;
|
|
||||||
sscanf(app_name, "PCI-ID=%i %n", &aub_pci_id, &pci_id_len);
|
|
||||||
if (pci_id == 0)
|
|
||||||
pci_id = aub_pci_id;
|
|
||||||
aubinator_init(aub_pci_id, app_name + pci_id_len);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
handle_memtrace_reg_write(uint32_t *p)
|
|
||||||
{
|
|
||||||
static struct execlist_regs {
|
|
||||||
uint32_t render_elsp[4];
|
|
||||||
int render_elsp_index;
|
|
||||||
uint32_t blitter_elsp[4];
|
|
||||||
int blitter_elsp_index;
|
|
||||||
} state = {};
|
|
||||||
|
|
||||||
uint32_t offset = p[1];
|
|
||||||
uint32_t value = p[5];
|
|
||||||
|
|
||||||
int engine;
|
|
||||||
uint64_t context_descriptor;
|
|
||||||
|
|
||||||
switch (offset) {
|
|
||||||
case 0x2230: /* render elsp */
|
|
||||||
state.render_elsp[state.render_elsp_index++] = value;
|
|
||||||
if (state.render_elsp_index < 4)
|
|
||||||
return;
|
|
||||||
|
|
||||||
state.render_elsp_index = 0;
|
|
||||||
engine = GEN_ENGINE_RENDER;
|
|
||||||
context_descriptor = (uint64_t)state.render_elsp[2] << 32 |
|
|
||||||
state.render_elsp[3];
|
|
||||||
break;
|
|
||||||
case 0x22230: /* blitter elsp */
|
|
||||||
state.blitter_elsp[state.blitter_elsp_index++] = value;
|
|
||||||
if (state.blitter_elsp_index < 4)
|
|
||||||
return;
|
|
||||||
|
|
||||||
state.blitter_elsp_index = 0;
|
|
||||||
engine = GEN_ENGINE_BLITTER;
|
|
||||||
context_descriptor = (uint64_t)state.blitter_elsp[2] << 32 |
|
|
||||||
state.blitter_elsp[3];
|
|
||||||
break;
|
|
||||||
case 0x2510: /* render elsq0 lo */
|
|
||||||
state.render_elsp[3] = value;
|
|
||||||
return;
|
|
||||||
break;
|
|
||||||
case 0x2514: /* render elsq0 hi */
|
|
||||||
state.render_elsp[2] = value;
|
|
||||||
return;
|
|
||||||
break;
|
|
||||||
case 0x22510: /* blitter elsq0 lo */
|
|
||||||
state.blitter_elsp[3] = value;
|
|
||||||
return;
|
|
||||||
break;
|
|
||||||
case 0x22514: /* blitter elsq0 hi */
|
|
||||||
state.blitter_elsp[2] = value;
|
|
||||||
return;
|
|
||||||
break;
|
|
||||||
case 0x2550: /* render elsc */
|
|
||||||
engine = GEN_ENGINE_RENDER;
|
|
||||||
context_descriptor = (uint64_t)state.render_elsp[2] << 32 |
|
|
||||||
state.render_elsp[3];
|
|
||||||
break;
|
|
||||||
case 0x22550: /* blitter elsc */
|
|
||||||
engine = GEN_ENGINE_BLITTER;
|
|
||||||
context_descriptor = (uint64_t)state.blitter_elsp[2] << 32 |
|
|
||||||
state.blitter_elsp[3];
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint32_t pphwsp_size = 4096;
|
const uint32_t pphwsp_size = 4096;
|
||||||
uint32_t pphwsp_addr = context_descriptor & 0xfffff000;
|
uint32_t pphwsp_addr = context_descriptor & 0xfffff000;
|
||||||
struct gen_batch_decode_bo pphwsp_bo = get_ggtt_batch_bo(NULL, pphwsp_addr);
|
struct gen_batch_decode_bo pphwsp_bo = get_ggtt_batch_bo(NULL, pphwsp_addr);
|
||||||
|
|
@ -618,40 +484,20 @@ handle_memtrace_reg_write(uint32_t *p)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
handle_memtrace_mem_write(uint32_t *p)
|
handle_ring_write(void *user_data, enum gen_engine engine,
|
||||||
|
const void *data, uint32_t data_len)
|
||||||
{
|
{
|
||||||
struct gen_batch_decode_bo bo = {
|
batch_ctx.get_bo = get_ggtt_batch_bo;
|
||||||
.map = p + 5,
|
|
||||||
/* Addresses written by aubdump here are in canonical form but the batch
|
|
||||||
* decoder always gives us addresses with the top 16bits zeroed, so do
|
|
||||||
* the same here.
|
|
||||||
*/
|
|
||||||
.addr = gen_48b_address(*(uint64_t*)&p[1]),
|
|
||||||
.size = p[4],
|
|
||||||
};
|
|
||||||
uint32_t address_space = p[3] >> 28;
|
|
||||||
|
|
||||||
switch (address_space) {
|
gen_print_batch(&batch_ctx, data, data_len, 0);
|
||||||
case 0: /* GGTT */
|
|
||||||
handle_ggtt_write(bo.addr, bo.map, bo.size);
|
clear_bo_maps();
|
||||||
break;
|
|
||||||
case 1: /* Local */
|
|
||||||
add_gtt_bo_map(bo, false);
|
|
||||||
break;
|
|
||||||
case 2: /* Physical */
|
|
||||||
handle_physical_write(bo.addr, bo.map, bo.size);
|
|
||||||
break;
|
|
||||||
case 4: /* GGTT Entry */
|
|
||||||
handle_ggtt_entry_write(bo.addr, bo.map, bo.size);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct aub_file {
|
struct aub_file {
|
||||||
FILE *stream;
|
FILE *stream;
|
||||||
|
|
||||||
uint32_t *map, *end, *cursor;
|
void *map, *end, *cursor;
|
||||||
uint32_t *mem_end;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct aub_file *
|
static struct aub_file *
|
||||||
|
|
@ -683,103 +529,11 @@ aub_file_open(const char *filename)
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|
||||||
file->cursor = file->map;
|
file->cursor = file->map;
|
||||||
file->end = file->map + sb.st_size / 4;
|
file->end = file->map + sb.st_size;
|
||||||
|
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define TYPE(dw) (((dw) >> 29) & 7)
|
|
||||||
#define OPCODE(dw) (((dw) >> 23) & 0x3f)
|
|
||||||
#define SUBOPCODE(dw) (((dw) >> 16) & 0x7f)
|
|
||||||
|
|
||||||
#define MAKE_HEADER(type, opcode, subopcode) \
|
|
||||||
(((type) << 29) | ((opcode) << 23) | ((subopcode) << 16))
|
|
||||||
|
|
||||||
#define TYPE_AUB 0x7
|
|
||||||
|
|
||||||
/* Classic AUB opcodes */
|
|
||||||
#define OPCODE_AUB 0x01
|
|
||||||
#define SUBOPCODE_HEADER 0x05
|
|
||||||
#define SUBOPCODE_BLOCK 0x41
|
|
||||||
#define SUBOPCODE_BMP 0x1e
|
|
||||||
|
|
||||||
/* Newer version AUB opcode */
|
|
||||||
#define OPCODE_NEW_AUB 0x2e
|
|
||||||
#define SUBOPCODE_REG_POLL 0x02
|
|
||||||
#define SUBOPCODE_REG_WRITE 0x03
|
|
||||||
#define SUBOPCODE_MEM_POLL 0x05
|
|
||||||
#define SUBOPCODE_MEM_WRITE 0x06
|
|
||||||
#define SUBOPCODE_VERSION 0x0e
|
|
||||||
|
|
||||||
#define MAKE_GEN(major, minor) ( ((major) << 8) | (minor) )
|
|
||||||
|
|
||||||
static bool
|
|
||||||
aub_file_decode_batch(struct aub_file *file)
|
|
||||||
{
|
|
||||||
uint32_t *p, h, *new_cursor;
|
|
||||||
int header_length, bias;
|
|
||||||
|
|
||||||
assert(file->cursor < file->end);
|
|
||||||
|
|
||||||
p = file->cursor;
|
|
||||||
h = *p;
|
|
||||||
header_length = h & 0xffff;
|
|
||||||
|
|
||||||
switch (OPCODE(h)) {
|
|
||||||
case OPCODE_AUB:
|
|
||||||
bias = 2;
|
|
||||||
break;
|
|
||||||
case OPCODE_NEW_AUB:
|
|
||||||
bias = 1;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fprintf(outfile, "unknown opcode %d at %td/%td\n",
|
|
||||||
OPCODE(h), file->cursor - file->map,
|
|
||||||
file->end - file->map);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
new_cursor = p + header_length + bias;
|
|
||||||
if ((h & 0xffff0000) == MAKE_HEADER(TYPE_AUB, OPCODE_AUB, SUBOPCODE_BLOCK)) {
|
|
||||||
assert(file->end - file->cursor >= 4);
|
|
||||||
new_cursor += p[4] / 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
assert(new_cursor <= file->end);
|
|
||||||
|
|
||||||
switch (h & 0xffff0000) {
|
|
||||||
case MAKE_HEADER(TYPE_AUB, OPCODE_AUB, SUBOPCODE_HEADER):
|
|
||||||
handle_trace_header(p);
|
|
||||||
break;
|
|
||||||
case MAKE_HEADER(TYPE_AUB, OPCODE_AUB, SUBOPCODE_BLOCK):
|
|
||||||
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):
|
|
||||||
handle_memtrace_version(p);
|
|
||||||
break;
|
|
||||||
case MAKE_HEADER(TYPE_AUB, OPCODE_NEW_AUB, SUBOPCODE_REG_WRITE):
|
|
||||||
handle_memtrace_reg_write(p);
|
|
||||||
break;
|
|
||||||
case MAKE_HEADER(TYPE_AUB, OPCODE_NEW_AUB, SUBOPCODE_MEM_WRITE):
|
|
||||||
handle_memtrace_mem_write(p);
|
|
||||||
break;
|
|
||||||
case MAKE_HEADER(TYPE_AUB, OPCODE_NEW_AUB, SUBOPCODE_MEM_POLL):
|
|
||||||
fprintf(outfile, "memory poll block (dwords %d):\n", h & 0xffff);
|
|
||||||
break;
|
|
||||||
case MAKE_HEADER(TYPE_AUB, OPCODE_NEW_AUB, SUBOPCODE_REG_POLL):
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
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 = new_cursor;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
aub_file_more_stuff(struct aub_file *file)
|
aub_file_more_stuff(struct aub_file *file)
|
||||||
{
|
{
|
||||||
|
|
@ -908,8 +662,23 @@ int main(int argc, char *argv[])
|
||||||
|
|
||||||
file = aub_file_open(input_file);
|
file = aub_file_open(input_file);
|
||||||
|
|
||||||
|
struct aub_read aub_read = {
|
||||||
|
.user_data = NULL,
|
||||||
|
.error = aubinator_error,
|
||||||
|
.info = aubinator_init,
|
||||||
|
.local_write = handle_local_write,
|
||||||
|
.phys_write = handle_physical_write,
|
||||||
|
.ggtt_write = handle_ggtt_write,
|
||||||
|
.ggtt_entry_write = handle_ggtt_entry_write,
|
||||||
|
.execlist_write = handle_execlist_write,
|
||||||
|
.ring_write = handle_ring_write,
|
||||||
|
};
|
||||||
|
int consumed;
|
||||||
while (aub_file_more_stuff(file) &&
|
while (aub_file_more_stuff(file) &&
|
||||||
aub_file_decode_batch(file));
|
(consumed = aub_read_command(&aub_read, file->cursor,
|
||||||
|
file->end - file->cursor)) > 0) {
|
||||||
|
file->cursor += consumed;
|
||||||
|
}
|
||||||
|
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
/* close the stdout which is opened to write the output */
|
/* close the stdout which is opened to write the output */
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@
|
||||||
|
|
||||||
aubinator = executable(
|
aubinator = executable(
|
||||||
'aubinator',
|
'aubinator',
|
||||||
files('aubinator.c', 'intel_aub.h'),
|
files('aubinator.c', 'intel_aub.h', 'aub_read.h', 'aub_read.c'),
|
||||||
dependencies : [dep_expat, dep_zlib, dep_dl, dep_thread, dep_m],
|
dependencies : [dep_expat, dep_zlib, dep_dl, dep_thread, dep_m],
|
||||||
include_directories : [inc_common, inc_intel],
|
include_directories : [inc_common, inc_intel],
|
||||||
link_with : [libintel_common, libintel_compiler, libintel_dev, libmesa_util],
|
link_with : [libintel_common, libintel_compiler, libintel_dev, libmesa_util],
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue