• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
73 static PRINTFLIKE(3, 4) void
parse_error(struct aub_read * read,const uint32_t * p,const char * fmt,...)74 parse_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 
89 static bool
handle_trace_header(struct aub_read * read,const uint32_t * p)90 handle_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 
119 static bool
handle_memtrace_version(struct aub_read * read,const uint32_t * p)120 handle_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 
144 static bool
handle_trace_block(struct aub_read * read,const uint32_t * p)145 handle_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 
188 static void
handle_memtrace_reg_write(struct aub_read * read,const uint32_t * p)189 handle_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 
272 static void
do_write(struct aub_read * read,uint32_t address_space,uint64_t addr,const void * data,uint32_t size)273 do_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 
298 static void
handle_memtrace_mem_write(struct aub_read * read,const uint32_t * p)299 handle_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 
309 static void
handle_memtrace_mem_write_discont(struct aub_read * read,const uint32_t * p)310 handle_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 
330 int
aub_read_command(struct aub_read * read,const void * data,uint32_t data_len)331 aub_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