1 /*
2 * Copyright © 2022 Igalia S.L.
3 * SPDX-License-Identifier: MIT
4 */
5
6 #include <assert.h>
7 #include <ctype.h>
8 #include <err.h>
9 #include <errno.h>
10 #include <fcntl.h>
11 #include <getopt.h>
12 #include <signal.h>
13 #include <stdarg.h>
14 #include <stdbool.h>
15 #include <stdint.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <unistd.h>
20 #include <sys/mman.h>
21 #include <sys/stat.h>
22 #include <sys/types.h>
23 #include <sys/wait.h>
24
25 #include "util/u_math.h"
26
27 #include "adreno_common.xml.h"
28 #include "adreno_pm4.xml.h"
29 #include "freedreno_pm4.h"
30
31 #include "a6xx.xml.h"
32 #include "common/freedreno_dev_info.h"
33
34 #include "util/hash_table.h"
35 #include "util/os_time.h"
36 #include "util/ralloc.h"
37 #include "util/rb_tree.h"
38 #include "util/set.h"
39 #include "util/u_vector.h"
40 #include "buffers.h"
41 #include "cffdec.h"
42 #include "disasm.h"
43 #include "io.h"
44 #include "rdutil.h"
45 #include "redump.h"
46 #include "rnnutil.h"
47
48 /* Decompiles a single cmdstream from .rd into compilable C source.
49 * C source could be compiled using rdcompiler-meson.build as an example.
50 *
51 * For how-to see freedreno.rst
52 */
53
54 static int handle_file(const char *filename, uint32_t submit_to_decompile);
55
56 static const char *levels[] = {
57 "\t",
58 "\t\t",
59 "\t\t\t",
60 "\t\t\t\t",
61 "\t\t\t\t\t",
62 "\t\t\t\t\t\t",
63 "\t\t\t\t\t\t\t",
64 "\t\t\t\t\t\t\t\t",
65 "\t\t\t\t\t\t\t\t\t",
66 };
67
68 static void
printlvl(int lvl,const char * fmt,...)69 printlvl(int lvl, const char *fmt, ...)
70 {
71 assert(lvl < ARRAY_SIZE(levels));
72
73 va_list args;
74 va_start(args, fmt);
75 fputs(levels[lvl], stdout);
76 vprintf(fmt, args);
77 va_end(args);
78 }
79
80 static void
print_usage(const char * name)81 print_usage(const char *name)
82 {
83 /* clang-format off */
84 fprintf(stderr, "Usage:\n\n"
85 "\t%s [OPTIONS]... FILE...\n\n"
86 "Options:\n"
87 "\t-s, --submit=№ - № of the submit to decompile\n"
88 "\t--no-reg-bunch - Use pkt4 for each reg in CP_CONTEXT_REG_BUNCH\n"
89 "\t-h, --help - show this message\n"
90 , name);
91 /* clang-format on */
92 exit(2);
93 }
94
95 struct decompiler_options {
96 int no_reg_bunch;
97 };
98
99 static struct decompiler_options options = {};
100
101 /* clang-format off */
102 static const struct option opts[] = {
103 { "submit", required_argument, 0, 's' },
104 { "no-reg-bunch", no_argument, &options.no_reg_bunch, 1 },
105 { "help", no_argument, 0, 'h' },
106 };
107 /* clang-format on */
108
109 int
main(int argc,char ** argv)110 main(int argc, char **argv)
111 {
112 int ret = -1;
113 int c;
114 uint32_t submit_to_decompile = -1;
115
116 while ((c = getopt_long(argc, argv, "s:h", opts, NULL)) != -1) {
117 switch (c) {
118 case 0:
119 /* option that set a flag, nothing to do */
120 break;
121 case 's':
122 submit_to_decompile = strtoul(optarg, NULL, 0);
123 break;
124 case 'h':
125 default:
126 print_usage(argv[0]);
127 }
128 }
129
130 if (submit_to_decompile == -1) {
131 fprintf(stderr, "Submit to decompile has to be specified\n");
132 print_usage(argv[0]);
133 }
134
135 while (optind < argc) {
136 ret = handle_file(argv[optind], submit_to_decompile);
137 if (ret) {
138 fprintf(stderr, "error reading: %s\n", argv[optind]);
139 break;
140 }
141 optind++;
142 }
143
144 if (ret)
145 print_usage(argv[0]);
146
147 return ret;
148 }
149
150 static struct rnn *rnn;
151 static struct fd_dev_id dev_id;
152 static void *mem_ctx;
153
154 static struct set decompiled_shaders;
155
156 static void
init_rnn(const char * gpuname)157 init_rnn(const char *gpuname)
158 {
159 rnn = rnn_new(true);
160 rnn_load(rnn, gpuname);
161 }
162
163 const char *
pktname(unsigned opc)164 pktname(unsigned opc)
165 {
166 return rnn_enumname(rnn, "adreno_pm4_type3_packets", opc);
167 }
168
169 static uint32_t
decompile_shader(const char * name,uint32_t regbase,uint32_t * dwords,int level)170 decompile_shader(const char *name, uint32_t regbase, uint32_t *dwords, int level)
171 {
172 uint64_t gpuaddr = ((uint64_t)dwords[1] << 32) | dwords[0];
173 gpuaddr &= 0xfffffffffffffff0;
174
175 /* Shader's iova is referenced in two places, so we have to remember it. */
176 if (_mesa_set_search(&decompiled_shaders, &gpuaddr)) {
177 printlvl(level, "emit_shader_iova(&ctx, cs, 0x%" PRIx64 ");\n", gpuaddr);
178 } else {
179 uint64_t *key = ralloc(mem_ctx, uint64_t);
180 *key = gpuaddr;
181 _mesa_set_add(&decompiled_shaders, key);
182
183 void *buf = hostptr(gpuaddr);
184 assert(buf);
185
186 uint32_t sizedwords = hostlen(gpuaddr) / 4;
187
188 char *stream_data = NULL;
189 size_t stream_size = 0;
190 FILE *stream = open_memstream(&stream_data, &stream_size);
191
192 try_disasm_a3xx(buf, sizedwords, 0, stream, fd_dev_gen(&dev_id) * 100);
193 fclose(stream);
194
195 printlvl(level, "{\n");
196 printlvl(level + 1, "const char *source = R\"(\n");
197 printf("%s", stream_data);
198 printlvl(level + 1, ")\";\n");
199 printlvl(level + 1, "upload_shader(&ctx, 0x%" PRIx64 ", source);\n", gpuaddr);
200 printlvl(level + 1, "emit_shader_iova(&ctx, cs, 0x%" PRIx64 ");\n", gpuaddr);
201 printlvl(level, "}\n");
202 free(stream_data);
203 }
204
205 return 2;
206 }
207
208 static struct {
209 uint32_t regbase;
210 uint32_t (*fxn)(const char *name, uint32_t regbase, uint32_t *dwords, int level);
211 } reg_a6xx[] = {
212 {REG_A6XX_SP_VS_OBJ_START, decompile_shader},
213 {REG_A6XX_SP_HS_OBJ_START, decompile_shader},
214 {REG_A6XX_SP_DS_OBJ_START, decompile_shader},
215 {REG_A6XX_SP_GS_OBJ_START, decompile_shader},
216 {REG_A6XX_SP_FS_OBJ_START, decompile_shader},
217 {REG_A6XX_SP_CS_OBJ_START, decompile_shader},
218
219 {0, NULL},
220 }, *type0_reg;
221
222 static uint32_t
decompile_register(uint32_t regbase,uint32_t * dwords,uint16_t cnt,int level)223 decompile_register(uint32_t regbase, uint32_t *dwords, uint16_t cnt, int level)
224 {
225 struct rnndecaddrinfo *info = rnn_reginfo(rnn, regbase);
226
227 for (unsigned idx = 0; type0_reg[idx].regbase; idx++) {
228 if (type0_reg[idx].regbase == regbase) {
229 return type0_reg[idx].fxn(info->name, regbase, dwords, level);
230 }
231 }
232
233 const uint32_t dword = *dwords;
234
235 if (info && info->typeinfo) {
236 char *decoded = rnndec_decodeval(rnn->vc, info->typeinfo, dword);
237 printlvl(level, "/* pkt4: %s = %s */\n", info->name, decoded);
238
239 if (cnt == 0) {
240 printlvl(level, "pkt(cs, 0x%x);\n", dword);
241 } else {
242 #if 0
243 char reg_name[33];
244 char field_name[33];
245 char reg_idx[33];
246
247 /* reginfo doesn't return reg name in a compilable format, for now just
248 * parse it into a compilable reg name.
249 * TODO: Make RNN optionally return compilable reg name.
250 */
251 if (sscanf(info->name, "%32[A-Z0-6_][%32[x0-9]].%32s", reg_name,
252 reg_idx, field_name) != 3) {
253 printlvl(level, "pkt4(cs, REG_%s_%s, (%u), %u);\n", rnn->variant,
254 info->name, cnt, dword);
255 } else {
256 printlvl(level, "pkt4(cs, REG_%s_%s_%s(%s), (%u), %u);\n",
257 rnn->variant, reg_name, field_name, reg_idx, cnt, dword);
258 }
259 #else
260 /* TODO: We don't have easy way to get chip generation prefix,
261 * so just emit raw packet offset as a workaround.
262 */
263 printlvl(level, "pkt4(cs, 0x%04x, (%u), 0x%x);\n", regbase, cnt, dword);
264 #endif
265 }
266 } else {
267 printlvl(level, "/* unknown pkt4 */\n");
268 printlvl(level, "pkt4(cs, 0x%04x, (%u), 0x%x);\n", regbase, 1, dword);
269 }
270
271 rnn_reginfo_free(info);
272
273 return 1;
274 }
275
276 static uint32_t
decompile_register_reg_bunch(uint32_t regbase,uint32_t * dwords,uint16_t cnt,int level)277 decompile_register_reg_bunch(uint32_t regbase, uint32_t *dwords, uint16_t cnt, int level)
278 {
279 struct rnndecaddrinfo *info = rnn_reginfo(rnn, regbase);
280 const uint32_t dword = *dwords;
281
282 if (info && info->typeinfo) {
283 char *decoded = rnndec_decodeval(rnn->vc, info->typeinfo, dword);
284 printlvl(level, "/* reg: %s = %s */\n", info->name, decoded);
285 } else {
286 printlvl(level, "/* unknown pkt4 */\n");
287 }
288
289 printlvl(level, "pkt(cs, 0x%04x);\n", regbase);
290 printlvl(level, "pkt(cs, 0x%x);\n", dword);
291
292 rnn_reginfo_free(info);
293
294 return 1;
295 }
296
297 static void
decompile_registers(uint32_t regbase,uint32_t * dwords,uint32_t sizedwords,int level)298 decompile_registers(uint32_t regbase, uint32_t *dwords, uint32_t sizedwords,
299 int level)
300 {
301 if (!sizedwords)
302 return;
303 uint32_t consumed = decompile_register(regbase, dwords, sizedwords, level);
304 sizedwords -= consumed;
305 while (sizedwords > 0) {
306 regbase += consumed;
307 dwords += consumed;
308 consumed = decompile_register(regbase, dwords, 0, level);
309 sizedwords -= consumed;
310 }
311 }
312
313 static void
decompile_domain(uint32_t pkt,uint32_t * dwords,uint32_t sizedwords,const char * dom_name,const char * packet_name,int level)314 decompile_domain(uint32_t pkt, uint32_t *dwords, uint32_t sizedwords,
315 const char *dom_name, const char *packet_name, int level)
316 {
317 struct rnndomain *dom;
318 int i;
319
320 dom = rnn_finddomain(rnn->db, dom_name);
321
322 printlvl(level, "pkt7(cs, %s, %u);\n", packet_name, sizedwords);
323
324 if (pkt == CP_LOAD_STATE6_FRAG || pkt == CP_LOAD_STATE6_GEOM) {
325 enum a6xx_state_type state_type =
326 (dwords[0] & CP_LOAD_STATE6_0_STATE_TYPE__MASK) >>
327 CP_LOAD_STATE6_0_STATE_TYPE__SHIFT;
328 enum a6xx_state_src state_src =
329 (dwords[0] & CP_LOAD_STATE6_0_STATE_SRC__MASK) >>
330 CP_LOAD_STATE6_0_STATE_SRC__SHIFT;
331
332 /* TODO: decompile all other state */
333 if (state_type == ST6_SHADER && state_src == SS6_INDIRECT) {
334 printlvl(level, "pkt(cs, 0x%x);\n", dwords[0]);
335 decompile_shader(NULL, 0, dwords + 1, level);
336 return;
337 }
338 }
339
340 for (i = 0; i < sizedwords; i++) {
341 struct rnndecaddrinfo *info = NULL;
342 if (dom) {
343 info = rnndec_decodeaddr(rnn->vc, dom, i, 0);
344 }
345
346 char *decoded;
347 if (!(info && info->typeinfo)) {
348 printlvl(level, "pkt(cs, 0x%x);\n", dwords[i]);
349 continue;
350 }
351 uint64_t value = dwords[i];
352 bool reg64 = info->typeinfo->high >= 32 && i < sizedwords - 1;
353 if (reg64) {
354 value |= (uint64_t)dwords[i + 1] << 32;
355 }
356 decoded = rnndec_decodeval(rnn->vc, info->typeinfo, value);
357
358 printlvl(level, "/* %s */\n", decoded);
359 printlvl(level, "pkt(cs, 0x%x);\n", dwords[i]);
360 if (reg64) {
361 printlvl(level, "pkt(cs, 0x%x);\n", dwords[i + 1]);
362 i++;
363 }
364
365 free(decoded);
366 free(info->name);
367 free(info);
368 }
369 }
370
371 static void
decompile_commands(uint32_t * dwords,uint32_t sizedwords,int level,uint32_t * cond_count)372 decompile_commands(uint32_t *dwords, uint32_t sizedwords, int level, uint32_t *cond_count)
373 {
374 int dwords_left = sizedwords;
375 uint32_t count = 0; /* dword count including packet header */
376 uint32_t val;
377
378 if (!dwords) {
379 fprintf(stderr, "NULL cmd buffer!\n");
380 return;
381 }
382
383 while (dwords_left > 0) {
384 if (pkt_is_regwrite(dwords[0], &val, &count)) {
385 assert(val < 0xffff);
386 decompile_registers(val, dwords + 1, count - 1, level);
387 } else if (pkt_is_opcode(dwords[0], &val, &count)) {
388 if (val == CP_INDIRECT_BUFFER) {
389 uint64_t ibaddr;
390 uint32_t ibsize;
391 ibaddr = dwords[1];
392 ibaddr |= ((uint64_t)dwords[2]) << 32;
393 ibsize = dwords[3];
394
395 printlvl(level, "{\n");
396 printlvl(level + 1, "begin_ib();\n");
397
398 uint32_t *ptr = hostptr(ibaddr);
399 decompile_commands(ptr, ibsize, level + 1, NULL);
400
401 printlvl(level + 1, "end_ib();\n");
402 printlvl(level, "}\n");
403 } else if (val == CP_SET_DRAW_STATE) {
404 for (int i = 1; i < count; i += 3) {
405 uint32_t state_count = dwords[i] & 0xffff;
406 if (state_count != 0) {
407 uint32_t unchanged = dwords[i] & (~0xffff);
408 uint64_t ibaddr = dwords[i + 1];
409 ibaddr |= ((uint64_t)dwords[i + 2]) << 32;
410
411 printlvl(level, "{\n");
412 printlvl(level + 1, "begin_draw_state();\n");
413
414 uint32_t *ptr = hostptr(ibaddr);
415 decompile_commands(ptr, state_count, level + 1, NULL);
416
417 printlvl(level + 1, "end_draw_state(%u);\n", unchanged);
418 printlvl(level, "}\n");
419 } else {
420 decompile_domain(val, dwords + i, 3, "CP_SET_DRAW_STATE",
421 "CP_SET_DRAW_STATE", level);
422 }
423 }
424 } else if (val == CP_CONTEXT_REG_BUNCH || val == CP_CONTEXT_REG_BUNCH2) {
425 uint32_t *dw = dwords + 1;
426 uint32_t cnt = count - 1;
427
428 if (val == CP_CONTEXT_REG_BUNCH2) {
429 if (options.no_reg_bunch) {
430 printlvl(level, "// CP_CONTEXT_REG_BUNCH2\n");
431 printlvl(level, "{\n");
432 } else {
433 printlvl(level, "pkt7(cs, %s, %u);\n", "CP_CONTEXT_REG_BUNCH2", cnt);
434 printlvl(level, "{\n");
435 printlvl(level + 1, "pkt(cs, 0x%x);\n", dw[0]);
436 printlvl(level + 1, "pkt(cs, 0x%x);\n", dw[1]);
437 }
438
439 dw += 2;
440 cnt -= 2;
441 } else {
442 if (options.no_reg_bunch) {
443 printlvl(level, "// CP_CONTEXT_REG_BUNCH\n");
444 printlvl(level, "{\n");
445 } else {
446 printlvl(level, "pkt7(cs, %s, %u);\n", "CP_CONTEXT_REG_BUNCH", cnt);
447 printlvl(level, "{\n");
448 }
449 }
450
451 for (uint32_t i = 0; i < cnt; i += 2) {
452 if (options.no_reg_bunch) {
453 decompile_register(dw[i], &dw[i + 1], 1, level + 1);
454 } else {
455 decompile_register_reg_bunch(dw[i], &dw[i + 1], 1, level + 1);
456 }
457 }
458 printlvl(level, "}\n");
459 } else if (val == CP_COND_REG_EXEC) {
460 const char *packet_name = pktname(val);
461 const char *dom_name = packet_name;
462 uint32_t cond_count = dwords[count - 1];
463
464 decompile_domain(val, dwords + 1, count - 1, dom_name, packet_name, level);
465
466 printlvl(level, "{\n");
467 printlvl(level + 1, "/* BEGIN COND (%d DWORDS) */\n", cond_count);
468
469 decompile_commands(dwords + count, cond_count, level + 1, &cond_count);
470 count += cond_count;
471
472 printlvl(level + 1, "/* END COND */\n");
473 printlvl(level, "}\n");
474 } else if (val == CP_NOP) {
475 /* Prop will often use NOP past the end of cond execs
476 * which basically create an else path for the cond exec
477 */
478 const char *packet_name = pktname(val);
479 const char *dom_name = packet_name;
480
481 if (count > dwords_left) {
482 int else_cond_count = count - dwords_left;
483
484 assert(cond_count);
485 *cond_count += else_cond_count;
486
487 printlvl(level, "pkt7(cs, %s, %u);\n", packet_name, count - 1);
488 for (int i = 1; i < dwords_left; i++) {
489 printlvl(level, "pkt(cs, 0x%x);\n", dwords[i]);
490 }
491
492 printlvl(level, "/* TO ELSE COND */\n");
493 printlvl(level - 1, "}\n");
494
495 printlvl(level - 1, "{\n");
496 printlvl(level, "/* ELSE COND (%d DWORDS) */\n", else_cond_count);
497 decompile_commands(dwords + dwords_left, else_cond_count, level, NULL);
498
499 return;
500 } else {
501 decompile_domain(val, dwords + 1, count - 1, dom_name, packet_name,
502 level);
503 }
504 } else {
505 const char *packet_name = pktname(val);
506 const char *dom_name = packet_name;
507 if (packet_name) {
508 /* special hack for two packets that decode the same way
509 * on a6xx:
510 */
511 if (!strcmp(packet_name, "CP_LOAD_STATE6_FRAG") ||
512 !strcmp(packet_name, "CP_LOAD_STATE6_GEOM"))
513 dom_name = "CP_LOAD_STATE6";
514 decompile_domain(val, dwords + 1, count - 1, dom_name, packet_name,
515 level);
516 } else {
517 errx(1, "unknown pkt7 %u", val);
518 }
519 }
520 } else {
521 errx(1, "unknown packet %u", dwords[0]);
522 }
523
524 dwords += count;
525 dwords_left -= count;
526 }
527
528 if (dwords_left < 0)
529 fprintf(stderr, "**** this ain't right!! dwords_left=%d\n", dwords_left);
530 }
531
532 static void
emit_header()533 emit_header()
534 {
535 if (!dev_id.gpu_id && !dev_id.chip_id)
536 return;
537
538 static bool emitted = false;
539 if (emitted)
540 return;
541 emitted = true;
542
543 switch (fd_dev_gen(&dev_id)) {
544 case 6:
545 init_rnn("a6xx");
546 break;
547 case 7:
548 init_rnn("a7xx");
549 break;
550 default:
551 errx(-1, "unsupported gpu: %u", dev_id.gpu_id);
552 }
553
554 printf("#include \"decode/rdcompiler-utils.h\"\n"
555 "int main(int argc, char **argv)\n"
556 "{\n"
557 "\tstruct replay_context ctx;\n"
558 "\tstruct fd_dev_id dev_id = {%u, 0x%" PRIx64 "};\n"
559 "\treplay_context_init(&ctx, &dev_id, argc, argv);\n"
560 "\tstruct cmdstream *cs = ctx.submit_cs;\n\n",
561 dev_id.gpu_id, dev_id.chip_id);
562 }
563
564 static inline uint32_t
u64_hash(const void * key)565 u64_hash(const void *key)
566 {
567 return _mesa_hash_data(key, sizeof(uint64_t));
568 }
569
570 static inline bool
u64_compare(const void * key1,const void * key2)571 u64_compare(const void *key1, const void *key2)
572 {
573 return memcmp(key1, key2, sizeof(uint64_t)) == 0;
574 }
575
576 static int
handle_file(const char * filename,uint32_t submit_to_decompile)577 handle_file(const char *filename, uint32_t submit_to_decompile)
578 {
579 struct io *io;
580 int submit = 0;
581 bool needs_reset = false;
582 struct rd_parsed_section ps = {0};
583
584 if (!strcmp(filename, "-"))
585 io = io_openfd(0);
586 else
587 io = io_open(filename);
588
589 if (!io) {
590 fprintf(stderr, "could not open: %s\n", filename);
591 return -1;
592 }
593
594 type0_reg = reg_a6xx;
595 mem_ctx = ralloc_context(NULL);
596 _mesa_set_init(&decompiled_shaders, mem_ctx, u64_hash, u64_compare);
597
598 struct {
599 unsigned int len;
600 uint64_t gpuaddr;
601 } gpuaddr = {0};
602
603 while (parse_rd_section(io, &ps)) {
604 switch (ps.type) {
605 case RD_TEST:
606 case RD_VERT_SHADER:
607 case RD_FRAG_SHADER:
608 case RD_CMD:
609 /* no-op */
610 break;
611 case RD_GPUADDR:
612 if (needs_reset) {
613 reset_buffers();
614 needs_reset = false;
615 }
616
617 parse_addr(ps.buf, ps.sz, &gpuaddr.len, &gpuaddr.gpuaddr);
618 break;
619 case RD_BUFFER_CONTENTS:
620 add_buffer(gpuaddr.gpuaddr, gpuaddr.len, ps.buf);
621 ps.buf = NULL;
622 break;
623 case RD_CMDSTREAM_ADDR: {
624 unsigned int sizedwords;
625 uint64_t gpuaddr;
626 parse_addr(ps.buf, ps.sz, &sizedwords, &gpuaddr);
627
628 if (submit == submit_to_decompile) {
629 decompile_commands(hostptr(gpuaddr), sizedwords, 0, NULL);
630 }
631
632 needs_reset = true;
633 submit++;
634 break;
635 }
636 case RD_GPU_ID: {
637 dev_id.gpu_id = parse_gpu_id(ps.buf);
638 if (fd_dev_info_raw(&dev_id))
639 emit_header();
640 break;
641 }
642 case RD_CHIP_ID: {
643 dev_id.chip_id = parse_chip_id(ps.buf);
644 if (fd_dev_info_raw(&dev_id))
645 emit_header();
646 break;
647 }
648 default:
649 break;
650 }
651 }
652
653 printf("\treplay_context_finish(&ctx);\n}");
654
655 io_close(io);
656 fflush(stdout);
657
658 if (ps.ret < 0) {
659 fprintf(stderr, "corrupt file\n");
660 }
661 return 0;
662 }
663