-- oracle_call_test.lua -- minimal proof that the firmware's challenge pipeline -- can be invoked directly from the debugger (no TCP connection). -- -- Calls 0x3F5A9620(1) (dwt_prf's allocator/init, Ghidra 0x07EB52C4) -- at frame 1000 and stops at the synthetic return address. local machine = manager.machine local cpu = machine.devices[':maincpu'] local dbg = machine.debugger local space = cpu.spaces['program'] if not dbg then machine:exit(); return end dbg.visible_cpu = cpu local ARG = 0x01800000 local STACK = 0x01840000 local RET = 0x018c0000 local IE = 0x200000 local INIT = 0x3F5A9620 local f = 0 local started = false local saved = {} local function state(name) local r = cpu.state[name] return r and r.value or nil end local function push(v) local sp = state('SP') - 0x20 space:write_u32(sp, v) cpu.state['SP'].value = sp end local function setup_call(target, args) saved.pc = state('PC') saved.sp = state('SP') saved.a14 = state('A14') saved.st = state('ST') print(string.format("TEST setup target=%08X pc=%08X sp=%08X a14=%08X st=%08X", target, saved.pc, saved.sp, saved.a14, saved.st)) cpu.state['SP'].value = STACK if #args > 0 then local a = ARG for i = 1, #args do space:write_u32(a, args[i]) a = a + 0x20 end push(saved.a14) cpu.state['A14'].value = ARG + #args * 0x20 end push(RET) cpu.state['PC'].value = target cpu.state['ST'].value = saved.st & ~IE dbg:command('bclear') dbg:command(string.format('bpset %X', RET)) dbg.execution_state = 'run' end emu.register_frame_done(function() f = f + 1 if f == 1000 and not started then started = true print(string.format("TEST frame=%d @1C0200=%08X", f, space:read_u32(0x1c0200))) setup_call(INIT, { 1 }) return end if started and saved.pc then local es = dbg.execution_state if es == 'stop' then local pc = state('PC') print(string.format("TEST stop frame=%d pc=%08X savedpc=%08X", f, pc, saved.pc)) print(string.format("TEST @1C0200=%08X @1C0220=%08X @1C0240=%08X @1C0260=%08X", space:read_u32(0x1c0200), space:read_u32(0x1c0220), space:read_u32(0x1c0240), space:read_u32(0x1c0260))) -- dump 16 bytes at the key pointer if it looks sane local kp = space:read_u32(0x1c0260) if kp ~= 0 then local t = {} for i = 0, 15 do t[#t + 1] = string.format("%02X", space:read_u8(kp + i * 8)) end print("TEST key[0..15]=" .. table.concat(t, " ")) end dbg:command('bclear') cpu.state['PC'].value = saved.pc cpu.state['SP'].value = saved.sp cpu.state['A14'].value = saved.a14 cpu.state['ST'].value = saved.st print("TEST restoring and exiting") machine:exit() end end end, "vt1200-oracle-call-test") dbg.execution_state = 'run'