diff --git a/proxyclient/hv/trace_agx.py b/proxyclient/hv/trace_agx.py index dd780edd..1912ed8b 100644 --- a/proxyclient/hv/trace_agx.py +++ b/proxyclient/hv/trace_agx.py @@ -1,5 +1,7 @@ # SPDX-License-Identifier: MIT +from m1n1.utils import * + trace_device("/arm-io/sgx", False) trace_device("/arm-io/pmp", False) trace_device("/arm-io/gfx-asc", False) @@ -7,5 +9,80 @@ trace_device("/arm-io/gfx-asc", False) from m1n1.trace.asc import ASCTracer ASCTracer = ASCTracer._reloadcls() -gfx_tracer = ASCTracer(hv, "/arm-io/gfx-asc", verbose=True) + +# gfx_tracer = ASCTracer(hv, "/arm-io/gfx-asc", verbose=True) +# gfx_tracer.start() + +from m1n1.trace.agx import AGXTracer +AGXTracer = AGXTracer._reloadcls() + +gfx_tracer = AGXTracer(hv, "/arm-io/gfx-asc", verbose=False) gfx_tracer.start() + +trace_range(irange(gfx_tracer.gpu_region, gfx_tracer.gpu_region_size), mode=TraceMode.SYNC) +trace_range(irange(gfx_tracer.gfx_shared_region, gfx_tracer.gfx_shared_region_size), mode=TraceMode.SYNC) +trace_range(irange(gfx_tracer.gfx_handoff, gfx_tracer.gfx_handoff_size), mode=TraceMode.SYNC) + + +# Trace the entire mmio range around the GPU +# node = hv.adt["/arm-io/sgx"] +# addr, size = node.get_reg(0) +# hv.trace_range(irange(addr, 0x1000000), TraceMode.SYNC) + +def trace_all_gfx_io(): + # These are all the IO ranges that get mapped into the UAT iommu pagetable + # Trace them so we can see if any of them are being written by the CPU + + # page (8): fa010020000 ... fa010023fff -> 000000020e100000 [8000020e100447] + hv.trace_range(irange(0x20e100000, 0x4000), mode=TraceMode.SYNC) + + # page (10): fa010028000 ... fa01002bfff -> 000000028e104000 [c000028e104447] + hv.trace_range(irange(0x20e100000, 0x4000), mode=TraceMode.SYNC) + + # page (22): fa010058000 ... fa01005bfff -> 000000028e494000 [8000028e494447] + hv.trace_range(irange(0x28e494000, 0x4000), mode=TraceMode.SYNC) + + # page (28): fa010070000 ... fa010073fff -> 0000000204d60000 [c0000204d60447] + hv.trace_range(irange(0x204d60000, 0x4000), mode=TraceMode.SYNC) + + # page (30): fa010078000 ... fa01007bfff -> 0000000200000000 [c0000200000447] + # to + # page (83): fa01014c000 ... fa01014ffff -> 00000002000d4000 [c00002000d4447] + hv.trace_range(irange(0x200000000, 0xd5000), mode=TraceMode.SYNC) + + # page (84): fa010150000 ... fa010153fff -> 0000000201000000 [c0000201000447] + #page (137): fa010224000 ... fa010227fff -> 00000002010d4000 [c00002010d4447] + hv.trace_range(irange(0x201000000, 0xd5000), mode=TraceMode.SYNC) + + # page (138): fa010228000 ... fa01022bfff -> 0000000202000000 [c0000202000447] + # page (191): fa0102fc000 ... fa0102fffff -> 00000002020d4000 [c00002020d4447] + hv.trace_range(irange(0x202000000, 0xd5000), mode=TraceMode.SYNC) + + # page (192): fa010300000 ... fa010303fff -> 0000000203000000 [c0000203000447] + hv.trace_range(irange(0x203000000, 0xd5000), mode=TraceMode.SYNC) + hv.trace_range(irange(0x204000000, 0xd5000), mode=TraceMode.SYNC) + hv.trace_range(irange(0x205000000, 0xd5000), mode=TraceMode.SYNC) + hv.trace_range(irange(0x206000000, 0xd5000), mode=TraceMode.SYNC) + hv.trace_range(irange(0x207000000, 0xd5000), mode=TraceMode.SYNC) + + # page (464): fa010740000 ... fa010743fff -> 00000002643c4000 [c00002643c4447] + hv.trace_range(irange(0x2643c4000, 0x4000), mode=TraceMode.SYNC) + # page (466): fa010748000 ... fa01074bfff -> 000000028e3d0000 [c000028e3d0447] + hv.trace_range(irange(0x28e3d0000, 0x4000), mode=TraceMode.SYNC) + # page (468): fa010750000 ... fa010753fff -> 000000028e3c0000 [8000028e3c0447] + hv.trace_range(irange(0x28e3c0000, 0x4000), mode=TraceMode.SYNC) + + # page (8): f9100020000 ... f9100023fff -> 0000000406000000 [60000406000447] + # page (263): f910041c000 ... f910041ffff -> 00000004063fc000 [600004063fc447] + hv.trace_range(irange(0x2643c4000, 0x63fc000), mode=TraceMode.SYNC) + +def trace_gpu_irqs(): + # Trace sgx interrupts + node = hv.adt["/arm-io/sgx"] + for irq in getattr(node, "interrupts"): + hv.trace_irq(f"{node.name} {irq}", irq, 1, hv.IRQTRACE_IRQ) + + # Trace gfx-asc interrupts + node = hv.adt["/arm-io/gfx-asc"] + for irq in getattr(node, "interrupts"): + hv.trace_irq(f"{node.name} {irq}", irq, 1, hv.IRQTRACE_IRQ) diff --git a/proxyclient/m1n1/trace/agx.py b/proxyclient/m1n1/trace/agx.py new file mode 100644 index 00000000..ce6b8f25 --- /dev/null +++ b/proxyclient/m1n1/trace/agx.py @@ -0,0 +1,152 @@ + +from mmap import PAGESIZE +from . import ADTDevTracer +from .asc import * +from ..hw.uat import UAT + +from m1n1.proxyutils import RegMonitor + +from construct import * +from construct.core import Int16ul, Int32ul, Int64ul, Int8ul + + +ControlStruct = Struct( + "unkptr_0" / Int64ul, # allocation size: 0x4000 + "unk_8" / Int32ul, + "unk_c"/ Int32ul, + "unkptr_10" / Int64ul, # allocation size: 0x34000 + "unkptr_18" / Int64ul, # allocation size: 0x88000, heap? + "unkptr_20" / Int64ul, # allocation size: 0x4000, but probally only 0x80 bytes long + "unk_28" / Int32ul, + "unk_2c" / Int32ul, + "unk_30" / Int32ul, +) + +class InitMsg(Register64): + TYPE = 59, 52 + +class InitReq(InitMsg): + TYPE = 59, 52, Constant(0x1) + UNK = 47, 0 + +class InitResp(InitMsg): + # example: 0x0010_4fa0_0c388000 + TYPE = 59, 52, Constant(0x1) + UNK1 = 47, 44 + ADDR = 43, 0 # GPU VA that gets filled with a repating 0xefefefef pattern + +class InitEp(EP): + # This endpoint receives and sends one message during boot. + # Potentially a "Ready" and a "Init" message. + BASE_MESSAGE = InitMsg + + @msg(0x1, DIR.RX, InitReq) + def init_req(self, msg): + print(f" Received Init Request, {msg.UNK:x}") + + @msg(0x1, DIR.TX, InitResp) + def init_resp(self, msg): + print(f" CPU Sent Init Response {msg.UNK1:x}, ADDR: {msg.ADDR:x}") + + # monitor whatever is at this address + self.tracer.mon_addva(msg.ADDR, 0x4000, "init_region") + self.tracer.mon.poll() + return True + +class GpuMsg(Register64): + TYPE = 55, 48 + +class PongMsg(GpuMsg): + TYPE = 59, 52 + UNK = 47, 0 + +class PongEp(EP): + # This endpoint recives pongs. The cpu code reads some status registers after receiving one + # Might be a "work done" message. + BASE_MESSAGE = GpuMsg + + @msg(0x42, DIR.RX, PongMsg) + def pong_rx(self, msg): + print(f" Pong {msg.UNK:x}") + if msg.UNK != 0: + print(f" Pong had unexpected value{msg.UNK:x}") + self.hv.run_shell() + + self.tracer.pong() + return True + + @msg(0x81, DIR.TX, PongMsg) + def init_ep(self, msg): + print(f" Init {msg.UNK:x}") + + addr = msg.UNK + + #self.tracer.mon_addva(addr, 0x4000, "control_struct") + control = ControlStruct.parse(self.tracer.uat.ioread(0, addr, 0x34)) + #self.tracer.mon_addva(control.unkptr_0, 0x4000, "control_struct->unkptr_0") + # self.tracer.mon_addva(control.unkptr_10, 0x34000, "control_struct->unkptr_10") + # self.tracer.mon_addva(control.unkptr_18, 0x88000, "control_struct->unkptr_18") + #self.tracer.mon_addva(control.unkptr_20, 0x4000, "control_struct->unkptr_20") + self.tracer.control = control + + self.tracer.mon.poll() + + self.tracer.kick_init() + return True + +class KickMsg(GpuMsg): + TYPE = 59, 52 + KICK = 7, 0 # Seen: 17, 16 (common), 9, 8, 1 (common), 0 (common) + +class KickEp(EP): + BASE_MESSAGE = GpuMsg + + @msg(0x83, DIR.TX, KickMsg) + def kick(self, msg): + print(f" Kick {msg.KICK:x}") + self.tracer.kick(msg.KICK) + + return True + +class AGXTracer(ASCTracer): + ENDPOINTS = { + 0x01: InitEp, + 0x20: PongEp, + 0x21: KickEp + } + + PAGESIZE = 0x4000 + + def __init__(self, hv, devpath, verbose=False): + super().__init__(hv, devpath, verbose) + self.uat = UAT(hv.iface, hv.u) + self.mon = RegMonitor(hv.u, ascii=True) + self.dev_sgx = hv.u.adt["/arm-io/sgx"] + self.gpu_region = getattr(self.dev_sgx, "gpu-region-base") + self.gpu_region_size = getattr(self.dev_sgx, "gpu-region-size") + self.gfx_shared_region = getattr(self.dev_sgx, "gfx-shared-region-base") + self.gfx_shared_region_size = getattr(self.dev_sgx, "gfx-shared-region-size") + self.gfx_handoff = getattr(self.dev_sgx, "gfx-handoff-base") + self.gfx_handoff_size = getattr(self.dev_sgx, "gfx-handoff-size") + + # self.mon.add(self.gpu_region, self.gpu_region_size, "contexts") + # self.mon.add(self.gfx_shared_region, self.gfx_shared_region_size, "gfx-shared") + # self.mon.add(self.gfx_handoff, self.gfx_handoff_size, "gfx-handoff") + + self.uat.set_ttbr(self.gpu_region) + + def mon_addva(self, va, size, name=""): + self.mon.add(va, size, name, readfn= lambda a, s: self.uat.ioread(0, a, s)) + + def kick(self, val): + self.mon.poll() + + # if val not in [0x0, 0x1, 0x10, 0x11]: + # self.hv.run_shell() + + def pong(self): + self.mon.poll() + + def kick_init(self): + self.hv.run_shell() +