xref: /aosp_15_r20/external/mesa3d/src/freedreno/decode/rddecompiler.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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