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
60static PRINTFLIKE(3, 4) void
61parse_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
76static bool
77handle_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
106static bool
107handle_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
131static bool
132handle_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
175static void
176handle_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
259static void
260handle_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
287int
288aub_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