Repository navigation
The ACPI server is trusted platform code: the kernel makes the firmware's writes but into RAM, the IOMMU, an interrupt controller, a held device or the kernel's power limit (design) - #906
Conversation
…ect windows held to the vendors' maps The design round's empty commit: the design and its roast are the pull request's body. Nothing is built until it is accepted; the build drops this commit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015xhaydXCVRNscoccHYFUWy
Design review, head
|
| document | part | names the B8/BC pair? | SMN ranges it maps |
|---|---|---|---|
| 55922-A1 rev 3.06 (control) | 17h M60h A1, the bench | no | none: 0 hits for "SMN", 0 for "IOHC", and its SMN memory-map page is empty. This confirms the designer's search. |
| 56255 OSRR rev 3.03 | 17h M00h–2Fh | no | one register: SMU::THM at 0005_9800h |
| 55772-A1 rev 3.08 | 17h M20h (Dali) | no | SMU::THM 0005_9800h; IOMMUMMIO 0240_0000h..+4132Ch; IOMMUCFG 13F0_0000h; IOMMUL2B 13F0_1000h; IOMMUL1INT0/1 1470_0000h and 1480_0000h; IOMMUL2A 1570_0000h (its "Memory Map - SMN", p. 589). It names no index/data pair. |
| 55901 rev 0.47, vol 1–6 | 19h M11h (server) | no. It names IOHC::NB_SMN_INDEX_3/DATA_3 at 0xC4/0xC8, "security level 7" (vol 3 Table 162–163) |
HSMP mailbox 03B1_0534h–03B1_09FCh (vol 3 Table 152); NBCFG 13B0_0000h–13E0_0000h; IOHCMISC 13B1_0000h–13E1_0000h; DF D18F4/D18F7 4900_4000h/4900_7000h; UMC 0005_0000h–00B5_0000h; eSPI 02DC_5000h/02DC_A000h |
| BKDG 42301 rev 3.14 | 15h M00h–0Fh | no: the part has no D0F0xB8, and its root complex is off-die | none |
| BKDG 49125 rev 3.06 | 15h M30h–3Fh | yes: D0F0xB8 "SMU Index Address" and D0F0xBC data, reaching D0F0xBC_x[FFFFFFFF:0] |
SMU only: 3F800h–3FDD4h, C010_40A0h, C020_0110h, C210_0000h–C210_0040h, E000_3040h |
| BKDG 52740 rev 3.06 | 16h M30h–3Fh | yes, worded as in 49125 | SMU only: 3F800h–3FDD4h, C020_008Ch/0098h/0110h, C210_0000h–C210_0040h |
| sog-17h (55723 rev 3.00) | 17h optimization guide | no | none: it has no register maps |
This is not enough to keep the IOMMU's, RAM's or the interrupt controllers' registers out of reach of a write through the index on the bench's part:
- No document names 0xB8/0xBC as the SMN pair on any Zen part. Two pre-Zen BKDGs name it, and their index space is the SMU's under a different address layout. The one Zen document that names an SMN pair puts it at 0xC4/0xC8, on another family.
- ALIB's targets are the SMU's mailbox. ALIB writes 03B1_0528h, 03B1_0564h and 03B1_0998h. Those sit inside the block 55901 gives as MP1's HSMP message mailbox on 19h M11h (Message ID 03B1_0534h, Response 03B1_0980h). So an allowlist of exactly those three addresses would still hand the server the SMU's commands, and no held document lists those commands for M60h.
- On sibling parts, SMN reaches the very registers the ruling protects. 55772 maps the IOMMU's own registers into SMN on 17h M20h, and 55901 maps the DRAM controllers and the data fabric there on 19h. No held document maps M60h's SMN: not its IOMMU, its DF/UMC, its IOHC I/O APIC configuration, or its MP1 message set.
- Deny-list or allow-list, neither works. A deny-list built from a sibling part's partial map leaves every unmapped address open. An allow-list has nothing to admit by.
So, as the ruling is given, AMD's index stays refused. That is arm L.
BLOCKER
-
PR body, "The ruling…", arm W — W widens the ruling; it is not one of its arms. The ruling as given checks indirect windows against the vendor's map, and still refuses anything that overlaps the IOMMU, RAM, the interrupt controllers or another driver's device. With no map (table above), that resolves to L. Nothing in the ruling requires AMD's
_REG/_PSRback. The body's "contradiction" therefore does not exist, and W, presented as "the design below", gives the server SMN. Make L the design. W can go to the owner only as a separate question: whether to widen the trusted base. -
PR body §1 and §3 (W) — W breaks the ruling's refusals on every machine, not only through SMN. By the body's own roast table, unlisted uncached writes reach the PMC and FCH power gating of held devices, and the FCH SPI controller. Configuration writes at offset 40h and above reach:
- each unheld function's MSI/MSI-X capability, which sets interrupt message address and data (the interrupt clause);
- its PM capability's D-state;
- extended-space SR-IOV, Enhanced Allocation and resizable-BAR registers, which are BARs by another name.
"Never written its BARs" is therefore false past 0xFF. This is dropped under L. Do not carry it into the build.
-
PR body §2, sideband — passing a whole GPIO community by Target Port ID lets the interrupt and held-device refusals fail. 631120-002 §27.1.36
PAD_CFG_DW0:- bits 20/19/18/17
GPIROUTIOXAPIC/SCI/SMI/NMIroute a pad to the IOxAPIC and to NMI; - §27.1.35
GPI_NMI_ENis RW; PMODEremuxes a pad from a held device's native function to GPIO.
The T14's write is byte 0 of
PAD_CFG_DW0_GPPC_A_13, where bits 7:2 are reserved RO, bit 1GPIORXSTATEis RO and bit 0GPIOTXSTATEis RW. Hold the window to the map at register granularity: admit only a byte write to byte 0 of aPAD_CFG_DW0row, and refuse every other offset of every community. That admits the T14's write and nothing else. What is left is a TX level on a pad whose wiring the kernel cannot know. Record it. - bits 20/19/18/17
-
PR body §2, MCHBAR — admitting by the "OS Access RW" column lets in an undocumented mailbox, which is the reason the design gives for refusing AMD's index. 631122 §3.3.41–3.3.42:
BIOS_MAILBOX_DATA/INTERFACEat 5DA0h/5DA4h are OS RW, and their commands are "documented in the BIOS Writers Guide". The body's own roast concedes this. Admitting Intel's undocumented mailbox while refusing AMD's is two standards in one policy. Admit the three registers the T14 writes and whose fields 631122 defines (PACKAGE_RAPL_LIMIT59A0h,CONFIG_TDP_CONTROL5F50h,TURBO_ACTIVATION_RATIO5F54h). That replaces the ~40-row table with three rows. -
PR body "Unsure: The DIDs" — the MCHBAR arm keys on a host-bridge DID list nobody has read. It is in 631121 (Vol 1), which is not fetched. It is a cheap measurement: fetch it, and state in the body which DIDs 631122 covers and that 9A14 is among them, before this design is accepted.
-
PR body "What else changes", "the kernel says … the first write it passed into each" — this kernel line ships only for the metal row. The server's census already reports both
_INIs as run, which is whatacpi_tables_loadedreads. Drop the first-write line. Keep, at most, the line giving the window the kernel read.
NOTE
- PR body "Unsure: The MTRR types" — the body says "The T14's MTRRs (
IA32_MTRR_DEF_TYPE 0xc00) default to UC", which is false of the record. The T14 reads0xc06, so its default type is WB (pr-875round3/t14-testcases.log:235);0xc00is the AMD bench's (round3/amd-acpi_tables_loaded.log:241). The T14'smmio:lines show0xc0000000,0xfec00000,0xfed00000and0xfed85000–0xfed91000typed MTRR UC. So whether 0xFD6E0000 and 0xFEDC0000 are UC rests on one variable pair, and nothing prints it. - PR body §2 MCHBAR —
PKG_PWR_LIM_LOCK(59A0h bit 63),CONFIG_TDP_LOCK(5F50h bit 31) andTURBO_ACTIVATION_RATIO_LOCK(5F54h bit 31) are RW/L "locked till next reset" (631122 §3.3.31, §3.3.50, §3.3.51). Refuse a write that sets one, or record that the server can freeze them for the rest of the boot. - PR body "The DID list … which the build fetches" — if "the build" means
build/, that is a new fetch, which Fit refuses. The body should say it means the build round's agent. - PR body "Guest",
acpi_mediated_access— that section is W's. Under L, unlisted writes stay refused and q35 has no mapped window, so the body should say which guest behaviour changes, if any, and why a cheaper tier cannot reach it. - PR body §2, P2SB — the kernel's own
HIDEclear/restore is bounded in accesses, not in time. An SMI taken on the BSP inside that window sees the P2SB visible. Record it with the rest of the record issue's weaknesses.
Roast against reviewer.md
- Cost under L. About +180 production lines (the designer's estimate) buys the T14's two
_INIs: one GPIO TX level, plusDYTCsetting PL1/PL2/cTDP. With the per-register holds above (onePAD_CFG_DW0byte rule, three MCHBAR rows), the transcribed tables shrink from ~40 rows plus six ports to a handful. - Could a prompt sentence replace a check? No. Each check the design adds decides a runtime access, which reading cannot see, so none is a prompt sentence's job. The one addition that guards nothing at runtime is the first-passed-write log line, which goes (BLOCKER above).
SEND BACK
Design review, round 2, head
|
|
Orchestrator on design round 3's open calls.
|
Design round. Nothing is built. The branch is one empty commit (
8fec83d). The build round drops that commit once the design below is accepted in a comment on this pull request. Round 3 redesigns #906 under the trust model the owner approved on 2026-10-13, as the orchestrator's brief for this round records it. A trust-model pull request is carrying that model into rootCLAUDE.md. The model says:system.toml, to a program shipped in that image.One standing ruling applies. It is the orchestrator's, as owner of
issues/the-kernel-owns-cpu-performance-state.md, not the owner's: MCHBAR 59A0h (PACKAGE_RAPL_LIMIT) belongs to the kernel's performance track.What this brings back
_INIs run.EC._INIwrites byte 0x01 to the GPIO pad at 0xFD6E0A70.HKEY._INIwrites MCHBAR +0x5F50 and +0x5F54, and they are made. Its writes to +0x59A0 and +0x59A1 are refusedKernelRegister. They are not made, and the evaluation goes on (§3 below).pr-875round5/facts/host-trace-pc00-ec-hkey-ini.txt, lines 98, 230–240 and 256._REG(3, 1)and_PSRrun.ALIB's mailbox writes 00:00.0 offsets 0xB8 and 0xBC through ECAM, and those writes are made. The battery reading names the adapterAC onlineorAC offline, notAC unknown.Design
1. The grant: the
acpiclaim, by name, in the image's manifestimages/system.tomlandimages/console.tomlalready nameacpiserveras the one holder ofdevices = ["acpi"]. No shipped manifest gives any programsyscap = ["device"], which is what could mint the claim at run time. That name is the grant, so no key is added.The build adds one clause to that row's comment: the
acpiclaim hands the program the firmware's own access, and the kernel makes the AML's writes for it inside the fences below.A test image (
tests/images/acpicase.toml) mints the claim for a probe shipped in that same image.2. The kernel makes the firmware's writes, fenced
toyos_userbound::firmwaredecides as it does today, with three changes.Memory. A write passes wherever a read passes today. An unlisted address, or memory typed
EfiMemoryMappedIO, is written under the read's conditions:That arm's
if !writegoes. These refusals stay, unchanged:UsableMemory: RAM.DeviceMemory: the LAPIC window, every window the kernel drives, and every recorded BAR's pages. That covers the I/O APICs, the HPET and the IOMMU units, VT-d and AMD-Vi alike (iommu_unit::register_windowmaps them as driven windows).TableWrite,FacsWrite,Unmapped,Straddles.RegisterCachedandRangeRegistersDiffer, which now also hold the RAM fence for memory the map does not list.Configuration space. A write passes, made through the ECAM window, with three fences. A write is held to the same shape as a read (
ConfigSpan,ConfigUnreachable).HeldFunctionAddressMapAddressMapConfigWriteis deleted.MCHBAR's kept registers. Two registers inside MCHBAR are the kernel's, on the five host bridges 631122 covers. A write overlapping either is refused
KernelRegister. Reads pass.PACKAGE_RAPL_LIMITINTRDIRCTLHow the kernel finds them:
DeviceMemory's does.No other host bridge has a row:
On those, every write that passes the other fences passes.
Index windows. None is fenced, because no document we hold maps a target behind one on a bench part. On the AMD bench, 00:00.0's 0xB8/0xBC reaches the SMN. Review 1's table of every held AMD document stands: none maps 0xB8/0xBC on Family 17h Model 60h. 55772 and 55901 map sibling parts' SMN, not this part's.
The P2SB sideband is not fenced. That includes its ITSS port, C4h (631119-007 Table 109), which holds the 8259/IOxAPIC routing and polarity. A fence would need the kernel to learn SBREG_BAR, which the T14's firmware hides behind
P2SBC.HIDE(631120-002 §3.1.22). That means a configuration write to unhide a device, open to an SMI taken in between. That is not cheap, and a mistake of ours that lands on port C4h exactly is not likely. This departs from the brief's interrupt-controller fence by name. The orchestrator may overrule it, and the cost of doing so is round 2's P2SB machinery.3. The server: a kept register's write is not made, and the evaluation goes on
system/acpiserver/src/host.rs,Firmware::write:KernelRegister. The write is not made. The server says it the first time per register, as one quotable line by kind, with the address underOWN. It answers the interpreterOk, so the evaluation goes on.DYTCrecords its mode in NVS at 0x949B8F04 afterCTCNreturns (trace line 256).memory_typeisUNLISTEDorEfiMemoryMappedIO, ECAM pages included), and into each function byPCI_Config. That is one quotable line by kind, with the address, width and value underOWN. This is the trust model's record of what the firmware wrote where no fence looks.Ledgeralready and is told each answer's memory type, and the kernel keeps no per-claim state for it.What else changes
toyos_abi::acpi::RefusedlosesConfigWriteand gainsHeldFunction,AddressMapandKernelRegister.MemoryTypestays, for types no access passes. No syscall is added.acpi_mode: the MCHBAR read at init, and the configuration write path, which makes a passed write throughpci::function_window.pcidev: one predicate, whether a function is held: kernel-driven, claimed, or of class 0800h/0806h.build/fetches nothing new. The build round's agent transcribes the DID list from 631121-012 into the policy's source.issues/the-t14s-controller-and-hotkey-ini-are-refused-for-writes-outside-the-map.mdandissues/the-amd-benchs-ec-reg-and-psr-are-refused-for-a-write-to-the-root-complexs-index.md: both exits are met by the rows below.issues/toyos-runs-the-machine-in-acpi-mode-and-interprets-its-aml.md, as the issue it takes up. The two named exceptions go, and the AMD adapter'sAC unknowngoes.issues/the-t14s-thermal-modes-do-not-move-its-package-power-limits.md:DYTC's PL1/PL2 writes to 59A0h are refusedKernelRegister, so Lenovo's thermal modes do not move PL1/PL2.DYTC. Or the owner rules that ToyOS does not follow the firmware's modes, and the row says so.lib/userbound/src/firmware.rs) states the contract: what the kernel fences, and what it does not fence (the residuals in the roast). It carries the closed issues' one durable line: a write the firmware's AML makes is made unless a named fence refuses it.How the earlier reviews bind
acpiserver.RegisterLock)build/fetches nothing.HIDEwindow open to an SMI; enumeration orderKernelRegister, recorded in the new defect above.Roast
Lines. These are estimates, not measurements. Round 2 estimated about +150 production and +200 tests.
sdk/abi/src/acpi.rslib/userbound/src/firmware.rs(arms, one DID-keyed table of 5 DIDs, 2 MCHBAR rows and 1 config range, module header)kernel/src/arch/x86_64/acpi_mode.rs(MCHBAR read, config write)kernel/src/pcidev/mod.rs(held predicate)system/acpiserver/src/host.rs(kept write, first-write ledger, module doc)images/*.tomlcommenttests/toyos.rsRuled−45 and expectations +25)What round 3 deletes against round 2's design:
HIDEclear, read and restore, and its SMI window;PAD_CFG_DW0runs and their 8 run boundaries;VendorRegisterandRegisterLock;Against
main, it deletes:ConfigWrite;tests/toyos.rs'sRuledstruct and itssays/held.What it adds:
Could less do?
INTRDIRCTLis one row on the same table.pcidevalready records.The
KernelRegisterexception is a second outcome for a refusal. It is the one place a refusal does not end the evaluation. The AML then believes PL1 moved, reads 59A1h back at the hardware's value, and records the mode in NVS. That gap between the mode and the limits is exactly the recorded defect. Denying instead would makeHKEY._INIrefused by name, and the firmware's own mode record would be lost with it.What the fences do not see, the trust model's residuals, stated in the policy's header:
INTRDIRCTLand the host bridge's address map;CONFIG_TDP_CONTROL5F50h, which selects a TDP level and is not in the ruling (see Unsure);What the T14's AML now does that it did not:
GPPC_A_13high;WGINandDYTC.What the AMD bench's does: it sends
ALIBmessages to the SMU through the mailbox, twelve under the 0xFF model below.Tests and metal rows that show it
Host,
lib/userbound/tests/firmware.rs(pure policy, the cheapest tier). Each test has a negative control: the whole change reverted onto8fec83d, red. Each fence arm gets a mutation: the arm deleted, its test red. The oracles are 631122 §3.1.14, §3.1.13–§3.1.34, §3.3.31 and §3.4.5; 631121-012 Table 15-3; PCIe Base §7.5.1; and PCI Code and ID Assignment base class 08h, each typed into the test from the document.an_unlisted_register_is_written_where_it_is_read.EfiMemoryMappedIOaddress.RegisterCachedbelow 1 MiB and where cached;RangeRegistersDiffer;DeviceMemoryon the LAPIC, a driven window and a BAR page.a_register_the_kernel_keeps_is_refused_kernelregister.kept_registers_exist_only_on_the_host_bridges_631122_covers.a_configuration_write_is_refused_in_every_header.AddressMap: 00h–3Fh, each width, by address and through ECAM.a_held_function_is_refused_whole.HeldFunction: claimed, kernel-driven, class 0800h and class 0806h, at 40h, B8h and 100h.the_host_bridges_address_map_is_refused_where_631122_maps_it.AddressMapon 9A14h: 48h, 54h, 60h, 80h and BCh.Host,
system/acpiserverunits.a_write_the_kernel_keeps_is_not_made_and_the_evaluation_goes_on. AKernelthat answersKernelRegister, and a method that writes a kept register and then stores. The method returns. The store is made. The line is said once.the_first_write_into_each_page_and_function_is_said_once.every_other_refusal_still_denies_the_evaluation. Its mutation turns every refusal into the kept one, and goes red.Guest,
acpi_mediated_access: its behaviour changes.AddressMap.diskserverholds isHeldFunctionat 44h and 100h.Why QEMU:
pcidev's held set reaching the policy, and the ABI round trip.ACPI_MEDIATED_SAIDintests/toyos.rs).Metal, T14 (
cargo test --test toyos-build -- --metal --metal-readback <dir> <row>in the build round):acpi_tables_loaded:T14.ruledgoes.\_SB_.PC00.LPCB.EC__._INIand…EC__.HKEY._INIrun, and "evaluations refused, by kind: none".KernelRegisterline once, with 0xFEDC59A0 underOWN.battery_read: nothing refused. The kept line is not a refusal of an evaluation.acpi_server_events,acpi_server_deathandcountersstay green.countersreadsWGSV's firmware calls as calls.Metal, AMD bench:
acpi_tables_loaded:AMD.ruledgoes.regreads_REG(3, 1) in 1 scope(s).AC onlineorAC offline.Independent oracles: the vendors' documents above, and the two benches. Negative control: the whole change reverted onto
8fec83d. The host tests go red on every pass arm, and the T14 and AMD rows go red on the methods refused, asmainreads them today.Measurements behind this
Evidence
pr-906:36be6e2:_REG(3, 1)and_PSR, traced on the host under toyos-aml at8fec83d, over the bench's own tables, with the host a model (source; 0x00 fill, EXIT=0; 0xFF fill, EXIT=0).NDPC'sODV0is set, it also writes ports 0x72/0x73 and one unlisted byte at 0xFE70039C. No recorded BAR covers that byte (round3/amd-acpi_tables_loaded.loglines 197–206).f7f1f8c:37745c3e…;afb02d7: PPR 55922 searches, 631119 Tables 6 and 109, and 631120 §3.1.5 and §3.1.22.The bench enumerations are
pr-875round3/t14-testcases.loglines 162–182 andround3/amd-acpi_tables_loaded.loglines 179–206. No other implementation was read or cited.Unsure
SGOVreads 0xFD6E0A70 just before writing it (trace line 97). ToyOS refused the write, not the read (t14-testcases.loglines 497–498). So that address is mapped, its CPUs agree, and ToyOS's own check finds it uncached.CTCNreads 0xFEDC5F50 before its first write there (trace lines 227–230). That write was the refused one,MemoryType, which is a write's refusal. 59A0h lies in the same 4 KiB page, 0xFEDC5000.IA32_MTRR_DEF_TYPEis 0xc00, so the default is UC (log line 241). If 0xFE70039C is ever reached and a variable pair types it cached, the write is refusedRegisterCached, and the build reports it.CONFIG_TDP_CONTROL. The ruling names 59A0h alone, so 5F50h passes. Its TDP level also moves the package's TDP. If the performance track wants it, it is one row on the same table.issues/the-acpi-claims-holder-reaches-every-port-and-firmware-range-the-kernel-did-not-declare.mdsays no configuration write is made. That is no longer true once this builds. That issue is neither the one this PR takes up nor one a rule names, so the build leaves it, for the trust-model pull request or the orchestrator.Gates
None run: design round, nothing built. The host trace's build and runs are evidence, not gates (EXIT=0 each, in the README).
🤖 Generated with Claude Code
https://claude.ai/code/session_015xhaydXCVRNscoccHYFUWy