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                   (((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
62static void
63parse_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
78static bool
79handle_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(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
108static bool
109handle_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(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
133static bool
134handle_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
177static void
178handle_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
261static void
262handle_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
289int
290aub_read_command(struct aub_read *read, const void *data, uint32_t data_len)
291{
292   const uint32_t *p = data, *next;
293   MAYBE_UNUSED 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