diff options
Diffstat (limited to 'tools/proxyclient/m1n1/fw/agx/handoff.py')
| -rw-r--r-- | tools/proxyclient/m1n1/fw/agx/handoff.py | 120 |
1 files changed, 120 insertions, 0 deletions
diff --git a/tools/proxyclient/m1n1/fw/agx/handoff.py b/tools/proxyclient/m1n1/fw/agx/handoff.py new file mode 100644 index 0000000..4f9acf0 --- /dev/null +++ b/tools/proxyclient/m1n1/fw/agx/handoff.py @@ -0,0 +1,120 @@ +# SPDX-License-Identifier: MIT +from ...utils import * +from contextlib import contextmanager + +PPL_MAGIC = 0x4b1d000000000002 + +class GFXHandoffStruct(RegMap): + MAGIC_AP = 0x0, Register64 + MAGIC_FW = 0x8, Register64 + + LOCK_AP = 0x10, Register8 + LOCK_FW = 0x11, Register8 + TURN = 0x14, Register32 + + CUR_CTX = 0x18, Register32 + + FLUSH_STATE = irange(0x20, 0x41, 0x18), Register64 + FLUSH_ADDR = irange(0x28, 0x41, 0x18), Register64 + FLUSH_SIZE = irange(0x30, 0x41, 0x18), Register64 + + UNK2 = 0x638, Register8 + UNK3 = 0x640, Register64 + +class GFXHandoff: + def __init__(self, u): + self.u = u + self.sgx_dev = self.u.adt["/arm-io/sgx"] + self.base = self.sgx_dev.gfx_handoff_base + self.reg = GFXHandoffStruct(u, self.base) + self.is_locked = False + self.initialized = False + + @contextmanager + def lock(self): + """Dekker's algorithm lock""" + assert not self.is_locked + + # Note: This *absolutely* needs barriers everywhere. + # Those are implicit in proxyclient for every operation. + + self.reg.LOCK_AP.val = 1 + while self.reg.LOCK_FW.val != 0: + if self.reg.TURN != 0: + self.reg.LOCK_AP = 0 + while self.reg.TURN != 0: + pass + self.reg.LOCK_AP = 1 + + self.is_locked = True + try: + yield + finally: + self.reg.TURN.val = 1 + self.reg.LOCK_AP.val = 0 + self.is_locked = False + + def initialize(self): + if self.initialized: + return + + print("[Handoff] Initializing...") + + self.reg.MAGIC_AP.val = PPL_MAGIC + self.reg.UNK = 0xffffffff + self.reg.UNK3 = 0 + + with self.lock(): + print("[Handoff] Waiting for FW PPL init...") + while self.reg.MAGIC_FW.val != PPL_MAGIC: + pass + + for i in range(0x41): + self.reg.FLUSH_STATE[i].val = 0 + self.reg.FLUSH_ADDR[i].val = 0 + self.reg.FLUSH_SIZE[i].val = 0 + + self.initialized = True + print("[Handoff] Initialized!") + + # The order here is: + # - Remap memory as shared + # - TLBI + # - prepare_cacheflush() + # - issue FWCtl request + # - wait for completion (ring or wait_cacheflush?) + # - Unmap memory + # - TLBI + # - complete_cacheflush() + def prepare_cacheflush(self, base, size, context=0x40): + assert self.reg.FLUSH_STATE[context].val == 0 + + self.reg.FLUSH_ADDR[context].val = base + self.reg.FLUSH_SIZE[context].val = size + self.reg.FLUSH_STATE[context].val = 1 + + def wait_cacheflush(self, context=0x40): + while self.reg.FLUSH_STATE[context].val == 1: + pass + + def complete_cacheflush(self, context=0x40): + assert self.reg.FLUSH_STATE[context].val == 2 + self.reg.FLUSH_STATE[context].val = 0 + + # probably not necessary? + # order is: + # - Remap memory as shared + # - (no TLBI?) + # - prepare_unmap() + # - unmap + # - TLBI + # - complete_unmap() + def prepare_unmap(self, base, size, context): + assert self.reg.FLUSH_STATE[context].val == 0 + self.reg.FLUSH_ADDR[context].val = 0xdead000000000000 | (base & 0xffffffffffff) + self.reg.FLUSH_SIZE[context].val = size + self.reg.FLUSH_STATE[context].val = 2 + + def complete_unmap(self, context): + assert self.reg.FLUSH_STATE[context].val == 2 + self.reg.FLUSH_STATE[context].val = 0 |
