DF-5745 / make_ssdt.py
#!/usr/bin/env python3 """ make_ssdt.py -- emit a minimal SSDT for the apple_gmux planted-ACPI rig. Hand-encodes AML (no iasl needed): DefinitionBlock ("", "SSDT", 2, "AUDIT", "GMUXRIG", 0x1) { Scope (\_SB) { Device (<NAME>) { Name (_HID, "APP000B") /* gmux HID, apple-gmux.c:708 */ Name (_STA, 0x0F) /* present + functional */ Name (_CRS, ResourceTemplate () { IO (Decode16, <BASE>, <BASE>, 0x01, 0x04) /* 4-byte I/O window */ }) } ... } } The 4-byte _CRS is the rig's point: apple_gmux attach never validates the allocated I/O resource length (GMUX_MIN_IO_LEN at apple-gmux.c:77 is dead code), so the production driver reads/writes gmux register offsets (0x04..0x06, 0xcc..0xce, 0xd0, 0xd4) far past the 4-byte allocation. Usage: make_ssdt.py <out.aml> NAME0=BASE0 [NAME1=BASE1 ...] Bases are hex without 0x, e.g.: make_ssdt.py ssdt_b.aml AAA0=8e AAA2=4cc """ import sys def pkglen(n): """ACPI PkgLength (no EISAID tricks, just the standard encoding).""" if n < 63: return bytes([n]) assert n < 4096, "rig does not need bigger lengths" return bytes([0x40 | (n & 0x0F), (n >> 4) & 0xFF]) def nameop_path(path): """NameOp + 4-char name (e.g. _HID -> 08 5F 48 49 44).""" assert len(path) == 4 return b"\x08" + path.encode() def device(name, base, length=4): assert len(name) == 4 body = b"" # Name (_HID, "APP000B") -- StringPrefix 0x0D + 7 chars + NUL body += nameop_path("_HID") + b"\x0D" + b"APP000B\x00" # Name (_STA, 0x0F) -- BytePrefix 0x0A body += nameop_path("_STA") + b"\x0A\x0F" # Name (_CRS, Buffer { IO(Decode16, base, base, 1, 4), EndTag }) # Small I/O descriptor 0x47: flags(1) min(2) max(2) aln(1) len(1) # -> 0x47 + 7 data bytes (small-descriptor length field is 3 bits, max 7). # Matches QEMU DSDT convention, e.g. COM1: 47 01 f8 03 f8 03 00 08. io_desc = bytes([0x47, 0x01, base & 0xFF, (base >> 8) & 0xFF, base & 0xFF, (base >> 8) & 0xFF, 0x01, length]) # EndTag: 0x79 0x00 (checksum byte 0, matching iasl-emitted templates; # a computed nonzero byte makes ACPICA reject the table at load time) buf_bytes = io_desc + bytes([0x79, 0x00]) buf_size_field = b"\x0A" + bytes([len(buf_bytes)]) inner = buf_size_field + buf_bytes body += nameop_path("_CRS") + b"\x11" + pkglen(len(inner)) + inner # DeviceOp 0x5B 0x82 <PkgLen> <Name4> <body> total = 4 + len(body) return b"\x5B\x82" + pkglen(total) + name.encode() + body def main(): out = sys.argv[1] devices = [] for spec in sys.argv[2:]: nm, rest = spec.split("=") if ":" in rest: base, ln = rest.split(":") devices.append(device(nm, int(base, 16), int(ln, 16))) else: devices.append(device(nm, int(base, 16))) scope_body = b"\x5C\x5F\x53\x42\x5F" + b"".join(devices) # \_SB scope = b"\x10" + pkglen(len(scope_body)) + scope_body header = bytearray(36) header[0:4] = b"SSDT" header[6] = 2 # revision header[10:16] = b"AUDIT " # OEMID (6) header[16:24] = b"GMUXRIG1" # OEM table id (8) header[24:28] = (1).to_bytes(4, "little") header[28:32] = b"INTL" header[32:36] = (1).to_bytes(4, "little") table = bytes(header) + scope table = table[:4] + len(table).to_bytes(4, "little") + table[8:] checksum = (0x100 - (sum(table) & 0xFF)) & 0xFF table = table[:9] + bytes([checksum]) + table[10:] with open(out, "wb") as f: f.write(table) print("wrote %s (%d bytes, csum 0x%02x)" % (out, len(table), checksum)) if __name__ == "__main__": main() |