error2aub.c revision 01e04c3f
1/*
2 * Copyright © 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 <assert.h>
26#include <getopt.h>
27#include <inttypes.h>
28#include <signal.h>
29#include <stdio.h>
30#include <stdlib.h>
31#include <string.h>
32#include <stdarg.h>
33#include <zlib.h>
34
35#include "aub_write.h"
36#include "i915_drm.h"
37#include "intel_aub.h"
38
39static void __attribute__ ((format(__printf__, 2, 3)))
40fail_if(int cond, const char *format, ...)
41{
42   va_list args;
43
44   if (!cond)
45      return;
46
47   va_start(args, format);
48   vfprintf(stderr, format, args);
49   va_end(args);
50
51   raise(SIGTRAP);
52}
53
54#define fail(...) fail_if(true, __VA_ARGS__)
55
56static int zlib_inflate(uint32_t **ptr, int len)
57{
58   struct z_stream_s zstream;
59   void *out;
60   const uint32_t out_size = 128*4096;  /* approximate obj size */
61
62   memset(&zstream, 0, sizeof(zstream));
63
64   zstream.next_in = (unsigned char *)*ptr;
65   zstream.avail_in = 4*len;
66
67   if (inflateInit(&zstream) != Z_OK)
68      return 0;
69
70   out = malloc(out_size);
71   zstream.next_out = out;
72   zstream.avail_out = out_size;
73
74   do {
75      switch (inflate(&zstream, Z_SYNC_FLUSH)) {
76      case Z_STREAM_END:
77         goto end;
78      case Z_OK:
79         break;
80      default:
81         inflateEnd(&zstream);
82         return 0;
83      }
84
85      if (zstream.avail_out)
86         break;
87
88      out = realloc(out, 2*zstream.total_out);
89      if (out == NULL) {
90         inflateEnd(&zstream);
91         return 0;
92      }
93
94      zstream.next_out = (unsigned char *)out + zstream.total_out;
95      zstream.avail_out = zstream.total_out;
96   } while (1);
97 end:
98   inflateEnd(&zstream);
99   free(*ptr);
100   *ptr = out;
101   return zstream.total_out / 4;
102}
103
104static int ascii85_decode(const char *in, uint32_t **out, bool inflate)
105{
106   int len = 0, size = 1024;
107
108   *out = realloc(*out, sizeof(uint32_t)*size);
109   if (*out == NULL)
110      return 0;
111
112   while (*in >= '!' && *in <= 'z') {
113      uint32_t v = 0;
114
115      if (len == size) {
116         size *= 2;
117         *out = realloc(*out, sizeof(uint32_t)*size);
118         if (*out == NULL)
119            return 0;
120      }
121
122      if (*in == 'z') {
123         in++;
124      } else {
125         v += in[0] - 33; v *= 85;
126         v += in[1] - 33; v *= 85;
127         v += in[2] - 33; v *= 85;
128         v += in[3] - 33; v *= 85;
129         v += in[4] - 33;
130         in += 5;
131      }
132      (*out)[len++] = v;
133   }
134
135   if (!inflate)
136      return len;
137
138   return zlib_inflate(out, len);
139}
140
141static void
142print_help(const char *progname, FILE *file)
143{
144   fprintf(file,
145           "Usage: %s [OPTION]... [FILE]\n"
146           "Convert an Intel GPU i915 error state to an aub file.\n"
147           "  -h, --help          display this help and exit\n"
148           "  -o, --output=FILE   the output aub file (default FILE.aub)\n",
149           progname);
150}
151
152int
153main(int argc, char *argv[])
154{
155   int i, c;
156   bool help = false;
157   char *out_filename = NULL, *in_filename = NULL;
158   const struct option aubinator_opts[] = {
159      { "help",       no_argument,       NULL,     'h' },
160      { "output",     required_argument, NULL,     'o' },
161      { NULL,         0,                 NULL,     0 }
162   };
163
164   i = 0;
165   while ((c = getopt_long(argc, argv, "ho:", aubinator_opts, &i)) != -1) {
166      switch (c) {
167      case 'h':
168         help = true;
169         break;
170      case 'o':
171         out_filename = strdup(optarg);
172         break;
173      default:
174         break;
175      }
176   }
177
178   if (optind < argc)
179      in_filename = argv[optind++];
180
181   if (help || argc == 1 || !in_filename) {
182      print_help(argv[0], stderr);
183      return in_filename ? EXIT_SUCCESS : EXIT_FAILURE;
184   }
185
186   if (out_filename == NULL) {
187      int out_filename_size = strlen(in_filename) + 5;
188      out_filename = malloc(out_filename_size);
189      snprintf(out_filename, out_filename_size, "%s.aub", in_filename);
190   }
191
192   FILE *err_file = fopen(in_filename, "r");
193   fail_if(!err_file, "Failed to open error file \"%s\": %m\n", in_filename);
194
195   FILE *aub_file = fopen(out_filename, "w");
196   fail_if(!aub_file, "Failed to open aub file \"%s\": %m\n", in_filename);
197
198   struct aub_file aub = {};
199
200   uint32_t active_ring = 0;
201   int num_ring_bos = 0;
202
203   uint64_t batch_addr = 0;
204
205   enum bo_type {
206      BO_TYPE_UNKNOWN = 0,
207      BO_TYPE_BATCH,
208      BO_TYPE_USER,
209   } bo_type = BO_TYPE_UNKNOWN;
210   uint64_t bo_addr = 0;
211
212   char *line = NULL;
213   size_t line_size;
214   while (getline(&line, &line_size, err_file) > 0) {
215      const char *pci_id_start = strstr(line, "PCI ID");
216      if (pci_id_start) {
217         int pci_id;
218         int matched = sscanf(line, "PCI ID: 0x%04x\n", &pci_id);
219         fail_if(!matched, "Invalid error state file!\n");
220
221         aub_file_init(&aub, aub_file, pci_id);
222         fail_if(!aub_use_execlists(&aub),
223                 "%s currently only works on gen8+\n", argv[0]);
224
225         aub_write_header(&aub, "error state");
226         continue;
227      }
228
229      const char *active_start = "Active (";
230      if (strncmp(line, active_start, strlen(active_start)) == 0) {
231         fail_if(active_ring != 0, "TODO: Handle multiple active rings\n");
232
233         char *ring = line + strlen(active_start);
234
235         const struct {
236            const char *match;
237            uint32_t ring;
238         } rings[] = {
239            { "rcs", I915_EXEC_RENDER },
240            { "vcs", I915_EXEC_VEBOX },
241            { "bcs", I915_EXEC_BLT },
242            { NULL, BO_TYPE_UNKNOWN },
243         }, *r;
244
245         for (r = rings; r->match; r++) {
246            if (strncasecmp(ring, r->match, strlen(r->match)) == 0) {
247               active_ring = r->ring;
248               break;
249            }
250         }
251
252         char *count = strchr(ring, '[');
253         fail_if(!count || sscanf(count, "[%d]:", &num_ring_bos) < 1,
254                 "Failed to parse BO table header\n");
255         continue;
256      }
257
258      if (num_ring_bos > 0) {
259         unsigned hi, lo, size;
260         if (sscanf(line, " %x_%x %d", &hi, &lo, &size) == 3) {
261            assert(aub_use_execlists(&aub));
262            aub_map_ppgtt(&aub, ((uint64_t)hi) << 32 | lo, size);
263            num_ring_bos--;
264         } else {
265            fail("Not enough BO entries in the active table\n");
266         }
267         continue;
268      }
269
270      if (line[0] == ':' || line[0] == '~') {
271         if (bo_type == BO_TYPE_UNKNOWN)
272            continue;
273
274         uint32_t *data = NULL;
275         int count = ascii85_decode(line+1, &data, line[0] == ':');
276         fail_if(count == 0, "ASCII85 decode failed.\n");
277         uint64_t bo_size = count * 4;
278
279         if (bo_type == BO_TYPE_BATCH) {
280            aub_write_trace_block(&aub, AUB_TRACE_TYPE_BATCH,
281                                  data, bo_size, bo_addr);
282            batch_addr = bo_addr;
283         } else {
284            assert(bo_type == BO_TYPE_USER);
285            aub_write_trace_block(&aub, AUB_TRACE_TYPE_NOTYPE,
286                                  data, bo_size, bo_addr);
287         }
288
289         continue;
290      }
291
292      char *dashes = strstr(line, "---");
293      if (dashes) {
294         dashes += 4;
295
296         const struct {
297            const char *match;
298            enum bo_type type;
299         } bo_types[] = {
300            { "gtt_offset", BO_TYPE_BATCH },
301            { "user", BO_TYPE_USER },
302            { NULL, BO_TYPE_UNKNOWN },
303         }, *b;
304
305         bo_type = BO_TYPE_UNKNOWN;
306         for (b = bo_types; b->match; b++) {
307            if (strncasecmp(dashes, b->match, strlen(b->match)) == 0) {
308               bo_type = b->type;
309               break;
310            }
311         }
312
313         if (bo_type != BO_TYPE_UNKNOWN) {
314            uint32_t hi, lo;
315            dashes = strchr(dashes, '=');
316            if (dashes && sscanf(dashes, "= 0x%08x %08x\n", &hi, &lo) == 2) {
317               bo_addr = ((uint64_t) hi) << 32 | lo;
318            } else {
319               fail("User BO does not have an address\n");
320            }
321         }
322         continue;
323      }
324   }
325
326   fail_if(!batch_addr, "Failed to find batch buffer.\n");
327
328   aub_write_exec(&aub, batch_addr, aub_gtt_size(&aub), I915_EXEC_RENDER);
329
330   free(out_filename);
331   free(line);
332   if(err_file) {
333      fclose(err_file);
334   }
335   if(aub.file) {
336      aub_file_finish(&aub);
337   } else if(aub_file) {
338      fclose(aub_file);
339   }
340   return EXIT_SUCCESS;
341}
342
343/* vim: set ts=8 sw=8 tw=0 cino=:0,(0 noet :*/
344