1/* 2 * Copyright © 2016-2018 Intel Corporation 3 * 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: 10 * 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 13 * Software. 14 * 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 21 * IN THE SOFTWARE. 22 * 23 */ 24 25#include <inttypes.h> 26#include <stdio.h> 27#include <stdlib.h> 28#include <string.h> 29#include <stdarg.h> 30 31#include "common/intel_gem.h" 32#include "util/macros.h" 33 34#include "aub_read.h" 35#include "intel_context.h" 36#include "intel_aub.h" 37 38#define TYPE(dw) (((dw) >> 29) & 7) 39#define OPCODE(dw) (((dw) >> 23) & 0x3f) 40#define SUBOPCODE(dw) (((dw) >> 16) & 0x7f) 41 42#define MAKE_HEADER(type, opcode, subopcode) \ 43 ((((unsigned) (type)) << 29) | ((opcode) << 23) | ((subopcode) << 16)) 44 45#define TYPE_AUB 0x7 46 47/* Classic AUB opcodes */ 48#define OPCODE_AUB 0x01 49#define SUBOPCODE_HEADER 0x05 50#define SUBOPCODE_BLOCK 0x41 51#define SUBOPCODE_BMP 0x1e 52 53/* Newer version AUB opcode */ 54#define OPCODE_NEW_AUB 0x2e 55#define SUBOPCODE_VERSION 0x00 56#define SUBOPCODE_REG_CMP 0x01 57#define SUBOPCODE_REG_POLL 0x02 58#define SUBOPCODE_REG_WRITE 0x03 59#define SUBOPCODE_MEM_CMP 0x04 60#define SUBOPCODE_MEM_POLL 0x05 61#define SUBOPCODE_MEM_WRITE 0x06 62#define SUBOPCODE_FRAME_BEGIN 0x07 63#define SUBOPCODE_COMMENT 0x08 64#define SUBOPCODE_TRACE_DELAY 0x09 65#define SUBOPCODE_MEM_DUMP 0x0a 66#define SUBOPCODE_MEM_WRITE_DISCONT 0x0b 67#define SUBOPCODE_TEST_PHASE_MARKER 0x0c 68#define SUBOPCODE_MEM_CONT_REGION 0x0d 69#define SUBOPCODE_VERSION_EXT 0x0e 70#define SUBOPCODE_PREDICATE 0x0f 71#define SUBOPCODE_DUMP_COMPRESS 0x10 72 73static PRINTFLIKE(3, 4) void 74parse_error(struct aub_read *read, const uint32_t *p, const char *fmt, ...) 75{ 76 if (!read->error) 77 return; 78 79 va_list ap; 80 va_start(ap, fmt); 81 82 char msg[80]; 83 vsnprintf(msg, sizeof(msg), fmt, ap); 84 read->error(read->user_data, p, msg); 85 86 va_end(ap); 87} 88 89static bool 90handle_trace_header(struct aub_read *read, const uint32_t *p) 91{ 92 /* The intel_aubdump tool from IGT is kind enough to put a PCI-ID= tag in 93 * the AUB header comment. If the user hasn't specified a hardware 94 * generation, try to use the one from the AUB file. 95 */ 96 const uint32_t *end = p + (p[0] & 0xffff) + 2; 97 int aub_pci_id = 0; 98 99 if (end > &p[12] && p[12] > 0) { 100 if (sscanf((char *)&p[13], "PCI-ID=%i", &aub_pci_id) > 0) { 101 if (!intel_get_device_info_from_pci_id(aub_pci_id, &read->devinfo)) { 102 parse_error(read, p, 103 "can't find device information: pci_id=0x%x\n", aub_pci_id); 104 return false; 105 } 106 } 107 } 108 109 char app_name[33]; 110 strncpy(app_name, (const char *)&p[2], 32); 111 app_name[32] = 0; 112 113 if (read->info) 114 read->info(read->user_data, aub_pci_id, app_name); 115 116 return true; 117} 118 119static bool 120handle_memtrace_version(struct aub_read *read, const uint32_t *p) 121{ 122 int header_length = p[0] & 0xffff; 123 char app_name[64]; 124 int app_name_len = MIN2(4 * (header_length + 1 - 5), ARRAY_SIZE(app_name) - 1); 125 int pci_id_len = 0; 126 int aub_pci_id = 0; 127 128 strncpy(app_name, (const char *)&p[5], app_name_len); 129 app_name[app_name_len] = 0; 130 131 if (sscanf(app_name, "PCI-ID=%i %n", &aub_pci_id, &pci_id_len) > 0) { 132 if (!intel_get_device_info_from_pci_id(aub_pci_id, &read->devinfo)) { 133 parse_error(read, p, "can't find device information: pci_id=0x%x\n", aub_pci_id); 134 return false; 135 } 136 137 if (read->info) 138 read->info(read->user_data, aub_pci_id, app_name + pci_id_len); 139 } 140 141 return true; 142} 143 144static bool 145handle_trace_block(struct aub_read *read, const uint32_t *p) 146{ 147 int operation = p[1] & AUB_TRACE_OPERATION_MASK; 148 int type = p[1] & AUB_TRACE_TYPE_MASK; 149 int address_space = p[1] & AUB_TRACE_ADDRESS_SPACE_MASK; 150 int header_length = p[0] & 0xffff; 151 enum drm_i915_gem_engine_class engine = I915_ENGINE_CLASS_RENDER; 152 const void *data = p + header_length + 2; 153 uint64_t address = intel_48b_address((read->devinfo.ver >= 8 ? ((uint64_t) p[5] << 32) : 0) | 154 ((uint64_t) p[3])); 155 uint32_t size = p[4]; 156 157 switch (operation) { 158 case AUB_TRACE_OP_DATA_WRITE: 159 if (address_space == AUB_TRACE_MEMTYPE_GTT) { 160 if (read->local_write) 161 read->local_write(read->user_data, address, data, size); 162 break; 163 case AUB_TRACE_OP_COMMAND_WRITE: 164 switch (type) { 165 case AUB_TRACE_TYPE_RING_PRB0: 166 engine = I915_ENGINE_CLASS_RENDER; 167 break; 168 case AUB_TRACE_TYPE_RING_PRB1: 169 engine = I915_ENGINE_CLASS_VIDEO; 170 break; 171 case AUB_TRACE_TYPE_RING_PRB2: 172 engine = I915_ENGINE_CLASS_COPY; 173 break; 174 default: 175 parse_error(read, p, "command write to unknown ring %d\n", type); 176 return false; 177 } 178 179 if (read->ring_write) 180 read->ring_write(read->user_data, engine, data, size); 181 break; 182 } 183 } 184 185 return true; 186} 187 188static void 189handle_memtrace_reg_write(struct aub_read *read, const uint32_t *p) 190{ 191 uint32_t offset = p[1]; 192 uint32_t value = p[5]; 193 194 if (read->reg_write) 195 read->reg_write(read->user_data, offset, value); 196 197 enum drm_i915_gem_engine_class engine; 198 uint64_t context_descriptor; 199 200 switch (offset) { 201 case RCSUNIT(EXECLIST_SUBMITPORT): /* render elsp */ 202 read->render_elsp[read->render_elsp_index++] = value; 203 if (read->render_elsp_index < 4) 204 return; 205 206 read->render_elsp_index = 0; 207 engine = I915_ENGINE_CLASS_RENDER; 208 context_descriptor = (uint64_t)read->render_elsp[2] << 32 | 209 read->render_elsp[3]; 210 break; 211 case VCSUNIT0(EXECLIST_SUBMITPORT): /* video elsp */ 212 read->video_elsp[read->video_elsp_index++] = value; 213 if (read->video_elsp_index < 4) 214 return; 215 216 read->video_elsp_index = 0; 217 engine = I915_ENGINE_CLASS_VIDEO; 218 context_descriptor = (uint64_t)read->video_elsp[2] << 32 | 219 read->video_elsp[3]; 220 break; 221 case BCSUNIT0(EXECLIST_SUBMITPORT): /* blitter elsp */ 222 read->blitter_elsp[read->blitter_elsp_index++] = value; 223 if (read->blitter_elsp_index < 4) 224 return; 225 226 read->blitter_elsp_index = 0; 227 engine = I915_ENGINE_CLASS_COPY; 228 context_descriptor = (uint64_t)read->blitter_elsp[2] << 32 | 229 read->blitter_elsp[3]; 230 break; 231 case RCSUNIT(EXECLIST_SQ_CONTENTS): /* render elsq0 lo */ 232 read->render_elsp[3] = value; 233 return; 234 case RCSUNIT(EXECLIST_SQ_CONTENTS) + 4: /* render elsq0 hi */ 235 read->render_elsp[2] = value; 236 return; 237 case VCSUNIT0(EXECLIST_SQ_CONTENTS): /* video elsq0 lo */ 238 read->video_elsp[3] = value; 239 return; 240 case VCSUNIT0(EXECLIST_SQ_CONTENTS) + 4: /* video elsq0 hi */ 241 read->video_elsp[2] = value; 242 return; 243 case BCSUNIT0(EXECLIST_SQ_CONTENTS): /* blitter elsq0 lo */ 244 read->blitter_elsp[3] = value; 245 return; 246 case BCSUNIT0(EXECLIST_SQ_CONTENTS) + 4: /* blitter elsq0 hi */ 247 read->blitter_elsp[2] = value; 248 return; 249 case RCSUNIT(EXECLIST_CONTROL): /* render elsc */ 250 engine = I915_ENGINE_CLASS_RENDER; 251 context_descriptor = (uint64_t)read->render_elsp[2] << 32 | 252 read->render_elsp[3]; 253 break; 254 case VCSUNIT0(EXECLIST_CONTROL): /* video_elsc */ 255 engine = I915_ENGINE_CLASS_VIDEO; 256 context_descriptor = (uint64_t)read->video_elsp[2] << 32 | 257 read->video_elsp[3]; 258 break; 259 case BCSUNIT0(EXECLIST_CONTROL): /* blitter elsc */ 260 engine = I915_ENGINE_CLASS_COPY; 261 context_descriptor = (uint64_t)read->blitter_elsp[2] << 32 | 262 read->blitter_elsp[3]; 263 break; 264 default: 265 return; 266 } 267 268 if (read->execlist_write) 269 read->execlist_write(read->user_data, engine, context_descriptor); 270} 271 272static void 273do_write(struct aub_read *read, uint32_t address_space, uint64_t addr, const void *data, uint32_t size) 274{ 275 if (0) 276 fprintf(stderr, "*0x%" PRIx64 " = *0x%p (%d)\n", addr, data, size); 277 278 switch (address_space) { 279 case 0: /* GGTT */ 280 if (read->ggtt_write) 281 read->ggtt_write(read->user_data, addr, data, size); 282 break; 283 case 1: /* Local */ 284 if (read->local_write) 285 read->local_write(read->user_data, addr, data, size); 286 break; 287 case 2: /* Physical */ 288 if (read->phys_write) 289 read->phys_write(read->user_data, addr, data, size); 290 break; 291 case 4: /* GGTT Entry */ 292 if (read->ggtt_entry_write) 293 read->ggtt_entry_write(read->user_data, addr, data, size); 294 break; 295 } 296} 297 298static void 299handle_memtrace_mem_write(struct aub_read *read, const uint32_t *p) 300{ 301 const void *data = p + 5; 302 uint64_t addr = intel_48b_address(*(uint64_t*)&p[1]); 303 uint32_t size = p[4]; 304 uint32_t address_space = p[3] >> 28; 305 306 do_write(read, address_space, addr, data, size); 307} 308 309static void 310handle_memtrace_mem_write_discont(struct aub_read *read, const uint32_t *p) 311{ 312 uint32_t address_space = p[1] >> 28; 313 const struct { 314 uint64_t address; 315 uint32_t size; 316 } __attribute__((packed)) *cur = (const void *)(p + 2); 317 const void *data = p + 2 + 3 * 63; 318 319 for (unsigned i = 0; i < 63; ++i, ++cur) { 320 uint64_t addr = intel_48b_address(cur->address); 321 uint32_t size = cur->size; 322 323 if (size == 0) 324 continue; 325 326 do_write(read, address_space, addr, data, size); 327 } 328} 329 330int 331aub_read_command(struct aub_read *read, const void *data, uint32_t data_len) 332{ 333 const uint32_t *p = data, *next; 334 ASSERTED const uint32_t *end = data + data_len; 335 uint32_t h, header_length, bias; 336 337 assert(data_len >= 4); 338 339 h = *p; 340 header_length = h & 0xffff; 341 342 switch (OPCODE(h)) { 343 case OPCODE_AUB: 344 bias = 2; 345 break; 346 case OPCODE_NEW_AUB: 347 bias = 1; 348 break; 349 default: 350 parse_error(read, data, "unknown opcode %d\n", OPCODE(h)); 351 return -1; 352 } 353 354 next = p + header_length + bias; 355 if ((h & 0xffff0000) == MAKE_HEADER(TYPE_AUB, OPCODE_AUB, SUBOPCODE_BLOCK)) { 356 assert(end - p >= 4); 357 next += p[4] / 4; 358 } 359 360 if (next > end) { 361 parse_error(read, data, 362 "input ends unexpectedly (command length: %zu, remaining bytes: %zu)\n", 363 (uintptr_t)next - (uintptr_t)data, 364 (uintptr_t)end - (uintptr_t)data); 365 return -1; 366 } 367 368 if (0) { 369 fprintf(stderr, "0x%x, 0x%x, 0x%x, len: %d\n", 370 TYPE(h), OPCODE(h), SUBOPCODE(h), header_length); 371 for (const uint32_t *cur = p; cur < next; ++cur) 372 fprintf(stderr, "0x%08x ", *cur); 373 fprintf(stderr, "\n"); 374 } 375 376 switch (h & 0xffff0000) { 377 case MAKE_HEADER(TYPE_AUB, OPCODE_AUB, SUBOPCODE_HEADER): 378 if (!handle_trace_header(read, p)) 379 return -1; 380 break; 381 case MAKE_HEADER(TYPE_AUB, OPCODE_AUB, SUBOPCODE_BLOCK): 382 if (!handle_trace_block(read, p)) 383 return -1; 384 break; 385 case MAKE_HEADER(TYPE_AUB, OPCODE_AUB, SUBOPCODE_BMP): 386 break; 387 case MAKE_HEADER(TYPE_AUB, OPCODE_NEW_AUB, SUBOPCODE_VERSION_EXT): 388 if (!handle_memtrace_version(read, p)) 389 return -1; 390 break; 391 case MAKE_HEADER(TYPE_AUB, OPCODE_NEW_AUB, SUBOPCODE_REG_WRITE): 392 handle_memtrace_reg_write(read, p); 393 break; 394 case MAKE_HEADER(TYPE_AUB, OPCODE_NEW_AUB, SUBOPCODE_MEM_WRITE): 395 handle_memtrace_mem_write(read, p); 396 break; 397 case MAKE_HEADER(TYPE_AUB, OPCODE_NEW_AUB, SUBOPCODE_MEM_POLL): 398 /* fprintf(outfile, "memory poll block (dwords %d):\n", h & 0xffff); */ 399 break; 400 case MAKE_HEADER(TYPE_AUB, OPCODE_NEW_AUB, SUBOPCODE_REG_POLL): 401 break; 402 case MAKE_HEADER(TYPE_AUB, OPCODE_NEW_AUB, SUBOPCODE_COMMENT): 403 if (read->comment) 404 read->comment(read->user_data, (const char *)(p + 2)); 405 break; 406 case MAKE_HEADER(TYPE_AUB, OPCODE_NEW_AUB, SUBOPCODE_MEM_WRITE_DISCONT): 407 handle_memtrace_mem_write_discont(read, p); 408 break; 409 case MAKE_HEADER(TYPE_AUB, OPCODE_NEW_AUB, SUBOPCODE_VERSION): 410 case MAKE_HEADER(TYPE_AUB, OPCODE_NEW_AUB, SUBOPCODE_REG_CMP): 411 case MAKE_HEADER(TYPE_AUB, OPCODE_NEW_AUB, SUBOPCODE_MEM_CMP): 412 case MAKE_HEADER(TYPE_AUB, OPCODE_NEW_AUB, SUBOPCODE_FRAME_BEGIN): 413 case MAKE_HEADER(TYPE_AUB, OPCODE_NEW_AUB, SUBOPCODE_TRACE_DELAY): 414 case MAKE_HEADER(TYPE_AUB, OPCODE_NEW_AUB, SUBOPCODE_MEM_DUMP): 415 case MAKE_HEADER(TYPE_AUB, OPCODE_NEW_AUB, SUBOPCODE_TEST_PHASE_MARKER): 416 case MAKE_HEADER(TYPE_AUB, OPCODE_NEW_AUB, SUBOPCODE_MEM_CONT_REGION): 417 case MAKE_HEADER(TYPE_AUB, OPCODE_NEW_AUB, SUBOPCODE_PREDICATE): 418 case MAKE_HEADER(TYPE_AUB, OPCODE_NEW_AUB, SUBOPCODE_DUMP_COMPRESS): 419 default: 420 parse_error(read, p, 421 "unknown block type=0x%x, opcode=0x%x, subopcode=0x%x (%08x)\n", 422 TYPE(h), OPCODE(h), SUBOPCODE(h), h); 423 return -1; 424 } 425 426 return (next - p) * sizeof(*p); 427} 428