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