diff --git a/issues/build/the-tooling-is-a-review-prompt-and-three-workflows.md b/issues/build/the-tooling-is-a-review-prompt-and-three-workflows.md index 3240514790e..e79d36b56f6 100644 --- a/issues/build/the-tooling-is-a-review-prompt-and-three-workflows.md +++ b/issues/build/the-tooling-is-a-review-prompt-and-three-workflows.md @@ -37,3 +37,9 @@ and the gates that held them go. - The nine workflows become three — `pr`, `nightly`, `publish`; then `a5b25a75^:src/mergehealth.rs` goes, and the ABI-lands-alone rule moves into the review prompt. + +**Ruled** (owner, 2026-10-04), on #629, which builds the content-addressed +toolchain item, **"Design pass, then re-cut"**: "A short design pass against +today's main (it would also ease the one-shared-fork-branch ordering +problem), roasted, then rebuilt as a fresh PR; #629 is closed in favour of +it." diff --git a/issues/diagnostics/nothing-in-the-machine-can-read-the-trace-ring.md b/issues/diagnostics/nothing-in-the-machine-can-read-the-trace-ring.md index 0a346c25365..e88fc27e2ce 100644 --- a/issues/diagnostics/nothing-in-the-machine-can-read-the-trace-ring.md +++ b/issues/diagnostics/nothing-in-the-machine-can-read-the-trace-ring.md @@ -43,6 +43,15 @@ anything more is built on it. `issues/kernel/the-supervisors-claim-of-a-pci-function-the-t14-lacks-holds-interrupts-off-for-3-8-ms.md` need. +**Ruled** (owner, 2026-10-04), on when these steps start, **"Both in +parallel"**: "Start the trace diary's first steps now, beside latency step 1 +(interrupts on in system calls). Step 1 is already measured by existing T14 +rows. The tail delays are only worked on once the diary shows their cause." +The step he names is step 2 of +`issues/kernel/toyos-beats-linuxs-latency-on-the-t14.md`, +`issues/kernel/syscall-preemption-is-incidental.md`; that mapping is the +orchestrator's, not his. + Behind that judgement, and not before it: interrupt enter and exit records with a noise reader, the profiling sample, and the censuses moved onto the ring. diff --git a/issues/kernel/a-driver-that-reflashes-its-device-escapes-its-isolation.md b/issues/kernel/a-driver-that-reflashes-its-device-escapes-its-isolation.md new file mode 100644 index 00000000000..2da9225428d --- /dev/null +++ b/issues/kernel/a-driver-that-reflashes-its-device-escapes-its-isolation.md @@ -0,0 +1,31 @@ +--- +status: open +kind: defect +opened: 2026-10-04 +--- + +# A driver that reflashes its device escapes its isolation + +A userland driver holds its device's registers, and through them many +devices take new firmware (NVMe's Firmware Image Download and Commit, for +one). Nothing in ToyOS refuses that or checks what a device runs. The IOMMU +confines a device by the requester ID its requests carry, so it confines a +reflashed one only as far as that ID is the device's own: ACS Source +Validation at a port refuses another bus's ID from below it, but nothing +stands between a root-complex-integrated endpoint, or one function of a +multi-function device, and an ID beside it. And the firmware outlives the +driver: the next holder, and the next boot's firmware before any IOMMU is +on, drive what the last holder wrote. That reach is the IOMMU design's +reading, not a measurement. + +**Ruled** (owner, 2026-10-04, "Refuse external, record reflash"): +"External-port devices can't be claimed by userland drivers for now; +reflashing is a recorded weakness with an exit (firmware verification) to +design later." + +Owner: the orchestrator, under `issues/kernel/the-iommu-refuses-nothing-yet.md`. + +**Exit**: a design for verifying a device's firmware is put to the owner +and ruled, and built; a device whose firmware fails that verification is +refused its claim by name, and a test or T14 row reads the refusal and its +negative control. diff --git a/issues/kernel/a-unit-in-scalable-or-abort-mode-loses-translation-for-its-root-table-switch.md b/issues/kernel/a-unit-in-scalable-or-abort-mode-loses-translation-for-its-root-table-switch.md new file mode 100644 index 00000000000..c1cf20d37d3 --- /dev/null +++ b/issues/kernel/a-unit-in-scalable-or-abort-mode-loses-translation-for-its-root-table-switch.md @@ -0,0 +1,45 @@ +--- +status: open +kind: defect +opened: 2026-10-04 +--- + +# A unit in scalable or abort mode loses translation for its root-table switch + +A unit firmware leaves translating with a root table in scalable or abort-DMA +mode (`RTADDR_REG.TTM` not `00`) and `CAP.ESRTPS` clear may not have its root +table pointer set while translation is on (VT-d Rev. 4.1 §6.6). Handing such a +unit over to this kernel's root table therefore turns translation off for that +one switch, and for that moment every function behind the unit reaches all of +memory. `issues/kernel/a-unit-left-translating-passes-dma-untranslated-while-programmed.md` +removes the gap where the switch may stay translating; on these units it may +not. + +Evidence: the specification alone. No machine here has such a unit: every unit of the +T14 reports `CAP` bit 63 (`ESRTPS`), `ECAP` bit 43 (`SMTS`) and bit 52 +(`ADMS`) clear. + +**Ruled** (owner, 2026-10-04, "Accept and file"): "Allow the one-moment gap on +those machines, log it, and file it as a known weakness with a fix (older +protection registers) as its exit." + +Owner: the orchestrator, under `issues/kernel/the-iommu-refuses-nothing-yet.md`. + +**Exit**: on such a unit that reports `CAP.PLMR` (bit 5) and `CAP.PHMR` +(bit 6), `PMEN`'s protected memory regions (§11.4.8.1) cover all of memory +before translation goes off for the switch and are released only once it is +back on; a host test reads that order, and is red with the `PMEN` step +removed. It is a host test because no machine reaches the path: QEMU's unit +always reports `ESRTPS` and implements `PMEN_REG` as read-only zero, and the +T14's units report `ESRTPS` clear but support neither mode. + +A unit that reports either bit clear has no fix under this exit: with either +clear, that region's base and limit are read-only (§11.4.8.1), so `PMEN` +cannot cover all of memory; the same section plans the protected memory +registers for deprecation, pointing new software at abort-DMA mode. Such a +unit keeps the gap, logged, and this file stays open for it once the `PMEN` +exit is met. + +**Exit for a unit with `PLMR` or `PHMR` clear**: on such a unit no function +behind it reaches memory while translation is off for the switch; a host test +reads that, and is red with the fix removed. diff --git a/issues/kernel/the-iommu-refuses-nothing-yet.md b/issues/kernel/the-iommu-refuses-nothing-yet.md index 5f7eed6a77c..9b55f359003 100644 --- a/issues/kernel/the-iommu-refuses-nothing-yet.md +++ b/issues/kernel/the-iommu-refuses-nothing-yet.md @@ -28,3 +28,62 @@ What the harness cannot measure: - **Cost.** The 2× bar is answerable only on hardware, in a same-session A/B; so are cache-snooping walks, real access-control enforcement, and mid-DMA function reset on a real device. + +**Ruled** (owner, 2026-10-04), on the threat model, **"Refuse external, +record reflash"**: "External-port devices can't be claimed by userland +drivers for now; reflashing is a recorded weakness with an exit (firmware +verification) to design later." The weakness is +`issues/kernel/a-driver-that-reflashes-its-device-escapes-its-isolation.md`. +On the T14 the external ports are the Thunderbolt root ports `00:07.0` and +`00:07.2`, under units 1 and 2 (the orchestrator's reading of that machine's +`iommu:` lines). + +**Ruled** (owner, 2026-10-04), on the default-deny root and the hand-over of +a unit firmware left translating: + +- **"Display and USB only"**: "Allowed only for display and USB controllers + whose reserved region belongs to them alone; that memory is mapped into the + driver's own isolated space. Everything else with reserved memory is + refused." Reserved memory is a DMAR RMRR; on the T14 the one RMRR, + `0x9c000000..0xa07fffff`, names the iGPU `00:02.0` alone. +- **"Accept and file"**: "Allow the one-moment gap on those machines, log it, + and file it as a known weakness with a fix (older protection registers) as + its exit." The gap, as put to him: a unit firmware left translating in + scalable or abort-DMA mode, with `CAP.ESRTPS` clear, may not have its root + table switched under translation (VT-d Rev. 4.1 §6.6), so translation goes + off for that one switch. The older protection registers are `PMEN`'s + protected memory regions (§11.4.8.1). The weakness is + `issues/kernel/a-unit-in-scalable-or-abort-mode-loses-translation-for-its-root-table-switch.md`. +- **"Apply it at hand-over"**, on reserved memory: "From the hand-over on, + only display and USB controllers keep access to their reserved region; any + other device's access is refused. A device that firmware was still using + then faults, which is logged and the device is stopped; the machine keeps + running." +- **"Allow it"**, on the T14 row in which a test program claims the iGPU and + its reserved region is mapped into its domain: "One test boot with a blank + panel, only in that row; normal boots are unaffected." +- On the row that aims the T14's undriven NVMe `04:00.0` at memory nobody + gave it, asked whether to allow a single read-only Identify on its own + boot, he answered: "You can do with the t14 what you want." The grant goes + beyond the question asked. + +Owner: the orchestrator. + +**Exit**: a test or a T14 row reads each ruled refusal, each with its +negative control: + +- the isolation-scope rule: a non-singleton scope is refused by name for a + function behind a PCIe switch, and admitted for a root-complex-integrated + function; +- a userland claim of a function below an external port (on the T14, + `00:07.0` or `00:07.2`) is refused by name; +- a claim of a function an RMRR names is refused unless it is a display or USB + controller that RMRR names alone, whose region is then mapped into its + driver's domain (the T14's iGPU row); +- from the hand-over on, a device that is neither a display nor a USB + controller faults on its own RMRR region, is logged and stopped, and the + machine keeps running; a display or USB controller whose RMRR also names + another device faults on that region the same way; and a display or USB + controller its RMRR names alone keeps that region. Each case has its own + negative control; +- a unit with the hand-over gap logs it. diff --git a/issues/kernel/the-kernel-heap-has-none-of-slubs-hardening.md b/issues/kernel/the-kernel-heap-has-none-of-slubs-hardening.md index 8a03007abb6..8cbc2c93b61 100644 --- a/issues/kernel/the-kernel-heap-has-none-of-slubs-hardening.md +++ b/issues/kernel/the-kernel-heap-has-none-of-slubs-hardening.md @@ -19,10 +19,18 @@ free list (`mm/slub.c:2228,2290`), and `CONFIG_RANDOM_KMALLOC_CACHES` spreads each size over 16 caches chosen by call site and a per-boot seed (`include/linux/slab.h:340-341,398-401`). -**Exit**: a free-list link is stored encoded with a per-boot secret and -checked on every unlink, a size class's allocation order is drawn per boot, -and one size is spread over 16 caches by call site and a per-boot seed. Host -tests on the allocator: a corrupted link panics at the next unlink, and -storing it plain passes it and reds; two seeds give two allocation orders, and -a fixed order reds; 1000 call sites of one size use all 16 caches, and one -cache reds. +**Ruled** (owner, 2026-10-04, "Change the goal"): "Close the issue with the +allocator's first stage under that stronger, ToyOS-shaped goal instead of +copying Linux's SLUB features one by one." The goal, as put to him: no +allocator bookkeeping stored inside objects, every free checked, and data +kept apart from pointers. The first stage is the kernel's front of +`issues/kernel/toyos-has-its-own-allocator.md`, which owns this issue. + +**Exit**: the kernel heap is that front, and its host tests hold the goal: +no free-list link or size is stored in memory an object occupies, so a write +past one object into a freed neighbour is followed by an allocation that +returns sound memory; a free of a pointer the heap did not hand out, and a +second free of one, each panic; and an allocation holding pointers never +shares a page with one holding only data. Each of those tests reds against +`dlmalloc`, or against the front with that property removed. The tests are +the orchestrator's reading of the goal, not his. diff --git a/issues/kernel/toyos-beats-linuxs-latency-on-the-t14.md b/issues/kernel/toyos-beats-linuxs-latency-on-the-t14.md index 09b21cc81db..da53316a20d 100644 --- a/issues/kernel/toyos-beats-linuxs-latency-on-the-t14.md +++ b/issues/kernel/toyos-beats-linuxs-latency-on-the-t14.md @@ -34,6 +34,16 @@ It samples: a window under 1 ms is seen only when a tick falls in it. **Ruled** (owner, 2026-10-03): **"131 µs"**. ToyOS must beat Linux's worst delay on the other seven CPUs, 131 µs, not cpu4's one-off 2.9 ms event. +**Ruled** (owner, 2026-10-04), on the order of the trace work, **"Both in +parallel"**: "Start the trace diary's first steps now, beside latency step 1 +(interrupts on in system calls). Step 1 is already measured by existing T14 +rows. The tail delays are only worked on once the diary shows their cause." +The step his text names is step 2 here, +`issues/kernel/syscall-preemption-is-incidental.md`, whose exit the +`mask_windows` row reads; the diary is +`issues/diagnostics/nothing-in-the-machine-can-read-the-trace-ring.md`. That +mapping is the orchestrator's, not his. + **Exit**: each step's exit is met, in the file the step names, and on the T14, with every CPU spawning a program that exits at once, as under Linux's 131 µs reading, the longest lateness of a 1 kHz timer's interrupt on each CPU reads under 131 µs, diff --git a/issues/kernel/toyos-has-its-own-allocator.md b/issues/kernel/toyos-has-its-own-allocator.md index ca62befbde8..1625a8ac13b 100644 --- a/issues/kernel/toyos-has-its-own-allocator.md +++ b/issues/kernel/toyos-has-its-own-allocator.md @@ -22,11 +22,24 @@ scans the page bitmap and zeroes the whole 2 MiB page before it returns, so every CPU that allocates from the heap meanwhile spins on its lock. How long that takes on the T14 is unmeasured. +**Ruled** (owner, 2026-10-04, "Yes, that bar"): "Within 10% of mimalloc +for time and peak memory on a pinned benchmark set; faster than dlmalloc +everywhere. The benchmarks get a portable Rust runner so they run on ToyOS +itself." + +The kernel's front closes +`issues/kernel/the-kernel-heap-has-none-of-slubs-hardening.md`, under the +goal the owner chose there (2026-10-04): no allocator bookkeeping inside +objects, every free checked, data apart from pointers. + Owner: the orchestrator. **Exit**: no heap growth allocates or zeroes a 2 MiB page inside the kernel heap's lock; the kernel allocates through ToyOS's allocator, and `dlmalloc`, `libc`, `windows-sys` and `windows-link` are gone from `kernel/Cargo.toml` and `kernel/Cargo.lock`, with `build::tests::the_kernel_resolves_no_libc_for_either_target` -(`src/build.rs`) deleted in the same pull request; and ToyOS's std allocates -through the std front, measured against `dlmalloc` before it is swapped in. +(`src/build.rs`) deleted in the same pull request; ToyOS's std allocates +through the std front, measured against `dlmalloc` before it is swapped in; +and the ruled bar holds, read by the benchmarks' portable Rust runner, which +runs on ToyOS: the allocator within 10% of mimalloc for time and peak memory +on the pinned benchmark set, and faster than `dlmalloc` everywhere. diff --git a/issues/kernel/toyos-runs-the-machine-in-acpi-mode-and-interprets-its-aml.md b/issues/kernel/toyos-runs-the-machine-in-acpi-mode-and-interprets-its-aml.md index 0bd119348e7..a7acea8bbff 100644 --- a/issues/kernel/toyos-runs-the-machine-in-acpi-mode-and-interprets-its-aml.md +++ b/issues/kernel/toyos-runs-the-machine-in-acpi-mode-and-interprets-its-aml.md @@ -50,9 +50,23 @@ writes its own, and the battery comes first (his direction of `0ee814f5a`). - **"Extracts only"**: the repository holds small decoded extracts of the T14's ACPI tables; the whole tables stay out of the tree, read only by a check run outside it. +- **"Local only; decode the 186 bytes"** (2026-10-04): "Full tables stay out + of the repo (a copy you hold); the 186-byte fixture on main is replaced by + decoded values, as 'Extracts only' says." The T14's root-bridge list is + `t14_root_bridge` in `toyos-acpi/tests/common/mod.rs`. - **"full clean room write with the spec"**: the AML interpreter is written from the ACPI specification. +**Ruled** (owner, 2026-10-04), on the interpreter: + +- **"Like Windows, not Linux"**, on `_OSI`: "Yes to every published Windows + version string, no to 'Linux' and 'FreeBSD', as Linux itself answers. The + T14 then runs the path it was tested on: Modern Standby, CPU performance + tables, 101-step backlight, thermal profiles, all devices present." +- **"Yes, one path"**, on power-off: "Power-off always goes through the ACPI + server; the kernel's power-off table reader is deleted. If the server is + broken, power-off fails loudly in every test." + The orchestrator's reading of the clean-room ruling, not his: uACPI and ACPICA are run only as black-box oracles, and whoever writes the interpreter never reads their source. @@ -67,3 +81,9 @@ power-off path (`SYS_SHUTDOWN`), and the boot's log records the press and that stop, and each EC query number once with its count: a T14 row reads them there. A second T14 row kills the server and reads `SCI_EN` clear in `PM1_CNT` afterwards, the kernel having written `ACPI_DISABLE` to `SMI_CMD`. + +**Stage: power-off through the server** (the orchestrator's placement of "Yes, +one path"). The ACPI server evaluates `\_S5` and powers the machine off. +Blocked on the interpreter's evaluation of `\_S5`. **Exit**: the kernel's `\_S5_` reader, `toyos-acpi/src/dsdt.rs`, and its caller +in `kernel/src/arch/x86_64/power.rs` are deleted, and a test that powers off +through a broken server is red. diff --git a/src/licence.rs b/src/licence.rs index cc0b165562c..bdc30429c02 100644 --- a/src/licence.rs +++ b/src/licence.rs @@ -276,12 +276,6 @@ pub const COMMITTED_FILES: &[(&str, &str, &str, Terms)] = &[ "ours: OVMF's answer on a q35 guest, read off that boot's own loader log", Terms::Spdx("MIT OR Apache-2.0"), ), - ( - "toyos-acpi/fixtures/thinkpad-t14/root-bridge-0.bin", - "a734078ed9ca3971ce804fd9ecc97b7794f816058f9ae17e47e0d2bcb63af0f3", - "ours: the T14's answer, read off that boot's own loader log on the stick", - Terms::Spdx("MIT OR Apache-2.0"), - ), // A bcachefs volume upstream's own tools wrote, gzipped. The bytes inside // it are this repository's test material; `NOTICE` carries the raw digest, // the commands, and the fsck that called it clean. diff --git a/toyos-acpi/fixtures/thinkpad-t14/SOURCE b/toyos-acpi/fixtures/thinkpad-t14/SOURCE deleted file mode 100644 index 760885c5900..00000000000 --- a/toyos-acpi/fixtures/thinkpad-t14/SOURCE +++ /dev/null @@ -1,11 +0,0 @@ -The ACPI resource descriptors `EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL::Configuration` -answered with on the one root bridge of the ThinkPad T14 this repository is -tested on, off that machine's own firmware. - - root-bridge-0.bin 186 bytes, off the `Root bridge: 0 (segment 0) 186 bytes:` - line in the `loader.log` the stick came back with from - metal run 33 (`tests/metalcase`). - -The bootloader printed the bytes and nothing decoded them on the way. What says -the length was right is the file itself: four descriptors whose own declared -lengths tile it exactly, then the End Tag. diff --git a/toyos-acpi/fixtures/thinkpad-t14/root-bridge-0.bin b/toyos-acpi/fixtures/thinkpad-t14/root-bridge-0.bin deleted file mode 100644 index f675c5b5b72..00000000000 Binary files a/toyos-acpi/fixtures/thinkpad-t14/root-bridge-0.bin and /dev/null differ diff --git a/toyos-acpi/src/resource.rs b/toyos-acpi/src/resource.rs index 80304260c28..26273cce3bc 100644 --- a/toyos-acpi/src/resource.rs +++ b/toyos-acpi/src/resource.rs @@ -10,7 +10,6 @@ //! //! Input is firmware-supplied and untrusted: no path panics, the walk //! terminates on every input, and every refusal is a [`ResourceError`]. -//! `tests/corpus.rs` holds that claim over both firmwares' committed bytes. use crate::Phys; use toyos_abi::boot::RootBridgeWindow; diff --git a/toyos-acpi/tests/common/mod.rs b/toyos-acpi/tests/common/mod.rs index 428de7c47ac..7df0a8162df 100644 --- a/toyos-acpi/tests/common/mod.rs +++ b/toyos-acpi/tests/common/mod.rs @@ -116,3 +116,41 @@ pub fn madt(entries: &[u8]) -> Vec { body.extend_from_slice(entries); sdt(b"APIC", 5, &body) } + +/// ACPI 6.5 Table 6.44's resource types. +pub const MEMORY: u8 = 0; +pub const IO: u8 = 1; +pub const BUS: u8 = 2; + +/// One QWORD Address Space Descriptor (ACPI 6.5 §6.4.3.5.1), field by field, +/// its General and Type Specific Flags clear. +pub fn qword_descriptor(kind: u8, granularity: u64, min: u64, max: u64, translation: u64, length: u64) -> Vec { + let mut d = vec![0x8A, 0x2B, 0x00, kind, 0x00, 0x00]; + for field in [granularity, min, max, translation, length] { + d.extend_from_slice(&field.to_le_bytes()); + } + d +} + +/// `descriptors`, then the End Tag over its checksum byte (ACPI 6.5 §6.4.2.9). +pub fn resource_list(descriptors: &[Vec]) -> Vec { + let mut bytes = descriptors.concat(); + bytes.extend_from_slice(&[0x79, 0x00]); + bytes +} + +/// What OVMF's firmware answered for its root bridge 0 through +/// `EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL::Configuration`, as captured. +pub const OVMF_ROOT_BRIDGE: &[u8] = include_bytes!("../../fixtures/ovmf-pure-efi/root-bridge-0.bin"); + +/// What the ThinkPad T14's firmware answers for its root bridge 0 through +/// `EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL::Configuration`, decoded: its I/O range, +/// two memory windows and its bus range. +pub fn t14_root_bridge() -> Vec { + resource_list(&[ + qword_descriptor(IO, 0, 0x3000, 0x3fff, 0, 0x1000), + qword_descriptor(MEMORY, 0x20, 0xa200_0000, 0xbcff_ffff, 0, 0x1b00_0000), + qword_descriptor(MEMORY, 0x40, 0x40_0000_0000, 0x60_3dbf_ffff, 0, 0x20_3dc0_0000), + qword_descriptor(BUS, 0, 0, 0x79, 0, 0x7a), + ]) +} diff --git a/toyos-acpi/tests/corpus.rs b/toyos-acpi/tests/corpus.rs index 1b4ad4ec520..6378bee937f 100644 --- a/toyos-acpi/tests/corpus.rs +++ b/toyos-acpi/tests/corpus.rs @@ -8,7 +8,7 @@ mod common; -use common::{declare_len, entry, madt, rsdp, sdt, xsdt, Machine}; +use common::{declare_len, entry, madt, rsdp, sdt, t14_root_bridge, xsdt, Machine, OVMF_ROOT_BRIDGE}; use toyos_abi::boot::RootBridgeWindow; use toyos_acpi::{ dsdt_address, ecam_base, find_table, hpet_base, iapc_boot_arch, madt_entries, memory_windows, @@ -566,10 +566,6 @@ fn a_fadt_that_ends_before_arm_boot_arch_is_short() { /// Where the two firmwares' descriptor lists sit for the sweep below. const ROOT_BRIDGE_AT: u64 = 0x4_0000; -const ROOT_BRIDGES: &[(&str, &[u8])] = &[ - ("ovmf", include_bytes!("../fixtures/ovmf-pure-efi/root-bridge-0.bin")), - ("thinkpad-t14", include_bytes!("../fixtures/thinkpad-t14/root-bridge-0.bin")), -]; /// **No panic and no unbounded walk, over every byte of both firmwares' real /// descriptor lists.** Each byte takes each of its 255 other values in turn and @@ -579,7 +575,7 @@ const ROOT_BRIDGES: &[(&str, &[u8])] = &[ fn no_single_byte_mutation_of_a_firmwares_descriptor_list_panics_or_runs_away() { let mut mutations = 0u64; let mut refused = 0u64; - for (which, original) in ROOT_BRIDGES { + for (which, original) in [("ovmf", OVMF_ROOT_BRIDGE.to_vec()), ("thinkpad-t14", t14_root_bridge())] { for offset in 0..original.len() { for value in 0..=255u8 { if original[offset] == value { diff --git a/toyos-acpi/tests/fixtures.rs b/toyos-acpi/tests/fixtures.rs index 608ccc12113..8b829878a09 100644 --- a/toyos-acpi/tests/fixtures.rs +++ b/toyos-acpi/tests/fixtures.rs @@ -3,7 +3,7 @@ mod common; -use common::Machine; +use common::{t14_root_bridge, Machine, OVMF_ROOT_BRIDGE}; use toyos_abi::boot::RootBridgeWindow; use toyos_acpi::{ century_of, dsdt_address, ecam_base, find_table, hpet_base, iapc_boot_arch, madt_entries, @@ -163,10 +163,8 @@ fn the_xsdt_walk_reaches_every_entry() { } const ROOT_BRIDGE: u64 = 0x7f00_0000; -const OVMF_BRIDGE: &[u8] = include_bytes!("../fixtures/ovmf-pure-efi/root-bridge-0.bin"); -const T14_BRIDGE: &[u8] = include_bytes!("../fixtures/thinkpad-t14/root-bridge-0.bin"); -fn bridge_windows(bytes: &'static [u8]) -> Vec { +fn bridge_windows(bytes: &[u8]) -> Vec { let regions: &[(u64, &[u8])] = &[(ROOT_BRIDGE, bytes)]; let mut out = [RootBridgeWindow::default(); 8]; let count = memory_windows(Machine { regions }, ROOT_BRIDGE, &mut out).expect("bytes a firmware answered with"); @@ -178,7 +176,7 @@ fn bridge_windows(bytes: &'static [u8]) -> Vec { #[test] fn the_windows_a_boot_printed_are_what_that_firmwares_own_bytes_say() { assert_eq!( - bridge_windows(OVMF_BRIDGE), + bridge_windows(OVMF_ROOT_BRIDGE), [ RootBridgeWindow { base: 0xc000_0000, length: 0x0010_0000 }, RootBridgeWindow { base: 0x8_0000_0000, length: 0x0010_0000 }, @@ -193,7 +191,7 @@ fn the_windows_a_boot_printed_are_what_that_firmwares_own_bytes_say() { #[test] fn a_second_firmwares_bytes_decode_to_that_machines_own_windows() { assert_eq!( - bridge_windows(T14_BRIDGE), + bridge_windows(&t14_root_bridge()), [ RootBridgeWindow { base: 0xa200_0000, length: 0x1b00_0000 }, RootBridgeWindow { base: 0x40_0000_0000, length: 0x20_3dc0_0000 }, diff --git a/toyos-acpi/tests/resource.rs b/toyos-acpi/tests/resource.rs index 298a97ec326..2a32804ce75 100644 --- a/toyos-acpi/tests/resource.rs +++ b/toyos-acpi/tests/resource.rs @@ -3,42 +3,17 @@ mod common; -use common::Machine; +use common::{qword_descriptor, resource_list as list, Machine, BUS, IO, MEMORY}; use toyos_abi::boot::RootBridgeWindow; use toyos_acpi::{memory_windows, ResourceError, MAX_LIST_BYTES}; /// Where a firmware pool allocation sits in the crafted machines below. const AT: u64 = 0x7f00_1234; -/// ACPI 6.5 Table 6.44's resource types. -const MEMORY: u8 = 0; -const IO: u8 = 1; -const BUS: u8 = 2; - -/// One QWORD Address Space Descriptor (ACPI 6.5 §6.4.3.5.1), well formed. +/// A well-formed descriptor: no granularity, its maximum its minimum plus its +/// length. fn qword(kind: u8, min: u64, length: u64, translation: u64) -> Vec { - let max = min + length - 1; - let mut d = vec![0x8A, 0x2B, 0x00, kind, 0x00, 0x00]; - d.extend_from_slice(&0u64.to_le_bytes()); - d.extend_from_slice(&min.to_le_bytes()); - d.extend_from_slice(&max.to_le_bytes()); - d.extend_from_slice(&translation.to_le_bytes()); - d.extend_from_slice(&length.to_le_bytes()); - d -} - -/// ACPI 6.5 §6.4.2.9, over its checksum byte. -fn end_tag() -> Vec { - vec![0x79, 0x00] -} - -fn list(descriptors: &[Vec]) -> Vec { - let mut bytes = Vec::new(); - for d in descriptors { - bytes.extend_from_slice(d); - } - bytes.extend_from_slice(&end_tag()); - bytes + qword_descriptor(kind, 0, min, min + length - 1, translation, length) } /// One walk of `bytes`, in a machine holding `bytes` at [`AT`] and nothing