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 
60 static PRINTFLIKE(3, 4) void
parse_error(struct aub_read * read,const uint32_t * p,const char * fmt,...)61 parse_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 
76 static bool
handle_trace_header(struct aub_read * read,const uint32_t * p)77 handle_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 
106 static bool
handle_memtrace_version(struct aub_read * read,const uint32_t * p)107 handle_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 
131 static bool
handle_trace_block(struct aub_read * read,const uint32_t * p)132 handle_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 
175 static void
handle_memtrace_reg_write(struct aub_read * read,const uint32_t * p)176 handle_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 
259 static void
handle_memtrace_mem_write(struct aub_read * read,const uint32_t * p)260 handle_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 
287 int
aub_read_command(struct aub_read * read,const void * data,uint32_t data_len)288 aub_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