⬢ DragonFlyBSD Kernel Audit
DF-2307 / gen_aei.py
← back to finding ↓ download raw
#!/usr/bin/env python3
"""
gen_aei.py -- build the planted ACPI table chain (RSDP->RSDT->[FACP->FACS+DSDT])
and the Cherry-View register-image blob for the DF-2307 AEI rig.

The table builder is the PROVEN DF-5518 gen_gpio.py build() (same injection
model: kenv hint.acpi.0.rsdp=0x40000000 + QEMU -device loader blobs), with
the DF-2307 AEI DSDT in place of the thermal-hammer one.

Usage:
  gen_aei.py chain dsdt_aei.aml aei_chain.bin
  gen_aei.py regs chv_regs.bin     # 0x8000B image @0xD0000
"""
import struct
import sys

BASE     = 0x40000000
RSDP_OFF = 0x0000
RSDT_OFF = 0x0100
FADT_OFF = 0x0200
FACS_OFF = 0x0280
MADT_OFF = 0x0400
DSDT_OFF = 0x1000


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)


def build_regs():
    """Cherry-View register image: 0x8000 bytes @0xD0000.

    PIN_ADDRESS(2) = 0x4400 + (2/15)*0x400 + (2%15)*8 = 0x4410
    CTL0 @0x4410, CTL1 @0x4414.
    """
    blob = bytearray(0x8000)
    ctl0 = 0x40008200          # intline nibble 4 | GPIOEN | GPIOCFG=0x200
    ctl1 = 0x00000002          # INTCFG=2 (edge, rising)
    struct.pack_into('<I', blob, 0x4410, ctl0)
    struct.pack_into('<I', blob, 0x4414, ctl1)
    return bytes(blob)


def main():
    if sys.argv[1] == 'chain':
        with open(sys.argv[2], 'rb') as f:
            dsdt = f.read()
        assert dsdt[:4] == b'DSDT', 'not a DSDT'
        blob = build(dsdt)
        open(sys.argv[3], 'wb').write(blob)
        sys.stderr.write('chain: %d bytes (DSDT %d)\n' %
                         (len(blob), len(dsdt)))
    elif sys.argv[1] == 'regs':
        blob = build_regs()
        open(sys.argv[2], 'wb').write(blob)
        sys.stderr.write('regs: %d bytes (CTL0(2)=0x40008200 @0x4410, '
                         'CTL1(2)=0x2 @0x4414)\n' % len(blob))


if __name__ == '__main__':
    main()