summaryrefslogtreecommitdiff
path: root/tools/proxyclient/m1n1/fw/agx/handoff.py
diff options
context:
space:
mode:
Diffstat (limited to 'tools/proxyclient/m1n1/fw/agx/handoff.py')
-rw-r--r--tools/proxyclient/m1n1/fw/agx/handoff.py120
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