#!/usr/bin/env python3 """ Trace all subsystems: WPR, Migration, Primary Dispatcher sub-commands """ import struct import os FWIMAGE_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), "gsp-570.144.fwimage.bin") BASE_ADDR = 0x04000000 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('> 7) & 0x7; rs2 = (inst >> 10) & 0x7 return {'m': 'c.mv', 'rd': rd+8, 'rs2': 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} if (inst & 0xF07F) == 0x8067: rs1 = (inst >> 7) & 0x1F return {'m': 'c.jalr', 'rs1': 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} 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} return {'m': 'c.unk', 'raw': inst} 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 if opcode == 0x13 and funct3 == 0: imm = (inst >> 20) & 0xFFF if imm >= 0x800: imm -= 0x1000 return {'m': 'addi', 'rd': rd, 'rs1': rs1, 'imm': imm} if opcode == 0x03 and funct3 == 3: off = (inst >> 20) & 0xFFF if off >= 0x800: off -= 0x1000 return {'m': 'ld', 'rd': rd, 'rs1': rs1, 'off': off} if opcode == 0x23 and funct3 == 3: off = ((inst >> 7) & 0x1F) | ((inst >> 25) & 0x7F) << 5 return {'m': 'sd', 'rs1': rs1, 'rs2': rs2, 'off': off} if opcode == 0x6F: imm = ((inst >> 31) & 0x1) << 20 | ((inst >> 12) & 0xFF) << 12 | ((inst >> 20) & 0x1) << 11 | ((inst >> 21) & 0x3FF) << 1 if imm & 0x100000: imm -= 0x200000 return {'m': 'jal', 'rd': rd, 'imm': imm} if opcode == 0x67 and funct3 == 0: imm = (inst >> 20) & 0xFFF if imm >= 0x800: imm -= 0x1000 return {'m': 'jalr', 'rd': rd, 'rs1': rs1, 'imm': imm} if opcode == 0x63: 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} if opcode == 0x37: imm = (inst >> 12) & 0xFFFFF return {'m': 'lui', 'rd': rd, 'imm': imm} if opcode == 0x17: imm = (inst >> 12) & 0xFFFFF return {'m': 'auipc', 'rd': rd, 'imm': imm} if opcode == 0x33: ops = {0:'add', 0x20:'sub', 1:'sll', 4:'xor', 5:'srl', 0x25:'sra', 6:'or', 7:'and'} return {'m': ops.get(funct7, f'arith{funct7}'), 'rd': rd, 'rs1': rs1, 'rs2': rs2} return {'m': 'unk', 'raw': inst} 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') in ('ret', 'jalr') and inst.get('rd') == 0 and inst.get('imm', 0) == 0 and inst.get('rs1', 1) == 1: break return insts def find_string_refs(data, strings): """Find all references to given strings in the binary""" results = {} for s in strings: s_bytes = s.encode('ascii') results[s] = [] # Search for string in data for i in range(len(data) - len(s_bytes)): if data[i:i+len(s_bytes)] == s_bytes: results[s].append(BASE_ADDR + i) return results def find_string_refs_via_loads(data, string_addrs): """Find code that loads addresses of strings""" results = {} for s, addrs in string_addrs.items(): results[s] = [] for str_addr in addrs: # Look for auipc/addi pairs that compute this address for i in range(0, len(data) - 4, 2): if i + 4 <= len(data): inst = struct.unpack('> 7) & 0x1F imm = (inst >> 12) & 0xFFFFF pc = BASE_ADDR + i base = (pc + (imm << 12)) & ~0xFFF # Check next instruction for addi if i + 8 <= len(data): inst2 = struct.unpack('> 12) & 0x7) == 0: rd2 = (inst2 >> 7) & 0x1F rs1 = (inst2 >> 15) & 0x1F imm2 = (inst2 >> 20) & 0xFFF if imm2 >= 0x800: imm2 -= 0x1000 if rd == rd2 and rs1 == rd: computed = base + imm2 if computed == str_addr: results[s].append(BASE_ADDR + i) return results data = read_binary(FWIMAGE_PATH) # ============================================================ # 1. TRACE WPR SUBSYSTEM # ============================================================ print("=" * 60) print("1. WPR SUBSYSTEM - String References") print("=" * 60) wpr_strings = [ "WPR_WRITE_COMPLETE", "WPR_READ_COMPLETE", "WPR_WRITE_TIMEOUT", "WPR_READ_TIMEOUT", "NV_WPR_WRITE_COMPLETE", "NV_WPR_READ_COMPLETE", "NV_WPR_WRITE_TIMEOUT", "NV_WPR_READ_TIMEOUT" ] wpr_locs = find_string_refs(data, wpr_strings) for s, addrs in wpr_locs.items(): if addrs: print(f"\n{s}:") for addr in addrs: print(f" String at 0x{addr:08x}") # Find code referencing these strings wpr_refs = find_string_refs_via_loads(data, wpr_locs) for s, addrs in wpr_refs.items(): if addrs: print(f"\nCode referencing {s}:") for addr in addrs[:5]: print(f" 0x{addr:08x}") # ============================================================ # 2. TRACE BAR SUBSYSTEM # ============================================================ print("\n" + "=" * 60) print("2. BAR SUBSYSTEM - String References") print("=" * 60) bar_strings = ["BAR1", "Bar1Rest", "ForceBarAccess", "Bar1Mapping", "Bar1Aperture", "Bar1Size"] bar_locs = find_string_refs(data, bar_strings) for s, addrs in bar_locs.items(): if addrs: print(f"\n{s}:") for addr in addrs: print(f" String at 0x{addr:08x}") bar_refs = find_string_refs_via_loads(data, bar_locs) for s, addrs in bar_refs.items(): if addrs: print(f"\nCode referencing {s}:") for addr in addrs[:5]: print(f" 0x{addr:08x}") # ============================================================ # 3. DECODE PRIMARY DISPATCHER SUB-COMMANDS (Jump Table at 0x057a3ad8) # ============================================================ print("\n" + "=" * 60) print("3. PRIMARY DISPATCHER SUB-COMMANDS (0x057a3ad8)") print("=" * 60) def decode_jal_target(inst, pc): imm = ((inst >> 31) & 0x1) << 20 | ((inst >> 12) & 0xFF) << 12 | ((inst >> 20) & 0x1) << 11 | ((inst >> 21) & 0x3FF) << 1 if imm & 0x100000: imm -= 0x200000 return pc + imm jt_base = 0x057a3ad8 for i in range(32): entry_addr = jt_base + i * 8 offset = entry_addr - BASE_ADDR if offset + 8 <= len(data): addi_inst = struct.unpack(' jal 0x{target:08x}") # ============================================================ # 4. TRACE MIGRATION (RPC 0x0B) IN DISPATCHERS # ============================================================ print("\n" + "=" * 60) print("4. MIGRATION (RPC 0x0B) HANDLERS") print("=" * 60) # Primary dispatcher - look for RPC 0x0B branches print("\nPrimary Dispatcher (0x057a1ac0) MIGRATE branches:") offset = 0x57a1ac0 - BASE_ADDR for i in range(0, 3000, 2): idx = offset + i if idx + 4 <= len(data): inst = struct.unpack('> 12) & 0x7 rs1 = (inst >> 15) & 0x1F rs2 = (inst >> 20) & 0x1F imm = ((inst >> 31) & 0x1) << 12 | ((inst >> 7) & 0x1) << 11 | ((inst >> 25) & 0x3F) << 5 | ((inst >> 8) & 0xF) << 1 if imm & 0x1000: imm -= 0x2000 target = BASE_ADDR + idx + imm # Check for nearby addi with imm=11 (MIGRATE) for back in range(2, 20, 2): if idx - back >= 0: prev = struct.unpack('> 12) & 0x7) == 0: prev_imm = (prev >> 20) & 0xFFF if prev_imm >= 0x800: prev_imm -= 0x1000 if prev_imm == 11: btype = ['beq','bne','?','?','blt','bge','bltu','bgeu'][funct3] print(f" 0x{BASE_ADDR+idx:08x}: {btype} x{rs1}, x{rs2}, 0x{target:08x} (RPC=0x0B)") # Secondary dispatcher print("\nSecondary Dispatcher (0x04ed39dc) MIGRATE branches:") offset = 0xed39dc for i in range(0, 5000, 2): idx = offset + i if idx + 4 <= len(data): inst = struct.unpack('> 12) & 0x7 rs1 = (inst >> 15) & 0x1F rs2 = (inst >> 20) & 0x1F imm = ((inst >> 31) & 0x1) << 12 | ((inst >> 7) & 0x1) << 11 | ((inst >> 25) & 0x3F) << 5 | ((inst >> 8) & 0xF) << 1 if imm & 0x1000: imm -= 0x2000 target = BASE_ADDR + idx + imm for back in range(2, 20, 2): if idx - back >= 0: prev = struct.unpack('> 12) & 0x7) == 0: prev_imm = (prev >> 20) & 0xFFF if prev_imm >= 0x800: prev_imm -= 0x1000 if prev_imm == 11: btype = ['beq','bne','?','?','blt','bge','bltu','bgeu'][funct3] print(f" 0x{BASE_ADDR+idx:08x}: {btype} x{rs1}, x{rs2}, 0x{target:08x} (RPC=0x0B)")