xref: /third_party/mesa3d/src/intel/tools/aub_read.c (revision bf215546)
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