2 * Copyright © 2018 Intel Corporation
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:
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
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
34 #include "aub_write.h"
36 #include "intel_aub.h"
38 static void __attribute__ ((format(__printf__
, 2, 3)))
39 fail_if(int cond
, const char *format
, ...)
46 va_start(args
, format
);
47 vfprintf(stderr
, format
, args
);
53 #define fail(...) fail_if(true, __VA_ARGS__)
55 static int zlib_inflate(uint32_t **ptr
, int len
)
57 struct z_stream_s zstream
;
59 const uint32_t out_size
= 128*4096; /* approximate obj size */
61 memset(&zstream
, 0, sizeof(zstream
));
63 zstream
.next_in
= (unsigned char *)*ptr
;
64 zstream
.avail_in
= 4*len
;
66 if (inflateInit(&zstream
) != Z_OK
)
69 out
= malloc(out_size
);
70 zstream
.next_out
= out
;
71 zstream
.avail_out
= out_size
;
74 switch (inflate(&zstream
, Z_SYNC_FLUSH
)) {
84 if (zstream
.avail_out
)
87 out
= realloc(out
, 2*zstream
.total_out
);
93 zstream
.next_out
= (unsigned char *)out
+ zstream
.total_out
;
94 zstream
.avail_out
= zstream
.total_out
;
100 return zstream
.total_out
/ 4;
103 static int ascii85_decode(const char *in
, uint32_t **out
, bool inflate
)
105 int len
= 0, size
= 1024;
107 *out
= realloc(*out
, sizeof(uint32_t)*size
);
111 while (*in
>= '!' && *in
<= 'z') {
116 *out
= realloc(*out
, sizeof(uint32_t)*size
);
124 v
+= in
[0] - 33; v
*= 85;
125 v
+= in
[1] - 33; v
*= 85;
126 v
+= in
[2] - 33; v
*= 85;
127 v
+= in
[3] - 33; v
*= 85;
137 return zlib_inflate(out
, len
);
141 print_help(const char *progname
, FILE *file
)
144 "Usage: %s [OPTION]... [FILE]\n"
145 "Convert an Intel GPU i915 error state to an aub file.\n"
146 " -h, --help display this help and exit\n"
147 " -o, --output=FILE the output aub file (default FILE.aub)\n",
152 main(int argc
, char *argv
[])
156 char *out_filename
= NULL
, *in_filename
= NULL
;
157 const struct option aubinator_opts
[] = {
158 { "help", no_argument
, NULL
, 'h' },
159 { "output", required_argument
, NULL
, 'o' },
164 while ((c
= getopt_long(argc
, argv
, "ho:", aubinator_opts
, &i
)) != -1) {
170 out_filename
= strdup(optarg
);
178 in_filename
= argv
[optind
++];
180 if (help
|| argc
== 1 || !in_filename
) {
181 print_help(argv
[0], stderr
);
182 return in_filename
? EXIT_SUCCESS
: EXIT_FAILURE
;
185 if (out_filename
== NULL
) {
186 int out_filename_size
= strlen(in_filename
) + 5;
187 out_filename
= malloc(out_filename_size
);
188 snprintf(out_filename
, out_filename_size
, "%s.aub", in_filename
);
191 FILE *err_file
= fopen(in_filename
, "r");
192 fail_if(!err_file
, "Failed to open error file \"%s\": %m\n", in_filename
);
194 FILE *aub_file
= fopen(out_filename
, "w");
195 fail_if(!aub_file
, "Failed to open aub file \"%s\": %m\n", in_filename
);
197 struct aub_file aub
= {};
199 uint32_t active_ring
= 0;
200 int num_ring_bos
= 0;
202 uint64_t batch_addr
= 0;
213 while (getline(&line
, &line_size
, err_file
) > 0) {
214 const char *pci_id_start
= strstr(line
, "PCI ID");
217 int matched
= sscanf(line
, "PCI ID: 0x%04x\n", &pci_id
);
218 fail_if(!matched
, "Invalid error state file!\n");
220 aub_file_init(&aub
, aub_file
, pci_id
);
221 fail_if(!aub_use_execlists(&aub
),
222 "%s currently only works on gen8+\n", argv
[0]);
224 aub_write_header(&aub
, "error state");
228 const char *active_start
= "Active (";
229 if (strncmp(line
, active_start
, strlen(active_start
)) == 0) {
230 fail_if(active_ring
!= 0, "TODO: Handle multiple active rings\n");
232 char *ring
= line
+ strlen(active_start
);
238 { "rcs", I915_EXEC_RENDER
},
239 { "vcs", I915_EXEC_VEBOX
},
240 { "bcs", I915_EXEC_BLT
},
241 { NULL
, BO_TYPE_UNKNOWN
},
244 for (r
= rings
; r
->match
; r
++) {
245 if (strncasecmp(ring
, r
->match
, strlen(r
->match
)) == 0) {
246 active_ring
= r
->ring
;
251 char *count
= strchr(ring
, '[');
252 fail_if(!count
|| sscanf(count
, "[%d]:", &num_ring_bos
) < 1,
253 "Failed to parse BO table header\n");
257 if (num_ring_bos
> 0) {
258 unsigned hi
, lo
, size
;
259 if (sscanf(line
, " %x_%x %d", &hi
, &lo
, &size
) == 3) {
260 assert(aub_use_execlists(&aub
));
261 aub_map_ppgtt(&aub
, ((uint64_t)hi
) << 32 | lo
, size
);
264 fail("Not enough BO entries in the active table\n");
269 if (line
[0] == ':' || line
[0] == '~') {
270 if (bo_type
== BO_TYPE_UNKNOWN
)
273 uint32_t *data
= NULL
;
274 int count
= ascii85_decode(line
+1, &data
, line
[0] == ':');
275 fail_if(count
== 0, "ASCII85 decode failed.\n");
276 uint64_t bo_size
= count
* 4;
278 if (bo_type
== BO_TYPE_BATCH
) {
279 aub_write_trace_block(&aub
, AUB_TRACE_TYPE_BATCH
,
280 data
, bo_size
, bo_addr
);
281 batch_addr
= bo_addr
;
283 assert(bo_type
== BO_TYPE_USER
);
284 aub_write_trace_block(&aub
, AUB_TRACE_TYPE_NOTYPE
,
285 data
, bo_size
, bo_addr
);
291 char *dashes
= strstr(line
, "---");
299 { "gtt_offset", BO_TYPE_BATCH
},
300 { "user", BO_TYPE_USER
},
301 { NULL
, BO_TYPE_UNKNOWN
},
304 bo_type
= BO_TYPE_UNKNOWN
;
305 for (b
= bo_types
; b
->match
; b
++) {
306 if (strncasecmp(dashes
, b
->match
, strlen(b
->match
)) == 0) {
312 if (bo_type
!= BO_TYPE_UNKNOWN
) {
314 dashes
= strchr(dashes
, '=');
315 if (dashes
&& sscanf(dashes
, "= 0x%08x %08x\n", &hi
, &lo
) == 2) {
316 bo_addr
= ((uint64_t) hi
) << 32 | lo
;
318 fail("User BO does not have an address\n");
325 fail_if(!batch_addr
, "Failed to find batch buffer.\n");
327 aub_write_exec(&aub
, batch_addr
, aub_gtt_size(&aub
), I915_EXEC_RENDER
);
332 /* vim: set ts=8 sw=8 tw=0 cino=:0,(0 noet :*/