mirror of
https://github.com/AsahiLinux/m1n1
synced 2024-12-28 06:03:04 +00:00
45c3682f60
Signed-off-by: Hector Martin <marcan@marcan.st>
202 lines
5.5 KiB
Python
202 lines
5.5 KiB
Python
# SPDX-License-Identifier: MIT
|
|
import struct
|
|
|
|
from ..utils import *
|
|
|
|
from .asc import StandardASC
|
|
from .asc.base import *
|
|
|
|
SMC_READ_KEY = 0x10
|
|
SMC_WRITE_KEY = 0x11
|
|
SMC_GET_KEY_BY_INDEX = 0x12
|
|
SMC_GET_KEY_INFO = 0x13
|
|
SMC_INITIALIZE = 0x17
|
|
SMC_NOTIFICATION = 0x18
|
|
SMC_RW_KEY = 0x20
|
|
|
|
class SMCMessage(Register64):
|
|
TYPE = 7, 0
|
|
UNK = 11, 8, Constant(0)
|
|
ID = 15, 12
|
|
|
|
class SMCInitialize(SMCMessage):
|
|
TYPE = 7, 0, Constant(SMC_INITIALIZE)
|
|
|
|
class SMCGetKeyInfo(SMCMessage):
|
|
TYPE = 7, 0, Constant(SMC_GET_KEY_INFO)
|
|
KEY = 63, 32
|
|
|
|
class SMCGetKeyByIndex(SMCMessage):
|
|
TYPE = 7, 0, Constant(SMC_GET_KEY_BY_INDEX)
|
|
INDEX = 63, 32
|
|
|
|
class SMCWriteKey(SMCMessage):
|
|
TYPE = 7, 0, Constant(SMC_WRITE_KEY)
|
|
SIZE = 23, 16
|
|
KEY = 63, 32
|
|
|
|
class SMCReadKey(SMCMessage):
|
|
TYPE = 7, 0, Constant(SMC_READ_KEY)
|
|
SIZE = 23, 16
|
|
KEY = 63, 32
|
|
|
|
class SMCReadWriteKey(SMCMessage):
|
|
TYPE = 7, 0, Constant(SMC_RW_KEY)
|
|
RSIZE = 23, 16
|
|
WSIZE = 31, 24
|
|
KEY = 63, 32
|
|
|
|
class SMCResult(Register64):
|
|
RESULT = 7, 0
|
|
ID = 15, 12
|
|
SIZE = 31, 16
|
|
VALUE = 63, 32
|
|
|
|
class SMCError(Exception):
|
|
pass
|
|
|
|
class SMCEndpoint(ASCBaseEndpoint):
|
|
BASE_MESSAGE = SMCMessage
|
|
SHORT = "smcep"
|
|
TYPE_MAP = {
|
|
"ui64": ("<Q", None),
|
|
"ui32": ("<I", None),
|
|
"ui16": ("<H", None),
|
|
"ui8 ": ("<B", None),
|
|
"si64": ("<q", None),
|
|
"si32": ("<i", None),
|
|
"si16": ("<h", None),
|
|
"si8 ": ("<b", None),
|
|
"flag": ("<B", None),
|
|
"flt ": ("<f", None),
|
|
"hex_": (None, hexdump),
|
|
"ch8*": (None, lambda c: c.split(b"\x00")[0]),
|
|
"ioft": ("<Q", None),
|
|
}
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super().__init__(*args, **kwargs)
|
|
self.shmem = None
|
|
self.msgid = 0
|
|
self.outstanding = set()
|
|
self.ret = {}
|
|
|
|
def start(self):
|
|
self.send(SMCInitialize(ID = 0))
|
|
self.msgid += 1 # important!
|
|
while self.shmem is None:
|
|
self.asc.work()
|
|
|
|
def new_msgid(self):
|
|
mid = (self.msgid & 0xF)
|
|
self.msgid += 1
|
|
assert(mid not in self.outstanding)
|
|
self.outstanding.add(mid)
|
|
return mid
|
|
|
|
def cmd(self, cmd):
|
|
cmd.ID = self.new_msgid()
|
|
self.send(cmd)
|
|
while cmd.ID in self.outstanding:
|
|
self.asc.work()
|
|
ret = self.ret[cmd.ID]
|
|
if ret.RESULT != 0:
|
|
raise SMCError(f"SMC error {ret}", ret)
|
|
return ret
|
|
|
|
def write(self, key, data):
|
|
key = int.from_bytes(key.encode("ascii"), byteorder="big")
|
|
self.asc.iface.writemem(self.shmem, data)
|
|
self.cmd(SMCWriteKey(KEY = key, SIZE = len(data)))
|
|
|
|
def read(self, key, size):
|
|
key = int.from_bytes(key.encode("ascii"), byteorder="big")
|
|
ret = self.cmd(SMCReadKey(KEY = key, SIZE = size))
|
|
if size <= 4:
|
|
return struct.pack("<I", ret.VALUE)[:size]
|
|
else:
|
|
return self.asc.iface.readmem(self.shmem, ret.SIZE)
|
|
|
|
def rw(self, key, data, outsize):
|
|
key = int.from_bytes(key.encode("ascii"), byteorder="big")
|
|
self.asc.iface.writemem(self.shmem, data)
|
|
ret = self.cmd(SMCReadWriteKey(KEY=key, RSIZE=outsize, WSIZE=len(data)))
|
|
if outsize <= 4:
|
|
return struct.pack("<I", ret.VALUE)[:outsize]
|
|
else:
|
|
return self.asc.iface.readmem(self.shmem, ret.SIZE)
|
|
|
|
def get_key_by_index(self, index):
|
|
ret = self.cmd(SMCGetKeyByIndex(INDEX = index))
|
|
key = ret.VALUE.to_bytes(4, byteorder="little").decode("ascii")
|
|
return key
|
|
|
|
def get_key_info(self, key):
|
|
key = int.from_bytes(key.encode("ascii"), byteorder="big")
|
|
ret = self.cmd(SMCGetKeyInfo(KEY = key))
|
|
info = self.asc.iface.readmem(self.shmem, 6)
|
|
length, type, flags = struct.unpack("B4sB", info)
|
|
return length, type.decode("ascii"), flags
|
|
|
|
def read64(self, key):
|
|
return struct.unpack("<Q", self.read(key, 8))[0]
|
|
|
|
def read32(self, key):
|
|
return struct.unpack("<I", self.read(key, 4))[0]
|
|
|
|
def read16(self, key):
|
|
return struct.unpack("<H", self.read(key, 2))[0]
|
|
|
|
def read8(self, key):
|
|
return struct.unpack("<B", self.read(key, 1))[0]
|
|
|
|
def read32b(self, key):
|
|
return struct.unpack(">I", self.read(key, 4))[0]
|
|
|
|
def write64(self, key, data):
|
|
self.write(key, struct.pack("<Q", data))
|
|
|
|
def write32(self, key, data):
|
|
self.write(key, struct.pack("<I", data))
|
|
|
|
def write16(self, key, data):
|
|
self.write(key, struct.pack("<H", data))
|
|
|
|
def write8(self, key, data):
|
|
self.write(key, struct.pack("<B", data))
|
|
|
|
def rw32(self, key, data):
|
|
return struct.unpack("<I", self.rw(key, struct.pack("<I", data), 4))[0]
|
|
|
|
def read_type(self, key, size, typecode):
|
|
fmt, func = self.TYPE_MAP.get(typecode, (None, None))
|
|
|
|
val = self.read(key, size)
|
|
|
|
if fmt:
|
|
val = struct.unpack(fmt, val)[0]
|
|
if func:
|
|
val = func(val)
|
|
return val
|
|
|
|
def handle_msg(self, msg0, msg1):
|
|
if self.shmem is None:
|
|
self.log("Starting up")
|
|
self.shmem = msg0
|
|
else:
|
|
msg = SMCResult(msg0)
|
|
ret = msg.RESULT
|
|
mid = msg.ID
|
|
if ret == SMC_NOTIFICATION:
|
|
self.log(f"Notification: {msg.VALUE:#x}")
|
|
return True
|
|
#print(f"msg {mid} return value {ret}")
|
|
self.outstanding.discard(mid)
|
|
self.ret[mid] = msg
|
|
|
|
return True
|
|
|
|
class SMCClient(StandardASC):
|
|
ENDPOINTS = {
|
|
0x20: SMCEndpoint,
|
|
}
|