DF-5518 / gen_gpio.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 | #!/usr/bin/env python3 """ gen_gpio.py -- craft the RSDP->RSDT->[FACP->FACS+DSDT, MADT] chain for the DF-5518 rig (sys/bus/gpio/gpio_acpi/gpio_acpi.c: in-flight GPIO address-space handler vs. driver detach). Injection model: identical to the proven madt-batch / DF-5483 vector: guest booted with loader kenv hint.acpi.0.rsdp=0x40000000 (sys/platform/pc64/acpica/acpi_sdt.c -- hinted RSDP accepted with NO signature/checksum validation), chain planted by QEMU -device loader,file=<blob>,addr=0x40000000,force-raw=on. FADT (rev1, 128 bytes) cloned PM blocks from the guest's SeaBIOS FADT so AcpiEnableSubsystem() finds working PM1/GPE blocks; DSDT pointer is ours. """ import struct import sys BASE = 0x40000000 RSDP_OFF = 0x0000 RSDT_OFF = 0x0100 FADT_OFF = 0x0200 FACS_OFF = 0x0280 MADT_OFF = 0x0400 DSDT_OFF = 0x1000 NITER = 200000 # hammer iterations inside _TMP (after register plant) # chv_n_ranges (gpio_cherryview.c, _UID=2): all valid pins, ascending PINS = (list(range(0, 9)) + list(range(15, 28)) + list(range(30, 42)) + list(range(45, 57)) + list(range(60, 73))) assert len(PINS) == 59 # FLD0 result bit i = RXSTATE of PINS[i]; gpoke plants RXSTATE=1 on even # physical pins -> magic has bit i set iff PINS[i] is even. MAGIC = 0 for i, p in enumerate(PINS): if p % 2 == 0: MAGIC |= 1 << i def csum(b): return (-sum(b)) & 0xFF def sdth(sig, length, rev): h = bytearray(36) h[0:4] = sig struct.pack_into('<I', h, 4, length) h[8] = rev h[9] = 0 h[10:16] = b'DFBSD ' h[17:21] = b'PASS' struct.pack_into('<I', h, 21, 1) h[25:29] = b'IACT' struct.pack_into('<I', h, 29, 1) return h def build(dsdt, ncpu=6): # MADT: LAPIC entries + the real QEMU IOAPIC (keeps PCI ints working) ent = b'' for i in range(ncpu): ent += struct.pack('<BBBBI', 0, 8, i, i, 1) # LAPIC ent += struct.pack('<BBBBII', 1, 12, 0, 0, 0xFEC00000, 0) # IOAPIC madt = sdth(b'APIC', 44 + len(ent), 3) + bytearray(8) struct.pack_into('<I', madt, 36, 0xFEE00000) struct.pack_into('<I', madt, 40, 1) madt += ent madt[9] = csum(madt) # FACS facs = bytearray(64) facs[0:4] = b'FACS' struct.pack_into('<I', facs, 4, 64) # FADT rev1, PM blocks cloned from SeaBIOS/QEMU fadt = sdth(b'FACP', 128, 1) fadt += bytearray(128 - 36) struct.pack_into('<I', fadt, 36, BASE + FACS_OFF) struct.pack_into('<I', fadt, 40, BASE + DSDT_OFF) fadt[44] = 1 fadt[45] = 0 struct.pack_into('<H', fadt, 46, 9) # SCI_INT struct.pack_into('<I', fadt, 48, 0xb2) # SMI_CMD fadt[52] = 0xf1 fadt[53] = 0xf0 struct.pack_into('<I', fadt, 56, 0x600) # PM1a_EVT struct.pack_into('<I', fadt, 64, 0x604) # PM1a_CNT struct.pack_into('<I', fadt, 76, 0x608) # PM_TMR struct.pack_into('<I', fadt, 80, 0xafe0) # GPE0 fadt[88] = 4 fadt[89] = 2 fadt[91] = 4 fadt[92] = 4 struct.pack_into('<I', fadt, 96, 0x0fff) struct.pack_into('<I', fadt, 100, 0x0fff) fadt[9] = csum(fadt) rsdt = sdth(b'RSDT', 36 + 8, 1) + bytearray(8) struct.pack_into('<I', rsdt, 36, BASE + FADT_OFF) struct.pack_into('<I', rsdt, 40, BASE + MADT_OFF) rsdt[9] = csum(rsdt) rsdp = bytearray(20) rsdp[0:8] = b'RSD PTR ' rsdp[8] = 0 rsdp[9:15] = b'DFBSD ' rsdp[15] = 0 struct.pack_into('<I', rsdp, 16, BASE + RSDT_OFF) blob = bytearray(DSDT_OFF + len(dsdt)) blob[RSDP_OFF:RSDP_OFF + 20] = rsdp blob[RSDT_OFF:RSDT_OFF + len(rsdt)] = rsdt blob[FADT_OFF:FADT_OFF + len(fadt)] = fadt blob[FACS_OFF:FACS_OFF + len(facs)] = facs blob[MADT_OFF:MADT_OFF + len(madt)] = madt blob[DSDT_OFF:DSDT_OFF + len(dsdt)] = dsdt return bytes(blob) if __name__ == '__main__': if sys.argv[1] == 'subst': d = open(sys.argv[2]).read() d = d.replace('@ITER@', str(NITER)).replace('@MAGIC@', hex(MAGIC)) open(sys.argv[3], 'w').write(d) sys.stderr.write('substituted: N=%d magic=0x%X\n' % (NITER, MAGIC)) sys.exit(0) aml_file, out = sys.argv[2], sys.argv[3] with open(aml_file, 'rb') as f: dsdt = f.read() assert dsdt[:4] == b'DSDT', 'not a DSDT' with open(out, 'wb') as f: f.write(build(dsdt)) sys.stderr.write('blob: %d bytes (DSDT %d, hammer N=%d, magic=0x%X)\n' % (DSDT_OFF + len(dsdt), len(dsdt), NITER, MAGIC)) |