From ff5e17f1f85c93aa0c0c1004938a21145b0f8b5d Mon Sep 17 00:00:00 2001 From: Rob Clark Date: Mon, 24 May 2021 11:00:28 -0700 Subject: [PATCH] freedreno/afuc: Use emulator to extract jmptbl This runs through the SQE bootstrap code to extract the packet-table, rather than relying on heuristics. As a bonus, it can detect the start of the LPAC fw in a660+ fw so that we can properly decode the LPAC fw and packet-table. Note that this decodes the jmptable as normal instructions, which is a change in behavior from the previous heuristic based jmptbl extraction. Not sure if that is a good or bad thing. For a5xx, for now the legacy heuristic based jmptable decoding is preserved, at least until enough control regs are figured out. Signed-off-by: Rob Clark Part-of: --- .../.gitlab-ci/reference/afuc_test.asm | 128 ++++++++++++++++++ src/freedreno/afuc/disasm.c | 103 +++++++++++--- 2 files changed, 215 insertions(+), 16 deletions(-) diff --git a/src/freedreno/.gitlab-ci/reference/afuc_test.asm b/src/freedreno/.gitlab-ci/reference/afuc_test.asm index c68460477bb..920aa4d49d3 100644 --- a/src/freedreno/.gitlab-ci/reference/afuc_test.asm +++ b/src/freedreno/.gitlab-ci/reference/afuc_test.asm @@ -260,3 +260,131 @@ UNKN126: UNKN127: waitin mov $01, $data + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [0000006b] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [0000003f] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000025] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000022] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [0000002c] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000030] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000062] ; nop + [00000076] ; nop + [00000055] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop + [00000076] ; nop diff --git a/src/freedreno/afuc/disasm.c b/src/freedreno/afuc/disasm.c index 8de7991ebbd..d7b322a1022 100644 --- a/src/freedreno/afuc/disasm.c +++ b/src/freedreno/afuc/disasm.c @@ -758,7 +758,81 @@ setup_labels(uint32_t *instrs, uint32_t sizedwords) } static void -disasm(uint32_t *buf, int sizedwords) +disasm(struct emu *emu) +{ + uint32_t sizedwords = emu->sizedwords; + uint32_t lpac_offset = 0; + + EMU_GPU_REG(CP_SQE_INSTR_BASE); + EMU_GPU_REG(CP_LPAC_SQE_INSTR_BASE); + + emu_init(emu); + +#ifdef BOOTSTRAP_DEBUG + while (true) { + disasm_instr(emu->instrs, emu->gpr_regs.pc); + emu_step(emu); + } +#endif + + emu_run_bootstrap(emu); + + /* Figure out if we have LPAC SQE appended: */ + if (emu_get_reg64(emu, &CP_LPAC_SQE_INSTR_BASE)) { + lpac_offset = emu_get_reg64(emu, &CP_LPAC_SQE_INSTR_BASE) - + emu_get_reg64(emu, &CP_SQE_INSTR_BASE); + lpac_offset /= 4; + sizedwords = lpac_offset; + } + + setup_packet_table(emu->jmptbl, ARRAY_SIZE(emu->jmptbl)); + setup_labels(emu->instrs, emu->sizedwords); + + /* TODO add option to emulate LPAC SQE instead: */ + if (emulator) { + /* Start from clean slate: */ + emu_fini(emu); + emu_init(emu); + + while (true) { + disasm_instr(emu->instrs, emu->gpr_regs.pc); + emu_step(emu); + } + } + + /* print instructions: */ + for (int i = 0; i < sizedwords; i++) { + disasm_instr(emu->instrs, i); + } + + if (!lpac_offset) + return; + + printf(";\n"); + printf("; LPAC microcode:\n"); + printf(";\n"); + + emu_fini(emu); + + emu->lpac = true; + emu->instrs += lpac_offset; + emu->sizedwords -= lpac_offset; + + emu_init(emu); + emu_run_bootstrap(emu); + + setup_packet_table(emu->jmptbl, ARRAY_SIZE(emu->jmptbl)); + setup_labels(emu->instrs, emu->sizedwords); + + /* print instructions: */ + for (int i = 0; i < emu->sizedwords; i++) { + disasm_instr(emu->instrs, i); + } +} + + +static void +disasm_legacy(uint32_t *buf, int sizedwords) { uint32_t *instrs = buf; const int jmptbl_start = instrs[1] & 0xffff; @@ -773,20 +847,6 @@ disasm(uint32_t *buf, int sizedwords) */ setup_labels(instrs, jmptbl_start); - if (emulator) { - struct emu state = { - .instrs = instrs, - .sizedwords = sizedwords, - }; - - emu_init(&state); - - while (true) { - disasm_instr(instrs, state.gpr_regs.pc); - emu_step(&state); - } - } - /* print instructions: */ for (i = 0; i < jmptbl_start; i++) { disasm_instr(instrs, i); @@ -898,7 +958,18 @@ main(int argc, char **argv) printf("; Disassembling microcode: %s\n", file); printf("; Version: %08x\n\n", buf[1]); - disasm(&buf[1], sz / 4 - 1); + + if (gpuver < 6) { + disasm_legacy(&buf[1], sz / 4 - 1); + } else { + struct emu emu = { + .instrs = &buf[1], + .sizedwords = sz / 4 - 1, + .gpu_id = gpu_id, + }; + + disasm(&emu); + } return 0; }