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