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 ((((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 #define MAKE_GEN(major, minor) (((major) << 8) | (minor))
61
62 static void
parse_error(struct aub_read * read,const uint32_t * p,const char * fmt,...)63 parse_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
78 static bool
handle_trace_header(struct aub_read * read,const uint32_t * p)79 handle_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_from_pci_id(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
108 static bool
handle_memtrace_version(struct aub_read * read,const uint32_t * p)109 handle_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_from_pci_id(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
133 static bool
handle_trace_block(struct aub_read * read,const uint32_t * p)134 handle_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
177 static void
handle_memtrace_reg_write(struct aub_read * read,const uint32_t * p)178 handle_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
261 static void
handle_memtrace_mem_write(struct aub_read * read,const uint32_t * p)262 handle_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
289 int
aub_read_command(struct aub_read * read,const void * data,uint32_t data_len)290 aub_read_command(struct aub_read *read, const void *data, uint32_t data_len)
291 {
292 const uint32_t *p = data, *next;
293 ASSERTED 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