summaryrefslogtreecommitdiffstats
path: root/firmware/57X-GSP/570.144/decompile_handlers.py
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/57X-GSP/570.144/decompile_handlers.py')
-rw-r--r--firmware/57X-GSP/570.144/decompile_handlers.py222
1 files changed, 222 insertions, 0 deletions
diff --git a/firmware/57X-GSP/570.144/decompile_handlers.py b/firmware/57X-GSP/570.144/decompile_handlers.py
new file mode 100644
index 0000000..e2e258f
--- /dev/null
+++ b/firmware/57X-GSP/570.144/decompile_handlers.py
@@ -0,0 +1,222 @@
+#!/usr/bin/env python3
+"""
+Decompile secondary dispatcher RPC handlers to pseudo-C.
+"""
+
+import struct
+import json
+import os
+
+FWIMAGE_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), "gsp-570.144.fwimage.bin")
+OUTPUT_DIR = os.path.dirname(os.path.abspath(__file__))
+BASE_ADDR = 0x04000000
+
+# Secondary dispatcher handler entry points
+HANDLERS = [
+ (0x04ed34b8, "rpc_pin_handler"),
+ (0x04ed4364, "rpc_schedule_handler_1"),
+ (0x04ed45ac, "rpc_schedule_handler_2"),
+ (0x04ed4764, "rpc_pin_alloc_handler"),
+ (0x04ed4930, "rpc_alloc_handler_1"),
+ (0x04ed4984, "rpc_alloc_handler_2"),
+ (0x04ed49f8, "rpc_alloc_handler_3"),
+ (0x04ed4a64, "rpc_alloc_free_handler"),
+ (0x04ed45a8, "rpc_alloc_handler_5"),
+ (0x04cb8189, "rpc_bar_trap_handler"),
+ (0x051efbf4, "rpc_schedule_main"),
+ (0x057e94ec, "rpc_alloc_main"),
+]
+
+REG_NAMES = ['x0','ra','sp','gp','tp','t0','t1','t2','s0','s1','a0','a1','a2','a3','a4','a5','a6','a7',
+ 's2','s3','s4','s5','s6','s7','s8','s9','s10','s11','t3','t4','t5','t6']
+
+def read_binary(path):
+ with open(path, 'rb') as f:
+ return f.read()
+
+def decode_inst(data, offset):
+ if offset + 4 > len(data): return None, 0
+ first16 = struct.unpack('<H', data[offset:offset+2])[0]
+ if (first16 & 0x3) != 0x3:
+ return decode_compressed(first16), 2
+ inst = struct.unpack('<I', data[offset:offset+4])[0]
+ return decode_32bit(inst), 4
+
+def decode_compressed(inst):
+ if (inst & 0xF003) == 0x8002:
+ rd = (inst >> 7) & 0x7; rs2 = (inst >> 10) & 0x7
+ return {'m': 'c.mv', 'rd': rd+8, 'rs2': rs2+8, 's': f'c.mv {REG_NAMES[rd+8]}, {REG_NAMES[rs2+8]}'}
+ if (inst & 0xE003) == 0x6001:
+ rd = (inst >> 7) & 0x7
+ imm = ((inst >> 2) & 0x3F) | ((inst >> 12) & 0x1) << 6
+ if imm & 0x40: imm -= 0x80
+ return {'m': 'c.addi', 'rd': rd+8, 'imm': imm, 's': f'c.addi {REG_NAMES[rd+8]}, {imm}'}
+ if (inst & 0xF07F) == 0x8067:
+ rs1 = (inst >> 7) & 0x1F
+ return {'m': 'c.jalr', 'rs1': rs1, 's': f'c.jalr {REG_NAMES[rs1]}'}
+ if (inst & 0xE003) == 0x6003:
+ rd = (inst >> 10) & 0x7; rs1 = (inst >> 7) & 0x7
+ off = ((inst >> 2) & 0x1F) | ((inst >> 13) & 0x3) << 5
+ return {'m': 'c.ld', 'rd': rd+8, 'rs1': rs1+8, 'off': off*8, 's': f'c.ld {REG_NAMES[rd+8]}, {off*8}({REG_NAMES[rs1+8]})'}
+ if (inst & 0xE003) == 0xE000:
+ rs1 = (inst >> 7) & 0x7; rs2 = (inst >> 10) & 0x7
+ off = ((inst >> 2) & 0x1F) | ((inst >> 13) & 0x3) << 5
+ return {'m': 'c.sd', 'rs1': rs1+8, 'rs2': rs2+8, 'off': off*8, 's': f'c.sd {REG_NAMES[rs2+8]}, {off*8}({REG_NAMES[rs1+8]})'}
+ return {'m': 'c.unk', 'raw': inst, 's': f'c.0x{inst:04x}'}
+
+def decode_32bit(inst):
+ opcode = inst & 0x7F
+ funct3 = (inst >> 12) & 0x7
+ rd = (inst >> 7) & 0x1F
+ rs1 = (inst >> 15) & 0x1F
+ rs2 = (inst >> 20) & 0x1F
+ funct7 = (inst >> 25) & 0x7F
+
+ def R(): return REG_NAMES[rd]
+ def R1(): return REG_NAMES[rs1]
+ def R2(): return REG_NAMES[rs2]
+
+ if opcode == 0x13 and funct3 == 0: # addi
+ imm = (inst >> 20) & 0xFFF
+ if imm >= 0x800: imm -= 0x1000
+ return {'m': 'addi', 'rd': rd, 'rs1': rs1, 'imm': imm, 's': f'{R()} = {R1()} + {imm}'}
+ if opcode == 0x03 and funct3 == 3: # ld
+ off = (inst >> 20) & 0xFFF
+ if off >= 0x800: off -= 0x1000
+ return {'m': 'ld', 'rd': rd, 'rs1': rs1, 'off': off, 's': f'{R()} = *(uint64_t*)({R1()} + {off})'}
+ if opcode == 0x23 and funct3 == 3: # sd
+ off = ((inst >> 7) & 0x1F) | ((inst >> 25) & 0x7F) << 5
+ return {'m': 'sd', 'rs1': rs1, 'rs2': rs2, 'off': off, 's': f'*(uint64_t*)({R1()} + {off}) = {R2()}'}
+ if opcode == 0x6F: # jal
+ imm = ((inst >> 31) & 0x1) << 20 | ((inst >> 12) & 0xFF) << 12 | ((inst >> 20) & 0x1) << 11 | ((inst >> 21) & 0x3FF) << 1
+ if imm & 0x100000: imm -= 0x200000
+ target = BASE_ADDR + offset + imm if 'offset' in globals() else 0
+ return {'m': 'jal', 'rd': rd, 'imm': imm, 's': f'{R()} = PC+4; goto FUNC_{target:08X}'}
+ if opcode == 0x67 and funct3 == 0: # jalr
+ imm = (inst >> 20) & 0xFFF
+ if imm >= 0x800: imm -= 0x1000
+ if rd == 0 and imm == 0 and rs1 == 1:
+ return {'m': 'ret', 's': 'return'}
+ return {'m': 'jalr', 'rd': rd, 'rs1': rs1, 'imm': imm, 's': f'{R()} = PC+4; goto *({R1()} + {imm})'}
+ if opcode == 0x63: # branch
+ imm = ((inst >> 31) & 0x1) << 12 | ((inst >> 7) & 0x1) << 11 | ((inst >> 25) & 0x3F) << 5 | ((inst >> 8) & 0xF) << 1
+ if imm & 0x1000: imm -= 0x2000
+ btype = ['beq','bne','?','?','blt','bge','bltu','bgeu'][funct3]
+ return {'m': btype, 'rs1': rs1, 'rs2': rs2, 'imm': imm, 's': f'if ({R1()} {btype} {R2()}) goto PC+{imm}'}
+ if opcode == 0x37: # lui
+ imm = (inst >> 12) & 0xFFFFF
+ return {'m': 'lui', 'rd': rd, 'imm': imm, 's': f'{R()} = 0x{imm:05x}000'}
+ if opcode == 0x17: # auipc
+ imm = (inst >> 12) & 0xFFFFF
+ return {'m': 'auipc', 'rd': rd, 'imm': imm, 's': f'{R()} = PC + 0x{imm:05x}000'}
+ if opcode == 0x33: # arithmetic
+ ops = {0:'add', 0x20:'sub', 1:'sll', 4:'xor', 5:'srl', 0x25:'sra', 6:'or', 7:'and'}
+ op = ops.get(funct7, f'arith{funct7}')
+ return {'m': op, 'rd': rd, 'rs1': rs1, 'rs2': rs2, 's': f'{R()} = {R1()} {op} {R2()}'}
+ if opcode == 0x0F: return {'m': 'fence', 's': 'fence'}
+ if opcode == 0x73: return {'m': 'ecall', 's': 'ecall/ebreak'}
+ return {'m': 'unk', 'raw': inst, 's': f'0x{inst:08x}'}
+
+def trace_function(data, start_addr, max_bytes=2000):
+ offset = start_addr - BASE_ADDR
+ insts = []
+ i = 0
+ while i < max_bytes:
+ idx = offset + i
+ if idx >= len(data): break
+ inst, size = decode_inst(data, idx)
+ if inst is None: i += 2; continue
+ inst['addr'] = BASE_ADDR + idx
+ inst['rel'] = i
+ insts.append(inst)
+ i += size
+ if inst.get('m') == 'ret': break
+ return insts
+
+def analyze_prologue(insts):
+ stack = None
+ ra_reg = None
+ for inst in insts[:20]:
+ m = inst.get('m')
+ if m == 'addi' and inst.get('rd') == 2 and inst.get('rs1') == 2 and inst.get('imm', 0) < -16:
+ stack = -inst['imm']
+ if m in ('addi', 'c.mv') and inst.get('rs1') == 1 and inst.get('imm', 0) == 0 and inst.get('rd', 0) >= 9:
+ ra_reg = inst['rd']
+ if m == 'c.mv' and inst.get('rs2') == 1 and inst.get('rd', 0) >= 8:
+ ra_reg = inst['rd']
+ return stack, ra_reg
+
+def generate_c(insts, name, stack, ra_reg):
+ lines = [f"// {name} @ 0x{insts[0]['addr']:08x}", f"// Stack: {stack or 'unknown'} bytes, RA saved in {REG_NAMES[ra_reg] if ra_reg else '?'}", ""]
+
+ for inst in insts:
+ m = inst.get('m')
+ addr = inst['addr']
+ rel = inst['rel']
+ lines.append(f"L_{rel:04x}: // 0x{addr:08x}")
+
+ if m == 'addi':
+ rd, rs1, imm = inst['rd'], inst['rs1'], inst['imm']
+ if rd == 2 and rs1 == 2 and imm < 0:
+ lines.append(f" sp -= {-imm}; // alloc stack frame ({-imm} bytes)")
+ elif rd == 8 and rs1 == 2:
+ lines.append(f" s0 = sp + {imm}; // frame pointer")
+ elif rs1 == 1 and imm == 0 and rd >= 9:
+ lines.append(f" {REG_NAMES[rd]} = ra; // save return address")
+ else:
+ lines.append(f" {REG_NAMES[rd]} = {REG_NAMES[rs1]} + {imm};")
+
+ elif m == 'ld':
+ lines.append(f" {REG_NAMES[inst['rd']]} = *(uint64_t*)({REG_NAMES[inst['rs1']]} + {inst['off']});")
+
+ elif m == 'sd':
+ lines.append(f" *(uint64_t*)({REG_NAMES[inst['rs1']]} + {inst['off']}) = {REG_NAMES[inst['rs2']]};")
+
+ elif m == 'jal':
+ target = inst['addr'] + inst['imm']
+ lines.append(f" ra = 0x{inst['addr']+4:08x};")
+ lines.append(f" goto FUNC_{target:08X}; // call")
+
+ elif m == 'jalr':
+ if inst.get('rd') == 0 and inst.get('imm') == 0 and inst.get('rs1') == 1:
+ lines.append(f" return;")
+ else:
+ lines.append(f" {REG_NAMES[inst['rd']]} = 0x{inst['addr']+4:08x}; goto *({REG_NAMES[inst['rs1']]} + {inst['imm']});")
+
+ elif m == 'ret':
+ lines.append(f" return;")
+
+ elif m in ('beq','bne','blt','bge','bltu','bgeu'):
+ target = inst['addr'] + inst['imm']
+ lines.append(f" if ({REG_NAMES[inst['rs1']]} {m} {REG_NAMES[inst['rs2']]}) goto 0x{target:08x};")
+
+ elif m in ('lui','auipc'):
+ lines.append(f" {REG_NAMES[inst['rd']]} = {m} 0x{inst['imm']:05x}000;")
+
+ elif m in ('add','sub','sll','xor','srl','sra','or','and'):
+ lines.append(f" {REG_NAMES[inst['rd']]} = {REG_NAMES[inst['rs1']]} {m} {REG_NAMES[inst['rs2']]};")
+
+ elif m.startswith('c.'):
+ lines.append(f" {inst['s']};")
+
+ else:
+ lines.append(f" {inst['s']};")
+
+ return '\n'.join(lines)
+
+def main():
+ data = read_binary(FWIMAGE_PATH)
+
+ for addr, name in HANDLERS:
+ print(f"Decompiling {name} @ 0x{addr:08x}...")
+ insts = trace_function(data, addr, 3000)
+ stack, ra_reg = analyze_prologue(insts)
+ c_code = generate_c(insts, name, stack, ra_reg)
+
+ out_file = f"{OUTPUT_DIR}/decompiled_{name}.c"
+ with open(out_file, 'w') as f:
+ f.write(c_code)
+ print(f" -> {out_file} ({len(insts)} insts, stack={stack}, ra_reg={REG_NAMES[ra_reg] if ra_reg else '?'})")
+
+if __name__ == "__main__":
+ main()