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