Repository navigation
The acpi claim's mediated access and the Global Lock, and acpiserver loading the machine's tables through them - #749
Conversation
…ation space read and written by the kernel, and the Global Lock The holder of the `acpi` claim runs the firmware's AML, which names memory, ports and PCI configuration space the claim's row does not hold. One syscall, SYS_ACPI, has the kernel make each access or refuse it by name, and take and give back the FACS's Global Lock. The policy is pure, in toyos-userbound::firmware, and answers a witness or a refusal: memory by the UEFI type firmware's map gives it, a port by what its declaration says (pio::declare and FIXED now take the answer), configuration space read whole and written only past the header, outside the capabilities the kernel programs, on a function nothing drives. The kernel keeps firmware's map by withholding the loader's copy from the allocator; pcidev::publish read that copy after mm::init could have handed its page out. Every window map_mmio makes is recorded, and refused to the holder. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RvnWQFcMuGqTHYhvSnTe8A
|
Mutation patches for this pull request, each applied to head 27e5cfb's tree as a checked patch, run and restored by one script; the tree was clean after ( m01-ram-passesdiff --git a/toyos-userbound/src/firmware.rs b/toyos-userbound/src/firmware.rs
index fab170718..5ba743f94 100644
--- a/toyos-userbound/src/firmware.rs
+++ b/toyos-userbound/src/firmware.rs
@@ -158,7 +158,7 @@ impl Memory<'_> {
return No(Refused::Straddles);
}
match ty {
- Some(ty) if toyos_bootmap::is_usable_type(ty) => return No(Refused::UsableMemory),
+ Some(ty) if toyos_bootmap::is_usable_type(ty) => {}
Some(EFI_ACPI_RECLAIM) if write => return No(Refused::TableWrite),
Some(EFI_RESERVED | EFI_ACPI_NVS | EFI_ACPI_RECLAIM) => {}
Some(_) | None => return No(Refused::MemoryType),m02-table-write-passesdiff --git a/toyos-userbound/src/firmware.rs b/toyos-userbound/src/firmware.rs
index fab170718..8bbb56ab3 100644
--- a/toyos-userbound/src/firmware.rs
+++ b/toyos-userbound/src/firmware.rs
@@ -159,7 +159,6 @@ impl Memory<'_> {
}
match ty {
Some(ty) if toyos_bootmap::is_usable_type(ty) => return No(Refused::UsableMemory),
- Some(EFI_ACPI_RECLAIM) if write => return No(Refused::TableWrite),
Some(EFI_RESERVED | EFI_ACPI_NVS | EFI_ACPI_RECLAIM) => {}
Some(_) | None => return No(Refused::MemoryType),
}m03-no-straddle-checkdiff --git a/toyos-userbound/src/firmware.rs b/toyos-userbound/src/firmware.rs
index fab170718..3e90e891f 100644
--- a/toyos-userbound/src/firmware.rs
+++ b/toyos-userbound/src/firmware.rs
@@ -154,9 +154,6 @@ impl Memory<'_> {
return No(Refused::KernelDevice);
}
let ty = self.type_of(at);
- if self.type_of(last) != ty {
- return No(Refused::Straddles);
- }
match ty {
Some(ty) if toyos_bootmap::is_usable_type(ty) => return No(Refused::UsableMemory),
Some(EFI_ACPI_RECLAIM) if write => return No(Refused::TableWrite),m04-kernel-windows-passdiff --git a/toyos-userbound/src/firmware.rs b/toyos-userbound/src/firmware.rs
index fab170718..6495d1bf0 100644
--- a/toyos-userbound/src/firmware.rs
+++ b/toyos-userbound/src/firmware.rs
@@ -150,9 +150,6 @@ impl Memory<'_> {
_ => return No(Refused::Straddles),
}
}
- if overlaps(at, last, LOCAL_APIC) || self.driven.iter().any(|&window| overlaps(at, last, window)) {
- return No(Refused::KernelDevice);
- }
let ty = self.type_of(at);
if self.type_of(last) != ty {
return No(Refused::Straddles);m05-local-apic-passesdiff --git a/toyos-userbound/src/firmware.rs b/toyos-userbound/src/firmware.rs
index fab170718..14c41ecc9 100644
--- a/toyos-userbound/src/firmware.rs
+++ b/toyos-userbound/src/firmware.rs
@@ -150,7 +150,7 @@ impl Memory<'_> {
_ => return No(Refused::Straddles),
}
}
- if overlaps(at, last, LOCAL_APIC) || self.driven.iter().any(|&window| overlaps(at, last, window)) {
+ if self.driven.iter().any(|&window| overlaps(at, last, window)) {
return No(Refused::KernelDevice);
}
let ty = self.type_of(at);m06-past-the-map-passesdiff --git a/toyos-userbound/src/firmware.rs b/toyos-userbound/src/firmware.rs
index fab170718..bb4826901 100644
--- a/toyos-userbound/src/firmware.rs
+++ b/toyos-userbound/src/firmware.rs
@@ -163,9 +163,6 @@ impl Memory<'_> {
Some(EFI_RESERVED | EFI_ACPI_NVS | EFI_ACPI_RECLAIM) => {}
Some(_) | None => return No(Refused::MemoryType),
}
- if last >= self.mapped_end {
- return No(Refused::Unmapped);
- }
if write && self.facs.is_some_and(|facs| overlaps(at, last, facs)) {
return No(Refused::FacsWrite);
}m07-mapped-end-off-by-onediff --git a/toyos-userbound/src/firmware.rs b/toyos-userbound/src/firmware.rs
index fab170718..1a225ef6a 100644
--- a/toyos-userbound/src/firmware.rs
+++ b/toyos-userbound/src/firmware.rs
@@ -163,7 +163,7 @@ impl Memory<'_> {
Some(EFI_RESERVED | EFI_ACPI_NVS | EFI_ACPI_RECLAIM) => {}
Some(_) | None => return No(Refused::MemoryType),
}
- if last >= self.mapped_end {
+ if last > self.mapped_end {
return No(Refused::Unmapped);
}
if write && self.facs.is_some_and(|facs| overlaps(at, last, facs)) {m08-facs-write-passesdiff --git a/toyos-userbound/src/firmware.rs b/toyos-userbound/src/firmware.rs
index fab170718..ae1888292 100644
--- a/toyos-userbound/src/firmware.rs
+++ b/toyos-userbound/src/firmware.rs
@@ -166,9 +166,6 @@ impl Memory<'_> {
if last >= self.mapped_end {
return No(Refused::Unmapped);
}
- if write && self.facs.is_some_and(|facs| overlaps(at, last, facs)) {
- return No(Refused::FacsWrite);
- }
MemoryVerdict::Through(MemoryAt { at, width })
}
}m09-ecam-is-plain-memorydiff --git a/toyos-userbound/src/firmware.rs b/toyos-userbound/src/firmware.rs
index fab170718..10e3c4030 100644
--- a/toyos-userbound/src/firmware.rs
+++ b/toyos-userbound/src/firmware.rs
@@ -138,7 +138,7 @@ impl Memory<'_> {
pub fn decide(&self, at: u64, width: Width, write: bool) -> MemoryVerdict {
use MemoryVerdict::Refused as No;
let Some(last) = at.checked_add(width.bytes() - 1) else { return No(Refused::Unmapped) };
- if let Some(ecam) = self.ecam {
+ if let Some(ecam) = self.ecam.filter(|_| false) {
match (ecam.holds(at), ecam.holds(last)) {
(true, true) => {
let offset = at - ecam.base;m10-other-types-passdiff --git a/toyos-userbound/src/firmware.rs b/toyos-userbound/src/firmware.rs
index fab170718..099445dc7 100644
--- a/toyos-userbound/src/firmware.rs
+++ b/toyos-userbound/src/firmware.rs
@@ -161,7 +161,8 @@ impl Memory<'_> {
Some(ty) if toyos_bootmap::is_usable_type(ty) => return No(Refused::UsableMemory),
Some(EFI_ACPI_RECLAIM) if write => return No(Refused::TableWrite),
Some(EFI_RESERVED | EFI_ACPI_NVS | EFI_ACPI_RECLAIM) => {}
- Some(_) | None => return No(Refused::MemoryType),
+ Some(_) => {}
+ None => return No(Refused::MemoryType),
}
if last >= self.mapped_end {
return No(Refused::Unmapped);m11-unlisted-passesdiff --git a/toyos-userbound/src/firmware.rs b/toyos-userbound/src/firmware.rs
index fab170718..37610f8e7 100644
--- a/toyos-userbound/src/firmware.rs
+++ b/toyos-userbound/src/firmware.rs
@@ -161,7 +161,8 @@ impl Memory<'_> {
Some(ty) if toyos_bootmap::is_usable_type(ty) => return No(Refused::UsableMemory),
Some(EFI_ACPI_RECLAIM) if write => return No(Refused::TableWrite),
Some(EFI_RESERVED | EFI_ACPI_NVS | EFI_ACPI_RECLAIM) => {}
- Some(_) | None => return No(Refused::MemoryType),
+ Some(_) => return No(Refused::MemoryType),
+ None => {}
}
if last >= self.mapped_end {
return No(Refused::Unmapped);m12-overlap-misses-the-last-bytediff --git a/toyos-userbound/src/firmware.rs b/toyos-userbound/src/firmware.rs
index fab170718..5a3cfe757 100644
--- a/toyos-userbound/src/firmware.rs
+++ b/toyos-userbound/src/firmware.rs
@@ -119,7 +119,7 @@ pub enum MemoryVerdict {
}
fn overlaps(first: u64, last: u64, (start, end): (u64, u64)) -> bool {
- first < end && start <= last
+ first < end && start < last
}
impl Memory<'_> {m13-kept-port-passesdiff --git a/toyos-userbound/src/firmware.rs b/toyos-userbound/src/firmware.rs
index fab170718..c2a5207c6 100644
--- a/toyos-userbound/src/firmware.rs
+++ b/toyos-userbound/src/firmware.rs
@@ -216,7 +216,7 @@ pub fn port(standing: impl Fn(u16) -> Standing, port: u16, width: Width, write:
Standing::Free | Standing::Declared(Mediated::Open) => {}
Standing::Declared(Mediated::ReadOnly) if !write => {}
Standing::Declared(Mediated::ReadOnly) => return Err(Refused::ReadOnlyPort),
- Standing::Declared(Mediated::Kept) => return Err(Refused::KernelPort),
+ Standing::Declared(Mediated::Kept) => {}
Standing::Row => return Err(Refused::ClaimedPort),
}
}m14-read-only-port-writtendiff --git a/toyos-userbound/src/firmware.rs b/toyos-userbound/src/firmware.rs
index fab170718..425edb76f 100644
--- a/toyos-userbound/src/firmware.rs
+++ b/toyos-userbound/src/firmware.rs
@@ -215,7 +215,7 @@ pub fn port(standing: impl Fn(u16) -> Standing, port: u16, width: Width, write:
match standing(port) {
Standing::Free | Standing::Declared(Mediated::Open) => {}
Standing::Declared(Mediated::ReadOnly) if !write => {}
- Standing::Declared(Mediated::ReadOnly) => return Err(Refused::ReadOnlyPort),
+ Standing::Declared(Mediated::ReadOnly) => {}
Standing::Declared(Mediated::Kept) => return Err(Refused::KernelPort),
Standing::Row => return Err(Refused::ClaimedPort),
}m15-row-port-passesdiff --git a/toyos-userbound/src/firmware.rs b/toyos-userbound/src/firmware.rs
index fab170718..5ea8ca39b 100644
--- a/toyos-userbound/src/firmware.rs
+++ b/toyos-userbound/src/firmware.rs
@@ -217,7 +217,7 @@ pub fn port(standing: impl Fn(u16) -> Standing, port: u16, width: Width, write:
Standing::Declared(Mediated::ReadOnly) if !write => {}
Standing::Declared(Mediated::ReadOnly) => return Err(Refused::ReadOnlyPort),
Standing::Declared(Mediated::Kept) => return Err(Refused::KernelPort),
- Standing::Row => return Err(Refused::ClaimedPort),
+ Standing::Row => {}
}
}
Ok(PortAt { port, width })m16-only-the-first-port-askeddiff --git a/toyos-userbound/src/firmware.rs b/toyos-userbound/src/firmware.rs
index fab170718..76fe4cb79 100644
--- a/toyos-userbound/src/firmware.rs
+++ b/toyos-userbound/src/firmware.rs
@@ -211,7 +211,7 @@ pub fn port(standing: impl Fn(u16) -> Standing, port: u16, width: Width, write:
if width == Width::QWord || port as usize + width.bytes() as usize > IO_PORTS {
return Err(Refused::PortSpan);
}
- for port in port..=port + (width.bytes() as u16 - 1) {
+ for port in port..=port {
match standing(port) {
Standing::Free | Standing::Declared(Mediated::Open) => {}
Standing::Declared(Mediated::ReadOnly) if !write => {}m17-qword-port-passesdiff --git a/toyos-userbound/src/firmware.rs b/toyos-userbound/src/firmware.rs
index fab170718..1d149eb2c 100644
--- a/toyos-userbound/src/firmware.rs
+++ b/toyos-userbound/src/firmware.rs
@@ -208,7 +208,7 @@ impl PortAt {
/// Decide an access of `width` at `port`: every port it spans is asked of
/// `standing`.
pub fn port(standing: impl Fn(u16) -> Standing, port: u16, width: Width, write: bool) -> Result<PortAt, Refused> {
- if width == Width::QWord || port as usize + width.bytes() as usize > IO_PORTS {
+ if port as usize + width.bytes() as usize > IO_PORTS {
return Err(Refused::PortSpan);
}
for port in port..=port + (width.bytes() as u16 - 1) {m18-header-writtendiff --git a/toyos-userbound/src/firmware.rs b/toyos-userbound/src/firmware.rs
index fab170718..057b9b120 100644
--- a/toyos-userbound/src/firmware.rs
+++ b/toyos-userbound/src/firmware.rs
@@ -284,9 +284,6 @@ impl ConfigWrite {
/// its offset and length.
pub fn config_write(at: ConfigAt, free: bool, programmed: impl IntoIterator<Item = (u8, u8)>) -> Result<ConfigWrite, Refused> {
let (first, last) = (at.offset, at.offset + (at.width.bytes() as u16 - 1));
- if first < CONFIG_HEADER {
- return Err(Refused::ConfigHeader);
- }
if last >= CONFIG_EXTENDED {
return Err(Refused::ConfigExtended);
}m19-extended-writtendiff --git a/toyos-userbound/src/firmware.rs b/toyos-userbound/src/firmware.rs
index fab170718..f16a999fa 100644
--- a/toyos-userbound/src/firmware.rs
+++ b/toyos-userbound/src/firmware.rs
@@ -287,9 +287,6 @@ pub fn config_write(at: ConfigAt, free: bool, programmed: impl IntoIterator<Item
if first < CONFIG_HEADER {
return Err(Refused::ConfigHeader);
}
- if last >= CONFIG_EXTENDED {
- return Err(Refused::ConfigExtended);
- }
if !free {
return Err(Refused::ConfigDriven);
}m20-driven-function-writtendiff --git a/toyos-userbound/src/firmware.rs b/toyos-userbound/src/firmware.rs
index fab170718..35f2b3876 100644
--- a/toyos-userbound/src/firmware.rs
+++ b/toyos-userbound/src/firmware.rs
@@ -290,9 +290,6 @@ pub fn config_write(at: ConfigAt, free: bool, programmed: impl IntoIterator<Item
if last >= CONFIG_EXTENDED {
return Err(Refused::ConfigExtended);
}
- if !free {
- return Err(Refused::ConfigDriven);
- }
for (offset, len) in programmed {
if first < u16::from(offset) + u16::from(len) && u16::from(offset) <= last {
return Err(Refused::ConfigCapability);m21-capability-writtendiff --git a/toyos-userbound/src/firmware.rs b/toyos-userbound/src/firmware.rs
index fab170718..d11fc437a 100644
--- a/toyos-userbound/src/firmware.rs
+++ b/toyos-userbound/src/firmware.rs
@@ -295,7 +295,7 @@ pub fn config_write(at: ConfigAt, free: bool, programmed: impl IntoIterator<Item
}
for (offset, len) in programmed {
if first < u16::from(offset) + u16::from(len) && u16::from(offset) <= last {
- return Err(Refused::ConfigCapability);
+ continue;
}
}
Ok(ConfigWrite(at))m22-capability-end-off-by-onediff --git a/toyos-userbound/src/firmware.rs b/toyos-userbound/src/firmware.rs
index fab170718..3ba765ff2 100644
--- a/toyos-userbound/src/firmware.rs
+++ b/toyos-userbound/src/firmware.rs
@@ -294,7 +294,7 @@ pub fn config_write(at: ConfigAt, free: bool, programmed: impl IntoIterator<Item
return Err(Refused::ConfigDriven);
}
for (offset, len) in programmed {
- if first < u16::from(offset) + u16::from(len) && u16::from(offset) <= last {
+ if first + 1 < u16::from(offset) + u16::from(len) && u16::from(offset) <= last {
return Err(Refused::ConfigCapability);
}
}m23-any-segment-reacheddiff --git a/toyos-userbound/src/firmware.rs b/toyos-userbound/src/firmware.rs
index fab170718..b568d68d7 100644
--- a/toyos-userbound/src/firmware.rs
+++ b/toyos-userbound/src/firmware.rs
@@ -250,7 +250,7 @@ impl ConfigAt {
/// dword boundary, the unit a configuration register is defined in.
pub fn config(ecam: Option<Ecam>, segment: u16, function: Function, offset: u16, width: Width) -> Result<ConfigAt, Refused> {
let reached = ecam.is_some_and(|ecam| {
- ecam.segment == segment && (ecam.first_bus..=ecam.last_bus).contains(&function.bus)
+ (ecam.first_bus..=ecam.last_bus).contains(&function.bus)
});
if !reached || function.device > 31 || function.function > 7 {
return Err(Refused::ConfigUnreachable);m24-any-bus-reacheddiff --git a/toyos-userbound/src/firmware.rs b/toyos-userbound/src/firmware.rs
index fab170718..9e2fd339b 100644
--- a/toyos-userbound/src/firmware.rs
+++ b/toyos-userbound/src/firmware.rs
@@ -250,7 +250,7 @@ impl ConfigAt {
/// dword boundary, the unit a configuration register is defined in.
pub fn config(ecam: Option<Ecam>, segment: u16, function: Function, offset: u16, width: Width) -> Result<ConfigAt, Refused> {
let reached = ecam.is_some_and(|ecam| {
- ecam.segment == segment && (ecam.first_bus..=ecam.last_bus).contains(&function.bus)
+ ecam.segment == segment
});
if !reached || function.device > 31 || function.function > 7 {
return Err(Refused::ConfigUnreachable);m25-config-crosses-a-dworddiff --git a/toyos-userbound/src/firmware.rs b/toyos-userbound/src/firmware.rs
index fab170718..38c99c74a 100644
--- a/toyos-userbound/src/firmware.rs
+++ b/toyos-userbound/src/firmware.rs
@@ -256,7 +256,7 @@ pub fn config(ecam: Option<Ecam>, segment: u16, function: Function, offset: u16,
return Err(Refused::ConfigUnreachable);
}
let bytes = width.bytes() as u16;
- if width == Width::QWord || offset % 4 + bytes > 4 || offset >= CONFIG_BYTES {
+ if width == Width::QWord || offset >= CONFIG_BYTES {
return Err(Refused::ConfigSpan);
}
Ok(ConfigAt { function, offset, width })m26-config-past-the-functiondiff --git a/toyos-userbound/src/firmware.rs b/toyos-userbound/src/firmware.rs
index fab170718..39683b5f5 100644
--- a/toyos-userbound/src/firmware.rs
+++ b/toyos-userbound/src/firmware.rs
@@ -256,7 +256,7 @@ pub fn config(ecam: Option<Ecam>, segment: u16, function: Function, offset: u16,
return Err(Refused::ConfigUnreachable);
}
let bytes = width.bytes() as u16;
- if width == Width::QWord || offset % 4 + bytes > 4 || offset >= CONFIG_BYTES {
+ if width == Width::QWord || offset % 4 + bytes > 4 {
return Err(Refused::ConfigSpan);
}
Ok(ConfigAt { function, offset, width })m27-ecam-first-bus-ignoreddiff --git a/toyos-userbound/src/firmware.rs b/toyos-userbound/src/firmware.rs
index fab170718..fe8cde6d2 100644
--- a/toyos-userbound/src/firmware.rs
+++ b/toyos-userbound/src/firmware.rs
@@ -60,7 +60,7 @@ pub struct Ecam {
impl Ecam {
fn holds(&self, at: u64) -> bool {
// Saturating: the base is firmware's word.
- let start = self.base.saturating_add(u64::from(self.first_bus) << 20);
+ let start = self.base;
let end = self.base.saturating_add((u64::from(self.last_bus) + 1) << 20);
(start..end).contains(&at)
}m28-owned-lock-takendiff --git a/toyos-acpi/src/facs.rs b/toyos-acpi/src/facs.rs
index db2c08d9f..168b869d1 100644
--- a/toyos-acpi/src/facs.rs
+++ b/toyos-acpi/src/facs.rs
@@ -75,7 +75,7 @@ pub fn facs<P: Phys>(phys: P, fadt: &Table<P>) -> Result<Facs, FacsRefused> {
pub const fn acquire(word: u32) -> (u32, bool) {
let owned = word & OWNED != 0;
let new = word & !PENDING | OWNED | if owned { PENDING } else { 0 };
- (new, !owned)
+ (new, true)
}
/// §5.2.10.1's `ReleaseGlobalLock`: the word to exchange `word` for, andm29-pending-never-setdiff --git a/toyos-acpi/src/facs.rs b/toyos-acpi/src/facs.rs
index db2c08d9f..da294a278 100644
--- a/toyos-acpi/src/facs.rs
+++ b/toyos-acpi/src/facs.rs
@@ -74,7 +74,7 @@ pub fn facs<P: Phys>(phys: P, fadt: &Table<P>) -> Result<Facs, FacsRefused> {
/// the two agree while bits 2 to 7 are zero, as Table 5.16 reserves them.
pub const fn acquire(word: u32) -> (u32, bool) {
let owned = word & OWNED != 0;
- let new = word & !PENDING | OWNED | if owned { PENDING } else { 0 };
+ let new = word & !PENDING | OWNED;
(new, !owned)
}
m30-release-never-signalsdiff --git a/toyos-acpi/src/facs.rs b/toyos-acpi/src/facs.rs
index db2c08d9f..5aecb8026 100644
--- a/toyos-acpi/src/facs.rs
+++ b/toyos-acpi/src/facs.rs
@@ -82,5 +82,5 @@ pub const fn acquire(word: u32) -> (u32, bool) {
/// whether the other side asked while the lock was held and is owed the
/// release's signal.
pub const fn release(word: u32) -> (u32, bool) {
- (word & !(PENDING | OWNED), word & PENDING != 0)
+ (word & !(PENDING | OWNED), false)
}m31-release-keeps-pendingdiff --git a/toyos-acpi/src/facs.rs b/toyos-acpi/src/facs.rs
index db2c08d9f..b38229bce 100644
--- a/toyos-acpi/src/facs.rs
+++ b/toyos-acpi/src/facs.rs
@@ -82,5 +82,5 @@ pub const fn acquire(word: u32) -> (u32, bool) {
/// whether the other side asked while the lock was held and is owed the
/// release's signal.
pub const fn release(word: u32) -> (u32, bool) {
- (word & !(PENDING | OWNED), word & PENDING != 0)
+ (word & !OWNED, word & PENDING != 0)
}m32-narrow-facs-address-winsdiff --git a/toyos-acpi/src/facs.rs b/toyos-acpi/src/facs.rs
index db2c08d9f..09a42b4f4 100644
--- a/toyos-acpi/src/facs.rs
+++ b/toyos-acpi/src/facs.rs
@@ -44,7 +44,7 @@ pub enum FacsRefused {
/// holds a non-zero one, else `FIRMWARE_CTRL` (Table 5.9).
pub fn facs<P: Phys>(phys: P, fadt: &Table<P>) -> Result<Facs, FacsRefused> {
let wide = match fadt.byte(SDT_REVISION) {
- Some(r) if r >= 2 => fadt.u64_at(FADT_X_FIRMWARE_CTRL).filter(|a| *a != 0),
+ Some(r) if r >= 2 => fadt.u64_at(FADT_X_FIRMWARE_CTRL).filter(|_| false),
_ => None,
};
let base = wide.unwrap_or_else(|| u64::from(fadt.u32_at(FADT_FIRMWARE_CTRL).unwrap_or(0)));g00-policy-passes-everythingdiff --git a/toyos-userbound/src/firmware.rs b/toyos-userbound/src/firmware.rs
index fab170718..8ce274949 100644
--- a/toyos-userbound/src/firmware.rs
+++ b/toyos-userbound/src/firmware.rs
@@ -150,6 +150,9 @@ impl Memory<'_> {
_ => return No(Refused::Straddles),
}
}
+ if true {
+ return MemoryVerdict::Through(MemoryAt { at, width });
+ }
if overlaps(at, last, LOCAL_APIC) || self.driven.iter().any(|&window| overlaps(at, last, window)) {
return No(Refused::KernelDevice);
}
@@ -212,7 +215,7 @@ pub fn port(standing: impl Fn(u16) -> Standing, port: u16, width: Width, write:
return Err(Refused::PortSpan);
}
for port in port..=port + (width.bytes() as u16 - 1) {
- match standing(port) {
+ match { let _ = standing(port); Standing::Free } {
Standing::Free | Standing::Declared(Mediated::Open) => {}
Standing::Declared(Mediated::ReadOnly) if !write => {}
Standing::Declared(Mediated::ReadOnly) => return Err(Refused::ReadOnlyPort),
@@ -284,6 +287,9 @@ impl ConfigWrite {
/// its offset and length.
pub fn config_write(at: ConfigAt, free: bool, programmed: impl IntoIterator<Item = (u8, u8)>) -> Result<ConfigWrite, Refused> {
let (first, last) = (at.offset, at.offset + (at.width.bytes() as u16 - 1));
+ if true {
+ return Ok(ConfigWrite(at));
+ }
if first < CONFIG_HEADER {
return Err(Refused::ConfigHeader);
}g01-unbound-claim-answersdiff --git a/kernel/src/syscall/device.rs b/kernel/src/syscall/device.rs
index 231a0b1c2..a15612e5b 100644
--- a/kernel/src/syscall/device.rs
+++ b/kernel/src/syscall/device.rs
@@ -131,9 +131,6 @@ pub(super) fn sys_acpi(ctx: &SyscallContext, handle: RawHandle, op: u64, at: u64
}
Err(e) => return e.refuse(),
};
- if !crate::isa::bound_to(row, process::current_process()) {
- return SyscallError::PermissionDenied.to_u64();
- }
let done = match op {
ops::ACCESS => ctx.copy_in::<toyos_abi::acpi::Access>(UserAddr::new(at)).and_then(|mut request| {
crate::arch::acpi_mode::access(row, &mut request)?;g02-claim-end-keeps-the-lockdiff --git a/kernel/src/arch/x86_64/acpi_mode.rs b/kernel/src/arch/x86_64/acpi_mode.rs
index ea08160cb..a4c012e71 100644
--- a/kernel/src/arch/x86_64/acpi_mode.rs
+++ b/kernel/src/arch/x86_64/acpi_mode.rs
@@ -372,7 +372,6 @@ pub fn release(row: usize) {
{
let mut lock = GLOBAL_LOCK.lock();
lock.claimed = false;
- give_back(hardware, &mut lock, "its claim is gone");
}
if ENABLED.load(Ordering::Relaxed) {
leave(hardware);g03-runtime-declarations-unaskeddiff --git a/kernel/src/arch/x86_64/pio.rs b/kernel/src/arch/x86_64/pio.rs
index 05b014183..de85c6ba7 100644
--- a/kernel/src/arch/x86_64/pio.rs
+++ b/kernel/src/arch/x86_64/pio.rs
@@ -125,9 +125,6 @@ pub fn standing(port: u16, row: usize) -> Standing {
if let Some(&(.., mediated)) = FIXED.iter().find(|(_, fixed, _)| fixed.0.overlaps(one)) {
return Standing::Declared(mediated);
}
- if let Some(mediated) = RUNTIME.lock().mediated(port) {
- return Standing::Declared(mediated);
- }
let others = (0..crate::isa::MAX_ROWS).filter(|&other| other != row).filter_map(crate::isa::runs);
if others.flatten().any(|run| run.overlaps(one)) { Standing::Row } else { Standing::Free }
}g04-fixed-declarations-unaskeddiff --git a/kernel/src/arch/x86_64/pio.rs b/kernel/src/arch/x86_64/pio.rs
index 05b014183..ab39896a0 100644
--- a/kernel/src/arch/x86_64/pio.rs
+++ b/kernel/src/arch/x86_64/pio.rs
@@ -122,9 +122,6 @@ pub fn holder(ports: Ports) -> Option<&'static str> {
/// free. Its own row's ports are free: it holds them already.
pub fn standing(port: u16, row: usize) -> Standing {
let one = Ports::one(port);
- if let Some(&(.., mediated)) = FIXED.iter().find(|(_, fixed, _)| fixed.0.overlaps(one)) {
- return Standing::Declared(mediated);
- }
if let Some(mediated) = RUNTIME.lock().mediated(port) {
return Standing::Declared(mediated);
}g06-take-not-recordeddiff --git a/kernel/src/arch/x86_64/acpi_mode.rs b/kernel/src/arch/x86_64/acpi_mode.rs
index ea08160cb..aebacfa67 100644
--- a/kernel/src/arch/x86_64/acpi_mode.rs
+++ b/kernel/src/arch/x86_64/acpi_mode.rs
@@ -490,7 +490,7 @@ pub fn lock_take() -> Result<bool, SyscallError> {
}
}
};
- lock.held = taken;
+ lock.held = taken && false;
Ok(taken)
}
g07-every-function-freediff --git a/kernel/src/pcidev/mod.rs b/kernel/src/pcidev/mod.rs
index 0bab2120c..15e4d1b03 100644
--- a/kernel/src/pcidev/mod.rs
+++ b/kernel/src/pcidev/mod.rs
@@ -415,7 +415,7 @@ pub fn mediated_standing(bus: u8, dev: u8, func: u8) -> (bool, Vec<(u8, u8)>) {
let driven = machine.kernel_driven.contains(&who) || machine.resetting.iter().any(|&(reset, ..)| reset == who);
match machine.functions.iter().find(|pci| requester(pci) == who) {
Some(pci) if !driven => *pci,
- _ => return (false, Vec::new()),
+ _ => return (true, Vec::new()),
}
};
if SLOTS.lock().contains(&Slot::Held(who)) {g08-memory-write-droppeddiff --git a/kernel/src/arch/x86_64/acpi_mode.rs b/kernel/src/arch/x86_64/acpi_mode.rs
index ea08160cb..ac29368d4 100644
--- a/kernel/src/arch/x86_64/acpi_mode.rs
+++ b/kernel/src/arch/x86_64/acpi_mode.rs
@@ -579,7 +579,7 @@ fn write_memory(passed: &MemoryAt, value: u64) {
Width::Byte => at.as_mut_ptr::<u8>().write_volatile(value as u8),
Width::Word => at.as_mut_ptr::<Unaligned<u16>>().write_volatile(Unaligned(value as u16)),
Width::DWord => at.as_mut_ptr::<Unaligned<u32>>().write_volatile(Unaligned(value as u32)),
- Width::QWord => at.as_mut_ptr::<Unaligned<u64>>().write_volatile(Unaligned(value)),
+ Width::QWord => {}
}
}
}g10-wide-value-takendiff --git a/kernel/src/arch/x86_64/acpi_mode.rs b/kernel/src/arch/x86_64/acpi_mode.rs
index ea08160cb..458fac23b 100644
--- a/kernel/src/arch/x86_64/acpi_mode.rs
+++ b/kernel/src/arch/x86_64/acpi_mode.rs
@@ -697,7 +697,7 @@ pub fn access(row: usize, request: &mut Access) -> Result<(), SyscallError> {
};
let write = match request.write {
0 => None,
- 1 if request.value <= width.max_value() => Some(request.value),
+ 1 => Some(request.value),
_ => return Err(SyscallError::InvalidArgument),
};
if request.reserved != [0; 3] {g11-reserved-bytes-unreaddiff --git a/kernel/src/arch/x86_64/acpi_mode.rs b/kernel/src/arch/x86_64/acpi_mode.rs
index ea08160cb..f2cdc6aa6 100644
--- a/kernel/src/arch/x86_64/acpi_mode.rs
+++ b/kernel/src/arch/x86_64/acpi_mode.rs
@@ -700,9 +700,6 @@ pub fn access(row: usize, request: &mut Access) -> Result<(), SyscallError> {
1 if request.value <= width.max_value() => Some(request.value),
_ => return Err(SyscallError::InvalidArgument),
};
- if request.reserved != [0; 3] {
- return Err(SyscallError::InvalidArgument);
- }
request.memory_type = toyos_abi::acpi::UNLISTED;
let made = match space {
Space::SystemMemory => memory(hardware, request, width, write),g12-pending-not-leftdiff --git a/kernel/src/arch/x86_64/acpi_mode.rs b/kernel/src/arch/x86_64/acpi_mode.rs
index ea08160cb..b5b9b5f04 100644
--- a/kernel/src/arch/x86_64/acpi_mode.rs
+++ b/kernel/src/arch/x86_64/acpi_mode.rs
@@ -483,7 +483,7 @@ pub fn lock_take() -> Result<bool, SyscallError> {
let mut read = word.load(Ordering::Acquire);
loop {
let (new, acquired) = toyos_acpi::acquire(read);
- match word.compare_exchange(read, new, Ordering::AcqRel, Ordering::Acquire) {
+ match word.compare_exchange(read, if acquired { new } else { read }, Ordering::AcqRel, Ordering::Acquire) {
Ok(_) => break acquired,
Err(now) => read = now,
} |
|
Review round 1 of Net lines, CI at this head, run 37694294491 on BLOCKER
NOTE
SEND BACK |
…BAR refused, the lock word typed, the stop obeyed - Every configuration write is refused by one name, `ConfigWrite`. The allow arm, `ConfigWrite` the witness, `pcidev::mediated_standing`, `caps::programmed_len` and four refusal names go: no path of the measured tables writes configuration space, and the arm let a holder move the ECAM base and the power-management block. - A device's memory is refused by the page: each window `map_mmio` made and each memory BAR `pcidev` keeps, where firmware put it and where a claim moved it, grown to the 4 KiB pages it lies in. `KernelDevice` becomes `DeviceMemory`. - The FACS is held to §5.2.10's 64-byte boundary, and the lock word is exchanged only through a witness the policy answers where all four of its bytes are in ACPI NVS or reserved memory. - One lock, `HOLDER`, is held from the decision to the last instruction of every access and every lock exchange, refuses each once the stop has begun, and is taken by `settle` before the power-off owns the hardware. - The probe turns red on a window nobody recorded, a BAR nobody fed the policy, another row's port answered free and a release that wrote no `GBL_RLS`; it boots with the i8042 withheld so that row is a claim's. - The `acpi_server_death` row reads where the machine's lock word is. - The issue records what the review found the surface still passes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RvnWQFcMuGqTHYhvSnTe8A
|
Round 2's mutations at m1-window-not-recorded — must red diff --git a/kernel/src/arch/x86_64/paging.rs b/kernel/src/arch/x86_64/paging.rs
index 38525436e..6b2e4a77d 100644
--- a/kernel/src/arch/x86_64/paging.rs
+++ b/kernel/src/arch/x86_64/paging.rs
@@ -883,9 +883,7 @@ pub fn map_mmio(phys: u64, size: u64, policy: MmioPolicy) -> crate::mm::Mmio {
let mmio = kernel().lock().map_mmio(phys, size, policy.cache());
{
let mut driven = DRIVEN.lock();
- if !driven.contains(&(phys, phys + size)) {
- driven.push((phys, phys + size));
- }
+ let _ = &mut driven;
}
crate::arch::tlb::shootdown(crate::invalidation::Origin::Mmio);
// Read back off the table and logged beside firmware's MTRR verdict: them2-no-gbl-rls — must red diff --git a/kernel/src/arch/x86_64/acpi_mode.rs b/kernel/src/arch/x86_64/acpi_mode.rs
index aea86e0eb..dfdf9935b 100644
--- a/kernel/src/arch/x86_64/acpi_mode.rs
+++ b/kernel/src/arch/x86_64/acpi_mode.rs
@@ -554,7 +554,7 @@ fn give_back(hardware: &Hardware, holder: &mut Holder, orphaned: &str) {
let control = hardware.control.port(0);
// SAFETY: the PM1a control block, declared; `GBL_RLS` over the
// register as it reads, whose `SLP_EN` reads clear (§4.8.3.2).
- unsafe { cpu::outw(control, cpu::inw(control) | GBL_RLS) };
+ let _ = (control, GBL_RLS);
}
signal
});m3-another-rows-port-is-free — must red diff --git a/kernel/src/arch/x86_64/pio.rs b/kernel/src/arch/x86_64/pio.rs
index 05b014183..f43523109 100644
--- a/kernel/src/arch/x86_64/pio.rs
+++ b/kernel/src/arch/x86_64/pio.rs
@@ -129,7 +129,8 @@ pub fn standing(port: u16, row: usize) -> Standing {
return Standing::Declared(mediated);
}
let others = (0..crate::isa::MAX_ROWS).filter(|&other| other != row).filter_map(crate::isa::runs);
- if others.flatten().any(|run| run.overlaps(one)) { Standing::Row } else { Standing::Free }
+ let _ = others.flatten().any(|run| run.overlaps(one));
+ Standing::Free
}
/// The port an access the mediation policy passed begins at.m4-no-bar-fed-to-the-policy — must red diff --git a/kernel/src/pcidev/mod.rs b/kernel/src/pcidev/mod.rs
index 175f9a494..930481e52 100644
--- a/kernel/src/pcidev/mod.rs
+++ b/kernel/src/pcidev/mod.rs
@@ -413,7 +413,8 @@ pub fn with_bar_memory<T>(f: impl FnOnce(&mut dyn Iterator<Item = (u64, u64)>) -
let machine = MACHINE.lock();
let firmware = machine.decoded.iter().map(|&(_, start, end)| (start, end));
let cut = machine.windows.iter().map(|&(_, _, at, span)| (at, at.saturating_add(span)));
- f(&mut firmware.chain(cut))
+ let _ = firmware.chain(cut);
+ f(&mut core::iter::empty())
}
/// The PCI segment group every enumerated function is on.m5-eoi-page-not-rounded — must red diff --git a/toyos-userbound/src/firmware.rs b/toyos-userbound/src/firmware.rs
index b1c22007a..c2e7e4813 100644
--- a/toyos-userbound/src/firmware.rs
+++ b/toyos-userbound/src/firmware.rs
@@ -126,7 +126,8 @@ fn overlaps(first: u64, last: u64, (start, end): (u64, u64)) -> bool {
/// driven through its first 0x20 bytes, and a chipset's keeps an EOI register
/// further into the same page.
fn pages((start, end): (u64, u64)) -> (u64, u64) {
- (start & !(PAGE_4K - 1), end.saturating_add(PAGE_4K - 1) & !(PAGE_4K - 1))
+ let _ = PAGE_4K;
+ (start, end)
}
/// The UEFI type of the range of `map` holding `at`, or `None` where it listsm6-facs-aligned-to-four — must red diff --git a/toyos-acpi/src/facs.rs b/toyos-acpi/src/facs.rs
index 23f2ccf1f..9dd3b65dc 100644
--- a/toyos-acpi/src/facs.rs
+++ b/toyos-acpi/src/facs.rs
@@ -52,7 +52,7 @@ pub fn facs<P: Phys>(phys: P, fadt: &Table<P>) -> Result<Facs, FacsRefused> {
if base == 0 {
return Err(FacsRefused::Absent);
}
- if !base.is_multiple_of(FACS_ALIGN) {
+ if !base.is_multiple_of(FACS_ALIGN / 16) {
return Err(FacsRefused::Misaligned(base));
}
if !phys.readable(base, FACS_MIN_LEN as usize) {m7-lock-word-typed-by-its-first-byte — must red diff --git a/toyos-userbound/src/firmware.rs b/toyos-userbound/src/firmware.rs
index b1c22007a..6085dfa6a 100644
--- a/toyos-userbound/src/firmware.rs
+++ b/toyos-userbound/src/firmware.rs
@@ -219,7 +219,7 @@ pub fn lock_word(map: &[MemoryMapEntry], mapped_end: u64, at: u64) -> Result<Loc
}
// No overflow: `at` is on a dword boundary.
let last = at + 3;
- for byte in at..=last {
+ for byte in at..=at {
match type_of(map, byte) {
Some(EFI_RESERVED | EFI_ACPI_NVS) => {}
other => return Err(NoLockWord::Type(other)),m8-config-write-passes — must red diff --git a/toyos-userbound/src/firmware.rs b/toyos-userbound/src/firmware.rs
index b1c22007a..22a5cf752 100644
--- a/toyos-userbound/src/firmware.rs
+++ b/toyos-userbound/src/firmware.rs
@@ -315,9 +315,7 @@ impl ConfigAt {
/// its shape: a function the window reaches, and at most a dword that crosses
/// no dword boundary, the unit a configuration register is defined in.
pub fn config(ecam: Option<Ecam>, segment: u16, function: Function, offset: u16, width: Width, write: bool) -> Result<ConfigAt, Refused> {
- if write {
- return Err(Refused::ConfigWrite);
- }
+ let _ = write;
let reached = ecam.is_some_and(|ecam| {
ecam.segment == segment && (ecam.first_bus..=ecam.last_bus).contains(&function.bus)
}); |
|
T14 at |
`Memory::decide` takes the record of device memory by value, and one test called it twice on the same value: CI's host step did not compile it, so no workspace test ran at 3771534. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RvnWQFcMuGqTHYhvSnTe8A
…s's branch - toyos-abi/src/acpi.rs: `AcpiInfo`, with this branch's `rsdp` and `reserved`, and `Access` are declared through `user_safe!`; their hand size assertions and `as_bytes` go with main's. - kernel/src/user_ptr.rs: main's side whole; the hand impl for `Access` goes with every other. - kernel/src/arch/x86_64/acpi_mode.rs: main's `smi_cmd` owns the port, its lock and its declaration; `settle` here keeps the holder's half alone. - kernel/src/arch/x86_64/smi_cmd.rs: the declaration says `ReadOnly`, the argument this branch made `pio::declare` require. - kernel/src/arch/x86_64/power.rs: the power-off calls both settles. The merge had taken main's line, which replaced the call this branch's wait hangs off, without a conflict. - tests/toyos.rs: `acpi_death_on_metal` reads main's line shape and its boot-processor judgement, and this branch's lock-word line. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RvnWQFcMuGqTHYhvSnTe8A
|
T14 at the merged head |
|
Review round 2 of Net lines, CI at this head, run 37708432612 on Round 1's BLOCKERs
BLOCKER
NOTE
What the server half has to read on the metal machine
SEND BACK |
…s, and evaluates \_S5 The server half of slice S1, on the kernel half's branch. toyos-acpi: definition_blocks walks the DSDT the FADT names and then every SSDT the XSDT lists, in order, each validated or answered as its refusal. acpiserver: after arming, so a press during the load latches, the server fetches every definition block through SYS_ACPI into its own memory (tables.rs), loads each with toyos_aml (aml.rs) through a Host over the same access (host.rs), and evaluates \_S5. Nothing is written: a write in any space and every access to the embedded controller's space are denied by name. The Global Lock is the kernel's to exchange; a take that finds the firmware holding it waits for GBL_STS with every other event disabled, for at most 10 s an evaluation. A refused SSDT is said and the load goes on; a refused DSDT leaves no namespace and the power button served (the owner's ruling: "Go on, say it loudly"). A line anyone may quote carries the address space, the kernel's name for the refusal, the memory type and counts; what the firmware chose goes on a line of its own. toyos-aml: the two refusals of a bridge's registers are Error::Bridge, carrying the function, its Header Type and its Secondary Bus Number. toyos: AcpiDev gains access, lock_take and lock_release. Review round 2 of the kernel half: - the probe ends by taking the Global Lock and asking for the power-off, and acpi_mediated_access reads the kernel's "(the machine is stopping)" line: what fails when the power-off stops settling the holder; - a FACS the kernel refuses answers a take NotSupported, and only an absent one answers taken; - the BAR record keeps firmware's half: a window pcidev cuts is only ever at an address firmware's map does not list, which is refused by that. Tests: the iterator on QEMU's fixtures, on crafted tables and under the corpus's single-byte mutations; the host, the fetch, the ledger and the load against a scripted kernel, QEMU's own tables among them; acpi_power_button reads the DSDT's load line and \_S5 beside the kernel's decode; the metal row acpi_tables_loaded reads the same on the T14 with the load's counts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RvnWQFcMuGqTHYhvSnTe8A
|
Mutations at No patch here reaches the take a refused FACS answers g00-policy-passes-everything — must red the negative control: diff --git a/toyos-userbound/src/firmware.rs b/toyos-userbound/src/firmware.rs
index b1c22007a..00b36a701 100644
--- a/toyos-userbound/src/firmware.rs
+++ b/toyos-userbound/src/firmware.rs
@@ -156,6 +156,9 @@ impl<D: IntoIterator<Item = (u64, u64)>> Memory<'_, D> {
_ => return No(Refused::Straddles),
}
}
+ if true {
+ return MemoryVerdict::Through(MemoryAt { at, width });
+ }
if overlaps(at, last, LOCAL_APIC) || self.devices.into_iter().any(|device| overlaps(at, last, pages(device))) {
return No(Refused::DeviceMemory);
}
@@ -270,7 +273,7 @@ pub fn port(standing: impl Fn(u16) -> Standing, port: u16, width: Width, write:
return Err(Refused::PortSpan);
}
for port in port..=port + (width.bytes() as u16 - 1) {
- match standing(port) {
+ match { let _ = standing(port); Standing::Free } {
Standing::Free | Standing::Declared(Mediated::Open) => {}
Standing::Declared(Mediated::ReadOnly) if !write => {}
Standing::Declared(Mediated::ReadOnly) => return Err(Refused::ReadOnlyPort),
@@ -315,9 +318,7 @@ impl ConfigAt {
/// its shape: a function the window reaches, and at most a dword that crosses
/// no dword boundary, the unit a configuration register is defined in.
pub fn config(ecam: Option<Ecam>, segment: u16, function: Function, offset: u16, width: Width, write: bool) -> Result<ConfigAt, Refused> {
- if write {
- return Err(Refused::ConfigWrite);
- }
+ let _ = write;
let reached = ecam.is_some_and(|ecam| {
ecam.segment == segment && (ecam.first_bus..=ecam.last_bus).contains(&function.bus)
});k1-the-power-off-does-not-settle-the-holder — must red review round 2's patch: diff --git a/kernel/src/arch/x86_64/power.rs b/kernel/src/arch/x86_64/power.rs
index 0eed43f94..ba48c92b6 100644
--- a/kernel/src/arch/x86_64/power.rs
+++ b/kernel/src/arch/x86_64/power.rs
@@ -171,7 +171,6 @@ pub fn off(stopping: crate::quiesce::Stopping) -> ! {
let control = control.port(0);
let taken = pio::take_back(&stopping);
super::smi_cmd::settle(&taken);
- super::acpi_mode::settle(&taken);
let held = cpu::inw(control);
if held & SCI_EN != 0 {
super::acpi_mode::quiet(&taken);k2-a-stop-leaves-the-lock-taken — must red diff --git a/kernel/src/arch/x86_64/acpi_mode.rs b/kernel/src/arch/x86_64/acpi_mode.rs
index 078444cfd..6263c37c9 100644
--- a/kernel/src/arch/x86_64/acpi_mode.rs
+++ b/kernel/src/arch/x86_64/acpi_mode.rs
@@ -173,7 +173,7 @@ static ENABLED: AtomicBool = AtomicBool::new(false);
pub fn settle(_taken: &TakenBack) {
let mut holder = HOLDER.lock();
if let Some(hardware) = hardware() {
- give_back(hardware, &mut holder, "the machine is stopping");
+ let _ = (hardware, &mut holder);
}
}
m1-window-not-recorded — must red diff --git a/kernel/src/arch/x86_64/paging.rs b/kernel/src/arch/x86_64/paging.rs
index 38525436e..6b2e4a77d 100644
--- a/kernel/src/arch/x86_64/paging.rs
+++ b/kernel/src/arch/x86_64/paging.rs
@@ -883,9 +883,7 @@ pub fn map_mmio(phys: u64, size: u64, policy: MmioPolicy) -> crate::mm::Mmio {
let mmio = kernel().lock().map_mmio(phys, size, policy.cache());
{
let mut driven = DRIVEN.lock();
- if !driven.contains(&(phys, phys + size)) {
- driven.push((phys, phys + size));
- }
+ let _ = &mut driven;
}
crate::arch::tlb::shootdown(crate::invalidation::Origin::Mmio);
// Read back off the table and logged beside firmware's MTRR verdict: them2-no-gbl-rls — must red diff --git a/kernel/src/arch/x86_64/acpi_mode.rs b/kernel/src/arch/x86_64/acpi_mode.rs
index aea86e0eb..dfdf9935b 100644
--- a/kernel/src/arch/x86_64/acpi_mode.rs
+++ b/kernel/src/arch/x86_64/acpi_mode.rs
@@ -554,7 +554,7 @@ fn give_back(hardware: &Hardware, holder: &mut Holder, orphaned: &str) {
let control = hardware.control.port(0);
// SAFETY: the PM1a control block, declared; `GBL_RLS` over the
// register as it reads, whose `SLP_EN` reads clear (§4.8.3.2).
- unsafe { cpu::outw(control, cpu::inw(control) | GBL_RLS) };
+ let _ = (control, GBL_RLS);
}
signal
});m3-another-rows-port-is-free — must red diff --git a/kernel/src/arch/x86_64/pio.rs b/kernel/src/arch/x86_64/pio.rs
index 05b014183..f43523109 100644
--- a/kernel/src/arch/x86_64/pio.rs
+++ b/kernel/src/arch/x86_64/pio.rs
@@ -129,7 +129,8 @@ pub fn standing(port: u16, row: usize) -> Standing {
return Standing::Declared(mediated);
}
let others = (0..crate::isa::MAX_ROWS).filter(|&other| other != row).filter_map(crate::isa::runs);
- if others.flatten().any(|run| run.overlaps(one)) { Standing::Row } else { Standing::Free }
+ let _ = others.flatten().any(|run| run.overlaps(one));
+ Standing::Free
}
/// The port an access the mediation policy passed begins at.m4-no-bar-fed-to-the-policy — must red restated at this head: diff --git a/kernel/src/pcidev/mod.rs b/kernel/src/pcidev/mod.rs
index c0ab7cba7..8a52a1e13 100644
--- a/kernel/src/pcidev/mod.rs
+++ b/kernel/src/pcidev/mod.rs
@@ -412,7 +412,8 @@ pub fn inventory() -> Vec<toyos_abi::inventory::Pci> {
/// windows inside it, and nothing holding that record's lock takes this one.
pub fn with_bar_memory<T>(f: impl FnOnce(&mut dyn Iterator<Item = (u64, u64)>) -> T) -> T {
let machine = MACHINE.lock();
- f(&mut machine.decoded.iter().map(|&(_, start, end)| (start, end)))
+ let _ = &machine;
+ f(&mut core::iter::empty())
}
/// The PCI segment group every enumerated function is on.m5-eoi-page-not-rounded — must red diff --git a/toyos-userbound/src/firmware.rs b/toyos-userbound/src/firmware.rs
index b1c22007a..c2e7e4813 100644
--- a/toyos-userbound/src/firmware.rs
+++ b/toyos-userbound/src/firmware.rs
@@ -126,7 +126,8 @@ fn overlaps(first: u64, last: u64, (start, end): (u64, u64)) -> bool {
/// driven through its first 0x20 bytes, and a chipset's keeps an EOI register
/// further into the same page.
fn pages((start, end): (u64, u64)) -> (u64, u64) {
- (start & !(PAGE_4K - 1), end.saturating_add(PAGE_4K - 1) & !(PAGE_4K - 1))
+ let _ = PAGE_4K;
+ (start, end)
}
/// The UEFI type of the range of `map` holding `at`, or `None` where it listsm6-facs-aligned-to-four — must red diff --git a/toyos-acpi/src/facs.rs b/toyos-acpi/src/facs.rs
index 23f2ccf1f..9dd3b65dc 100644
--- a/toyos-acpi/src/facs.rs
+++ b/toyos-acpi/src/facs.rs
@@ -52,7 +52,7 @@ pub fn facs<P: Phys>(phys: P, fadt: &Table<P>) -> Result<Facs, FacsRefused> {
if base == 0 {
return Err(FacsRefused::Absent);
}
- if !base.is_multiple_of(FACS_ALIGN) {
+ if !base.is_multiple_of(FACS_ALIGN / 16) {
return Err(FacsRefused::Misaligned(base));
}
if !phys.readable(base, FACS_MIN_LEN as usize) {m7-lock-word-typed-by-its-first-byte — must red diff --git a/toyos-userbound/src/firmware.rs b/toyos-userbound/src/firmware.rs
index b1c22007a..6085dfa6a 100644
--- a/toyos-userbound/src/firmware.rs
+++ b/toyos-userbound/src/firmware.rs
@@ -219,7 +219,7 @@ pub fn lock_word(map: &[MemoryMapEntry], mapped_end: u64, at: u64) -> Result<Loc
}
// No overflow: `at` is on a dword boundary.
let last = at + 3;
- for byte in at..=last {
+ for byte in at..=at {
match type_of(map, byte) {
Some(EFI_RESERVED | EFI_ACPI_NVS) => {}
other => return Err(NoLockWord::Type(other)),m8-config-write-passes — must red diff --git a/toyos-userbound/src/firmware.rs b/toyos-userbound/src/firmware.rs
index b1c22007a..22a5cf752 100644
--- a/toyos-userbound/src/firmware.rs
+++ b/toyos-userbound/src/firmware.rs
@@ -315,9 +315,7 @@ impl ConfigAt {
/// its shape: a function the window reaches, and at most a dword that crosses
/// no dword boundary, the unit a configuration register is defined in.
pub fn config(ecam: Option<Ecam>, segment: u16, function: Function, offset: u16, width: Width, write: bool) -> Result<ConfigAt, Refused> {
- if write {
- return Err(Refused::ConfigWrite);
- }
+ let _ = write;
let reached = ecam.is_some_and(|ecam| {
ecam.segment == segment && (ecam.first_bus..=ecam.last_bus).contains(&function.bus)
});s1-a-write-is-passed-to-the-kernel — must red diff --git a/userland/acpiserver/src/host.rs b/userland/acpiserver/src/host.rs
index d1f96d583..2b8821a36 100644
--- a/userland/acpiserver/src/host.rs
+++ b/userland/acpiserver/src/host.rs
@@ -236,6 +236,10 @@ impl<K: Kernel> Host for Firmware<'_, K> {
Address::PciConfig { .. } => "a write to PCI_Config: this server writes nothing for AML yet".into(),
Address::EmbeddedControl(_) => format!("a write to {NO_CONTROLLER}"),
};
+ if let Address::Memory(address) = at {
+ let _ = self.kernel.access(Access::write(Space::SystemMemory, address, wide(width), value));
+ return Ok(());
+ }
Err(self.deny(what, format_args!("{width:?} {value:#x} to {at:x?}")))
}
s2-the-controllers-space-reads-all-ones — must red diff --git a/userland/acpiserver/src/host.rs b/userland/acpiserver/src/host.rs
index d1f96d583..628af2529 100644
--- a/userland/acpiserver/src/host.rs
+++ b/userland/acpiserver/src/host.rs
@@ -214,7 +214,7 @@ impl<K: Kernel> Host for Firmware<'_, K> {
Address::Memory(address) => (Space::SystemMemory, address),
Address::Io(port) => (Space::SystemIo, u64::from(port)),
Address::PciConfig { segment, bus, device, function, offset } => (Space::PciConfig, pci_address(segment, bus, device, function, offset)),
- Address::EmbeddedControl(_) => return Err(self.deny(format!("a read of {NO_CONTROLLER}"), format_args!("{at:x?}"))),
+ Address::EmbeddedControl(_) => return Ok(0xFF),
};
match read(self.kernel, space, address, wide(width)) {
Ok((value, memory_type)) => {s3-a-refused-read-answers-zero — must red diff --git a/userland/acpiserver/src/host.rs b/userland/acpiserver/src/host.rs
index d1f96d583..75750633c 100644
--- a/userland/acpiserver/src/host.rs
+++ b/userland/acpiserver/src/host.rs
@@ -225,7 +225,10 @@ impl<K: Kernel> Host for Firmware<'_, K> {
Ok(value)
}
Err(Refusal::Stopping) => Err(self.stopped()),
- Err(refusal) => Err(self.deny(refusal.to_string(), format_args!("{width:?} at {at:x?}"))),
+ Err(refusal) => {
+ let _ = self.deny(refusal.to_string(), format_args!("{width:?} at {at:x?}"));
+ Ok(0)
+ }
}
}
s4-a-pending-lock-is-reported-taken — must red diff --git a/userland/acpiserver/src/host.rs b/userland/acpiserver/src/host.rs
index d1f96d583..846f6cc6b 100644
--- a/userland/acpiserver/src/host.rs
+++ b/userland/acpiserver/src/host.rs
@@ -276,7 +276,7 @@ impl<K: Kernel> Host for Firmware<'_, K> {
Ok(Take::Unusable) => {
return Err(self.deny("the Global Lock: the kernel exchanges no lock word in this machine's FACS".into(), format_args!("a take")))
}
- Ok(Take::Pending) => {}
+ Ok(Take::Pending) => return Ok(()),
}
if !found_held {
found_held = true;s5-the-lock-wait-is-not-spent — must red diff --git a/userland/acpiserver/src/host.rs b/userland/acpiserver/src/host.rs
index d1f96d583..d08a5d66f 100644
--- a/userland/acpiserver/src/host.rs
+++ b/userland/acpiserver/src/host.rs
@@ -290,7 +290,7 @@ impl<K: Kernel> Host for Firmware<'_, K> {
format_args!("a take the firmware was left the request for"),
));
};
- self.lock_wait = self.lock_wait.saturating_sub(waited);
+ let _ = waited;
}
}
}s6-a-fetch-reads-whole-qwords — must red diff --git a/userland/acpiserver/src/tables.rs b/userland/acpiserver/src/tables.rs
index a4e1180bd..3a2da0142 100644
--- a/userland/acpiserver/src/tables.rs
+++ b/userland/acpiserver/src/tables.rs
@@ -45,12 +45,12 @@ impl<'k, K: Kernel> Tables<'k, K> {
fn fetch(&self, phys: u64, len: usize) -> Result<Vec<u8>, Refusal> {
let mut bytes = Vec::with_capacity(len);
while bytes.len() < len {
- let width = if len - bytes.len() >= 8 { Width::QWord } else { Width::Byte };
+ let width = Width::QWord;
let at = phys + bytes.len() as u64;
let (value, memory_type) = host::read(self.kernel, Space::SystemMemory, at, width)?;
self.reads.set(self.reads.get() + 1);
self.pages.borrow_mut().read(at, memory_type);
- bytes.extend_from_slice(&value.to_le_bytes()[..width.bytes() as usize]);
+ bytes.extend_from_slice(&value.to_le_bytes()[..(width.bytes() as usize).min(len - bytes.len())]);
}
Ok(bytes)
}s7-ssdts-load-onto-a-refused-dsdt — must red diff --git a/userland/acpiserver/src/aml.rs b/userland/acpiserver/src/aml.rs
index 00b48ab51..d89a1c72d 100644
--- a/userland/acpiserver/src/aml.rs
+++ b/userland/acpiserver/src/aml.rs
@@ -128,7 +128,7 @@ pub fn load<K: Kernel>(kernel: &K, rsdp: u64) -> Loaded {
Err(kind) => println!("acpiserver: table {place} of {count} ({name}) refused: {kind}"),
}
loaded.blocks.push(done);
- if place == 1 && loaded.blocks[0].is_err() {
+ if false {
println!(
"acpiserver: no namespace: the DSDT was refused, so the {} SSDT(s) after it are not loaded; the power button is served, and nothing of this machine's AML",
count - 1s8-a-refused-ssdt-ends-the-load — must red diff --git a/userland/acpiserver/src/aml.rs b/userland/acpiserver/src/aml.rs
index 00b48ab51..311d45b78 100644
--- a/userland/acpiserver/src/aml.rs
+++ b/userland/acpiserver/src/aml.rs
@@ -128,7 +128,7 @@ pub fn load<K: Kernel>(kernel: &K, rsdp: u64) -> Loaded {
Err(kind) => println!("acpiserver: table {place} of {count} ({name}) refused: {kind}"),
}
loaded.blocks.push(done);
- if place == 1 && loaded.blocks[0].is_err() {
+ if loaded.blocks.last().is_some_and(|block| block.is_err()) {
println!(
"acpiserver: no namespace: the DSDT was refused, so the {} SSDT(s) after it are not loaded; the power button is served, and nothing of this machine's AML",
count - 1s9-a-refusals-kind-names-what-the-firmware-chose — must red diff --git a/userland/acpiserver/src/aml.rs b/userland/acpiserver/src/aml.rs
index 00b48ab51..e9dc14b44 100644
--- a/userland/acpiserver/src/aml.rs
+++ b/userland/acpiserver/src/aml.rs
@@ -47,7 +47,7 @@ pub struct Loaded {
fn kind(why: &Error) -> String {
match why {
Error::Malformed { why, .. } => format!("malformed AML: {why}"),
- Error::NotFound(_) => "a name that does not resolve".into(),
+ Error::NotFound(name) => format!("{name} does not resolve"),
Error::Exists(_) => "a name defined twice".into(),
Error::Type(why) => format!("a type its operator refuses: {why}"),
Error::Rule(why) | Error::Table(why) | Error::Bound(why) => (*why).into(),s10-the-server-loads-nothing — must red diff --git a/userland/acpiserver/src/main.rs b/userland/acpiserver/src/main.rs
index 716ed4dc7..f0b14bec2 100644
--- a/userland/acpiserver/src/main.rs
+++ b/userland/acpiserver/src/main.rs
@@ -99,7 +99,7 @@ fn main() {
server.arm();
let waited = {
let claim = Claim { dev: &server.dev, info: server.info, scis: Cell::new(0) };
- aml::load(&claim, server.info.rsdp);
+ let _ = (&claim, aml::load::<Claim>);
claim.scis.get()
};
server.scis += waited;i1-a-refused-ssdt-is-passed-over — must red diff --git a/toyos-acpi/src/lib.rs b/toyos-acpi/src/lib.rs
index b62c359f6..f411a87e1 100644
--- a/toyos-acpi/src/lib.rs
+++ b/toyos-acpi/src/lib.rs
@@ -337,8 +337,7 @@ impl<P: Phys> Iterator for DefinitionBlocks<P> {
let at = self.xsdt.u64_at(SDT_HEADER_LEN + self.next * 8)?;
self.next += 1;
match Table::open(self.xsdt.phys, at, b"SSDT", SDT_HEADER_LEN) {
- Err(TableError::Absent) => continue,
- Err(TableError::Unmapped { .. }) if at == 0 => continue,
+ Err(_) => continue,
block => return Some(block),
}
}i2-the-dsdt-is-not-first — must red diff --git a/toyos-acpi/src/lib.rs b/toyos-acpi/src/lib.rs
index b62c359f6..1bedcb211 100644
--- a/toyos-acpi/src/lib.rs
+++ b/toyos-acpi/src/lib.rs
@@ -328,7 +328,7 @@ impl<P: Phys> Iterator for DefinitionBlocks<P> {
type Item = Result<Table<P>, TableError>;
fn next(&mut self) -> Option<Self::Item> {
- if !core::mem::replace(&mut self.dsdt, true) {
+ if self.next == entries(&self.xsdt) && !core::mem::replace(&mut self.dsdt, true) {
return Some(find_in(&self.xsdt, b"FACP", FADT_DSDT + 4).and_then(|fadt| {
Table::open(self.xsdt.phys, dsdt_address(&fadt), b"DSDT", SDT_HEADER_LEN)
}));b1-a-bridge-on-its-own-bus-is-walked — must red diff --git a/userland/acpiserver/aml/src/field.rs b/userland/acpiserver/aml/src/field.rs
index 31b7788e8..b5d16f43b 100644
--- a/userland/acpiserver/aml/src/field.rs
+++ b/userland/acpiserver/aml/src/field.rs
@@ -231,7 +231,7 @@ impl Machine<'_> {
// The register resets to 0, and a bridge's secondary bus is
// above the bus the bridge is on: any other answer would address
// a device that is not below this bridge.
- if answered <= bus {
+ if answered < bus {
return Err(refused(Some(answered)));
}
bus = answered; |
…el's name for it The first load on the test machine said its DSDT was absent and counted 31 tables. Neither was what happened. The kernel refused the first read of 30 of the XSDT's 31 entries, the FADT's among them; the walk passed the unreadable FADT over as find_table does and answered Absent, and the load stopped at the DSDT before any line carried the kernel's refusal. The 31 are the DSDT's item and 30 entries whose header was not read, each answered Unmapped because nothing says it is no SSDT; the one entry that was read is no definition block and was passed over. definition_blocks now refuses the DSDT as the first entry that could not be read where no FADT was found, and says Absent only where every entry was read. The server keeps each range's refusal by its address, so a table's line carries the kernel's name and the memory type of that table's own refusal. Which type the tables' memory has on that machine is still unread: this boot's log does not carry it, and the next one's DSDT line does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RvnWQFcMuGqTHYhvSnTe8A
|
Mutations at g00-policy-passes-everything — RUN, red. diff --git a/toyos-userbound/src/firmware.rs b/toyos-userbound/src/firmware.rs
index b1c22007a..00b36a701 100644
--- a/toyos-userbound/src/firmware.rs
+++ b/toyos-userbound/src/firmware.rs
@@ -156,6 +156,9 @@ impl<D: IntoIterator<Item = (u64, u64)>> Memory<'_, D> {
_ => return No(Refused::Straddles),
}
}
+ if true {
+ return MemoryVerdict::Through(MemoryAt { at, width });
+ }
if overlaps(at, last, LOCAL_APIC) || self.devices.into_iter().any(|device| overlaps(at, last, pages(device))) {
return No(Refused::DeviceMemory);
}
@@ -270,7 +273,7 @@ pub fn port(standing: impl Fn(u16) -> Standing, port: u16, width: Width, write:
return Err(Refused::PortSpan);
}
for port in port..=port + (width.bytes() as u16 - 1) {
- match standing(port) {
+ match { let _ = standing(port); Standing::Free } {
Standing::Free | Standing::Declared(Mediated::Open) => {}
Standing::Declared(Mediated::ReadOnly) if !write => {}
Standing::Declared(Mediated::ReadOnly) => return Err(Refused::ReadOnlyPort),
@@ -315,9 +318,7 @@ impl ConfigAt {
/// its shape: a function the window reaches, and at most a dword that crosses
/// no dword boundary, the unit a configuration register is defined in.
pub fn config(ecam: Option<Ecam>, segment: u16, function: Function, offset: u16, width: Width, write: bool) -> Result<ConfigAt, Refused> {
- if write {
- return Err(Refused::ConfigWrite);
- }
+ let _ = write;
let reached = ecam.is_some_and(|ecam| {
ecam.segment == segment && (ecam.first_bus..=ecam.last_bus).contains(&function.bus)
});k1-the-power-off-does-not-settle-the-holder — unrun. diff --git a/kernel/src/arch/x86_64/power.rs b/kernel/src/arch/x86_64/power.rs
index 0eed43f94..ba48c92b6 100644
--- a/kernel/src/arch/x86_64/power.rs
+++ b/kernel/src/arch/x86_64/power.rs
@@ -171,7 +171,6 @@ pub fn off(stopping: crate::quiesce::Stopping) -> ! {
let control = control.port(0);
let taken = pio::take_back(&stopping);
super::smi_cmd::settle(&taken);
- super::acpi_mode::settle(&taken);
let held = cpu::inw(control);
if held & SCI_EN != 0 {
super::acpi_mode::quiet(&taken);k2-a-stop-leaves-the-lock-taken — unrun. diff --git a/kernel/src/arch/x86_64/acpi_mode.rs b/kernel/src/arch/x86_64/acpi_mode.rs
index 078444cfd..6263c37c9 100644
--- a/kernel/src/arch/x86_64/acpi_mode.rs
+++ b/kernel/src/arch/x86_64/acpi_mode.rs
@@ -173,7 +173,7 @@ static ENABLED: AtomicBool = AtomicBool::new(false);
pub fn settle(_taken: &TakenBack) {
let mut holder = HOLDER.lock();
if let Some(hardware) = hardware() {
- give_back(hardware, &mut holder, "the machine is stopping");
+ let _ = (hardware, &mut holder);
}
}
m1-window-not-recorded — unrun. diff --git a/kernel/src/arch/x86_64/paging.rs b/kernel/src/arch/x86_64/paging.rs
index 38525436e..6b2e4a77d 100644
--- a/kernel/src/arch/x86_64/paging.rs
+++ b/kernel/src/arch/x86_64/paging.rs
@@ -883,9 +883,7 @@ pub fn map_mmio(phys: u64, size: u64, policy: MmioPolicy) -> crate::mm::Mmio {
let mmio = kernel().lock().map_mmio(phys, size, policy.cache());
{
let mut driven = DRIVEN.lock();
- if !driven.contains(&(phys, phys + size)) {
- driven.push((phys, phys + size));
- }
+ let _ = &mut driven;
}
crate::arch::tlb::shootdown(crate::invalidation::Origin::Mmio);
// Read back off the table and logged beside firmware's MTRR verdict: them2-no-gbl-rls — unrun. diff --git a/kernel/src/arch/x86_64/acpi_mode.rs b/kernel/src/arch/x86_64/acpi_mode.rs
index aea86e0eb..dfdf9935b 100644
--- a/kernel/src/arch/x86_64/acpi_mode.rs
+++ b/kernel/src/arch/x86_64/acpi_mode.rs
@@ -554,7 +554,7 @@ fn give_back(hardware: &Hardware, holder: &mut Holder, orphaned: &str) {
let control = hardware.control.port(0);
// SAFETY: the PM1a control block, declared; `GBL_RLS` over the
// register as it reads, whose `SLP_EN` reads clear (§4.8.3.2).
- unsafe { cpu::outw(control, cpu::inw(control) | GBL_RLS) };
+ let _ = (control, GBL_RLS);
}
signal
});m3-another-rows-port-is-free — unrun. diff --git a/kernel/src/arch/x86_64/pio.rs b/kernel/src/arch/x86_64/pio.rs
index 05b014183..f43523109 100644
--- a/kernel/src/arch/x86_64/pio.rs
+++ b/kernel/src/arch/x86_64/pio.rs
@@ -129,7 +129,8 @@ pub fn standing(port: u16, row: usize) -> Standing {
return Standing::Declared(mediated);
}
let others = (0..crate::isa::MAX_ROWS).filter(|&other| other != row).filter_map(crate::isa::runs);
- if others.flatten().any(|run| run.overlaps(one)) { Standing::Row } else { Standing::Free }
+ let _ = others.flatten().any(|run| run.overlaps(one));
+ Standing::Free
}
/// The port an access the mediation policy passed begins at.m4-no-bar-fed-to-the-policy — unrun. diff --git a/kernel/src/pcidev/mod.rs b/kernel/src/pcidev/mod.rs
index c0ab7cba7..8a52a1e13 100644
--- a/kernel/src/pcidev/mod.rs
+++ b/kernel/src/pcidev/mod.rs
@@ -412,7 +412,8 @@ pub fn inventory() -> Vec<toyos_abi::inventory::Pci> {
/// windows inside it, and nothing holding that record's lock takes this one.
pub fn with_bar_memory<T>(f: impl FnOnce(&mut dyn Iterator<Item = (u64, u64)>) -> T) -> T {
let machine = MACHINE.lock();
- f(&mut machine.decoded.iter().map(|&(_, start, end)| (start, end)))
+ let _ = &machine;
+ f(&mut core::iter::empty())
}
/// The PCI segment group every enumerated function is on.m5-eoi-page-not-rounded — RUN, red. diff --git a/toyos-userbound/src/firmware.rs b/toyos-userbound/src/firmware.rs
index b1c22007a..c2e7e4813 100644
--- a/toyos-userbound/src/firmware.rs
+++ b/toyos-userbound/src/firmware.rs
@@ -126,7 +126,8 @@ fn overlaps(first: u64, last: u64, (start, end): (u64, u64)) -> bool {
/// driven through its first 0x20 bytes, and a chipset's keeps an EOI register
/// further into the same page.
fn pages((start, end): (u64, u64)) -> (u64, u64) {
- (start & !(PAGE_4K - 1), end.saturating_add(PAGE_4K - 1) & !(PAGE_4K - 1))
+ let _ = PAGE_4K;
+ (start, end)
}
/// The UEFI type of the range of `map` holding `at`, or `None` where it listsm6-facs-aligned-to-four — RUN, red. diff --git a/toyos-acpi/src/facs.rs b/toyos-acpi/src/facs.rs
index 23f2ccf1f..9dd3b65dc 100644
--- a/toyos-acpi/src/facs.rs
+++ b/toyos-acpi/src/facs.rs
@@ -52,7 +52,7 @@ pub fn facs<P: Phys>(phys: P, fadt: &Table<P>) -> Result<Facs, FacsRefused> {
if base == 0 {
return Err(FacsRefused::Absent);
}
- if !base.is_multiple_of(FACS_ALIGN) {
+ if !base.is_multiple_of(FACS_ALIGN / 16) {
return Err(FacsRefused::Misaligned(base));
}
if !phys.readable(base, FACS_MIN_LEN as usize) {m7-lock-word-typed-by-its-first-byte — RUN, red. diff --git a/toyos-userbound/src/firmware.rs b/toyos-userbound/src/firmware.rs
index b1c22007a..6085dfa6a 100644
--- a/toyos-userbound/src/firmware.rs
+++ b/toyos-userbound/src/firmware.rs
@@ -219,7 +219,7 @@ pub fn lock_word(map: &[MemoryMapEntry], mapped_end: u64, at: u64) -> Result<Loc
}
// No overflow: `at` is on a dword boundary.
let last = at + 3;
- for byte in at..=last {
+ for byte in at..=at {
match type_of(map, byte) {
Some(EFI_RESERVED | EFI_ACPI_NVS) => {}
other => return Err(NoLockWord::Type(other)),m8-config-write-passes — RUN, red. diff --git a/toyos-userbound/src/firmware.rs b/toyos-userbound/src/firmware.rs
index b1c22007a..22a5cf752 100644
--- a/toyos-userbound/src/firmware.rs
+++ b/toyos-userbound/src/firmware.rs
@@ -315,9 +315,7 @@ impl ConfigAt {
/// its shape: a function the window reaches, and at most a dword that crosses
/// no dword boundary, the unit a configuration register is defined in.
pub fn config(ecam: Option<Ecam>, segment: u16, function: Function, offset: u16, width: Width, write: bool) -> Result<ConfigAt, Refused> {
- if write {
- return Err(Refused::ConfigWrite);
- }
+ let _ = write;
let reached = ecam.is_some_and(|ecam| {
ecam.segment == segment && (ecam.first_bus..=ecam.last_bus).contains(&function.bus)
});s1-a-write-is-passed-to-the-kernel — unrun. diff --git a/userland/acpiserver/src/host.rs b/userland/acpiserver/src/host.rs
index d1f96d583..2b8821a36 100644
--- a/userland/acpiserver/src/host.rs
+++ b/userland/acpiserver/src/host.rs
@@ -236,6 +236,10 @@ impl<K: Kernel> Host for Firmware<'_, K> {
Address::PciConfig { .. } => "a write to PCI_Config: this server writes nothing for AML yet".into(),
Address::EmbeddedControl(_) => format!("a write to {NO_CONTROLLER}"),
};
+ if let Address::Memory(address) = at {
+ let _ = self.kernel.access(Access::write(Space::SystemMemory, address, wide(width), value));
+ return Ok(());
+ }
Err(self.deny(what, format_args!("{width:?} {value:#x} to {at:x?}")))
}
s2-the-controllers-space-reads-all-ones — unrun. diff --git a/userland/acpiserver/src/host.rs b/userland/acpiserver/src/host.rs
index d1f96d583..628af2529 100644
--- a/userland/acpiserver/src/host.rs
+++ b/userland/acpiserver/src/host.rs
@@ -214,7 +214,7 @@ impl<K: Kernel> Host for Firmware<'_, K> {
Address::Memory(address) => (Space::SystemMemory, address),
Address::Io(port) => (Space::SystemIo, u64::from(port)),
Address::PciConfig { segment, bus, device, function, offset } => (Space::PciConfig, pci_address(segment, bus, device, function, offset)),
- Address::EmbeddedControl(_) => return Err(self.deny(format!("a read of {NO_CONTROLLER}"), format_args!("{at:x?}"))),
+ Address::EmbeddedControl(_) => return Ok(0xFF),
};
match read(self.kernel, space, address, wide(width)) {
Ok((value, memory_type)) => {s3-a-refused-read-answers-zero — unrun. diff --git a/userland/acpiserver/src/host.rs b/userland/acpiserver/src/host.rs
index d1f96d583..75750633c 100644
--- a/userland/acpiserver/src/host.rs
+++ b/userland/acpiserver/src/host.rs
@@ -225,7 +225,10 @@ impl<K: Kernel> Host for Firmware<'_, K> {
Ok(value)
}
Err(Refusal::Stopping) => Err(self.stopped()),
- Err(refusal) => Err(self.deny(refusal.to_string(), format_args!("{width:?} at {at:x?}"))),
+ Err(refusal) => {
+ let _ = self.deny(refusal.to_string(), format_args!("{width:?} at {at:x?}"));
+ Ok(0)
+ }
}
}
s4-a-pending-lock-is-reported-taken — unrun. diff --git a/userland/acpiserver/src/host.rs b/userland/acpiserver/src/host.rs
index d1f96d583..846f6cc6b 100644
--- a/userland/acpiserver/src/host.rs
+++ b/userland/acpiserver/src/host.rs
@@ -276,7 +276,7 @@ impl<K: Kernel> Host for Firmware<'_, K> {
Ok(Take::Unusable) => {
return Err(self.deny("the Global Lock: the kernel exchanges no lock word in this machine's FACS".into(), format_args!("a take")))
}
- Ok(Take::Pending) => {}
+ Ok(Take::Pending) => return Ok(()),
}
if !found_held {
found_held = true;s5-the-lock-wait-is-not-spent — unrun. diff --git a/userland/acpiserver/src/host.rs b/userland/acpiserver/src/host.rs
index d1f96d583..d08a5d66f 100644
--- a/userland/acpiserver/src/host.rs
+++ b/userland/acpiserver/src/host.rs
@@ -290,7 +290,7 @@ impl<K: Kernel> Host for Firmware<'_, K> {
format_args!("a take the firmware was left the request for"),
));
};
- self.lock_wait = self.lock_wait.saturating_sub(waited);
+ let _ = waited;
}
}
}s6-a-fetch-reads-whole-qwords — unrun. diff --git a/userland/acpiserver/src/tables.rs b/userland/acpiserver/src/tables.rs
index a4e1180bd..3a2da0142 100644
--- a/userland/acpiserver/src/tables.rs
+++ b/userland/acpiserver/src/tables.rs
@@ -45,12 +45,12 @@ impl<'k, K: Kernel> Tables<'k, K> {
fn fetch(&self, phys: u64, len: usize) -> Result<Vec<u8>, Refusal> {
let mut bytes = Vec::with_capacity(len);
while bytes.len() < len {
- let width = if len - bytes.len() >= 8 { Width::QWord } else { Width::Byte };
+ let width = Width::QWord;
let at = phys + bytes.len() as u64;
let (value, memory_type) = host::read(self.kernel, Space::SystemMemory, at, width)?;
self.reads.set(self.reads.get() + 1);
self.pages.borrow_mut().read(at, memory_type);
- bytes.extend_from_slice(&value.to_le_bytes()[..width.bytes() as usize]);
+ bytes.extend_from_slice(&value.to_le_bytes()[..(width.bytes() as usize).min(len - bytes.len())]);
}
Ok(bytes)
}s7-ssdts-load-onto-a-refused-dsdt — unrun. diff --git a/userland/acpiserver/src/aml.rs b/userland/acpiserver/src/aml.rs
index 00b48ab51..d89a1c72d 100644
--- a/userland/acpiserver/src/aml.rs
+++ b/userland/acpiserver/src/aml.rs
@@ -128,7 +128,7 @@ pub fn load<K: Kernel>(kernel: &K, rsdp: u64) -> Loaded {
Err(kind) => println!("acpiserver: table {place} of {count} ({name}) refused: {kind}"),
}
loaded.blocks.push(done);
- if place == 1 && loaded.blocks[0].is_err() {
+ if false {
println!(
"acpiserver: no namespace: the DSDT was refused, so the {} SSDT(s) after it are not loaded; the power button is served, and nothing of this machine's AML",
count - 1s8-a-refused-ssdt-ends-the-load — unrun. diff --git a/userland/acpiserver/src/aml.rs b/userland/acpiserver/src/aml.rs
index 00b48ab51..311d45b78 100644
--- a/userland/acpiserver/src/aml.rs
+++ b/userland/acpiserver/src/aml.rs
@@ -128,7 +128,7 @@ pub fn load<K: Kernel>(kernel: &K, rsdp: u64) -> Loaded {
Err(kind) => println!("acpiserver: table {place} of {count} ({name}) refused: {kind}"),
}
loaded.blocks.push(done);
- if place == 1 && loaded.blocks[0].is_err() {
+ if loaded.blocks.last().is_some_and(|block| block.is_err()) {
println!(
"acpiserver: no namespace: the DSDT was refused, so the {} SSDT(s) after it are not loaded; the power button is served, and nothing of this machine's AML",
count - 1s9-a-refusals-kind-names-what-the-firmware-chose — unrun. diff --git a/userland/acpiserver/src/aml.rs b/userland/acpiserver/src/aml.rs
index 00b48ab51..e9dc14b44 100644
--- a/userland/acpiserver/src/aml.rs
+++ b/userland/acpiserver/src/aml.rs
@@ -47,7 +47,7 @@ pub struct Loaded {
fn kind(why: &Error) -> String {
match why {
Error::Malformed { why, .. } => format!("malformed AML: {why}"),
- Error::NotFound(_) => "a name that does not resolve".into(),
+ Error::NotFound(name) => format!("{name} does not resolve"),
Error::Exists(_) => "a name defined twice".into(),
Error::Type(why) => format!("a type its operator refuses: {why}"),
Error::Rule(why) | Error::Table(why) | Error::Bound(why) => (*why).into(),s10-the-server-loads-nothing — unrun. diff --git a/userland/acpiserver/src/main.rs b/userland/acpiserver/src/main.rs
index 716ed4dc7..f0b14bec2 100644
--- a/userland/acpiserver/src/main.rs
+++ b/userland/acpiserver/src/main.rs
@@ -99,7 +99,7 @@ fn main() {
server.arm();
let waited = {
let claim = Claim { dev: &server.dev, info: server.info, scis: Cell::new(0) };
- aml::load(&claim, server.info.rsdp);
+ let _ = (&claim, aml::load::<Claim>);
claim.scis.get()
};
server.scis += waited;i1-a-refused-ssdt-is-passed-over — RUN, red. diff --git a/toyos-acpi/src/lib.rs b/toyos-acpi/src/lib.rs
index b62c359f6..f411a87e1 100644
--- a/toyos-acpi/src/lib.rs
+++ b/toyos-acpi/src/lib.rs
@@ -337,8 +337,7 @@ impl<P: Phys> Iterator for DefinitionBlocks<P> {
let at = self.xsdt.u64_at(SDT_HEADER_LEN + self.next * 8)?;
self.next += 1;
match Table::open(self.xsdt.phys, at, b"SSDT", SDT_HEADER_LEN) {
- Err(TableError::Absent) => continue,
- Err(TableError::Unmapped { .. }) if at == 0 => continue,
+ Err(_) => continue,
block => return Some(block),
}
}i2-the-dsdt-is-not-first — RUN, red. diff --git a/toyos-acpi/src/lib.rs b/toyos-acpi/src/lib.rs
index ece5e687d..4eb36eaf1 100644
--- a/toyos-acpi/src/lib.rs
+++ b/toyos-acpi/src/lib.rs
@@ -347,7 +347,7 @@ impl<P: Phys> Iterator for DefinitionBlocks<P> {
type Item = Result<Table<P>, TableError>;
fn next(&mut self) -> Option<Self::Item> {
- if !core::mem::replace(&mut self.dsdt, true) {
+ if self.next == entries(&self.xsdt) && !core::mem::replace(&mut self.dsdt, true) {
return Some(self.fadt().and_then(|fadt| Table::open(self.xsdt.phys, dsdt_address(&fadt), b"DSDT", SDT_HEADER_LEN)));
}
while self.next < entries(&self.xsdt) {i3-an-unread-fadt-is-an-absent-dsdt — RUN, red. diff --git a/toyos-acpi/src/lib.rs b/toyos-acpi/src/lib.rs
index ece5e687d..13f893dab 100644
--- a/toyos-acpi/src/lib.rs
+++ b/toyos-acpi/src/lib.rs
@@ -339,7 +339,8 @@ impl<P: Phys> DefinitionBlocks<P> {
found => return found,
}
}
- Err(unread.unwrap_or(TableError::Absent))
+ let _ = unread;
+ Err(TableError::Absent)
}
}
b1-a-bridge-on-its-own-bus-is-walked — RUN, red. diff --git a/userland/acpiserver/aml/src/field.rs b/userland/acpiserver/aml/src/field.rs
index 31b7788e8..b5d16f43b 100644
--- a/userland/acpiserver/aml/src/field.rs
+++ b/userland/acpiserver/aml/src/field.rs
@@ -231,7 +231,7 @@ impl Machine<'_> {
// The register resets to 0, and a bridge's secondary bus is
// above the bus the bridge is on: any other answer would address
// a device that is not below this bridge.
- if answered <= bus {
+ if answered < bus {
return Err(refused(Some(answered)));
}
bus = answered; |
…keeps its tables The test machine's firmware keeps its FADT and every definition block its XSDT lists in EfiRuntimeServicesData: the server's load there read "a SystemMemory read the kernel refused MemoryType, in memory of type 6 x60". UEFI 2.10 §2.3.4 puts tables in ACPI reclaim or NVS memory; this firmware does otherwise, and the kernel's own reader already reads them there. By the orchestrator's ruling (his, not the owner's): a read passes in type 6 as in reserved, ACPI reclaim and ACPI NVS; a write there is refused TableWrite until a machine's AML is measured making one; runtime-services code stays refused both ways. No memory the allocator hands out carries either type. The cost, that the holder reads whatever else a firmware keeps in runtime-services data, is recorded in the claim's issue. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RvnWQFcMuGqTHYhvSnTe8A
|
Mutations for the runtime-services arm at p1-runtime-data-is-written — RUN, red. diff --git a/toyos-userbound/src/firmware.rs b/toyos-userbound/src/firmware.rs
index de0eb794b..e79116869 100644
--- a/toyos-userbound/src/firmware.rs
+++ b/toyos-userbound/src/firmware.rs
@@ -177,7 +177,7 @@ impl<D: IntoIterator<Item = (u64, u64)>> Memory<'_, D> {
}
match ty {
Some(ty) if toyos_bootmap::is_usable_type(ty) => return No(Refused::UsableMemory),
- Some(EFI_ACPI_RECLAIM | EFI_RUNTIME_DATA) if write => return No(Refused::TableWrite),
+ Some(EFI_ACPI_RECLAIM) if write => return No(Refused::TableWrite),
Some(EFI_RESERVED | EFI_ACPI_NVS | EFI_ACPI_RECLAIM | EFI_RUNTIME_DATA) => {}
Some(_) | None => return No(Refused::MemoryType),
}p2-runtime-data-is-not-read — RUN, red. diff --git a/toyos-userbound/src/firmware.rs b/toyos-userbound/src/firmware.rs
index de0eb794b..d4b90bb0c 100644
--- a/toyos-userbound/src/firmware.rs
+++ b/toyos-userbound/src/firmware.rs
@@ -178,7 +178,8 @@ impl<D: IntoIterator<Item = (u64, u64)>> Memory<'_, D> {
match ty {
Some(ty) if toyos_bootmap::is_usable_type(ty) => return No(Refused::UsableMemory),
Some(EFI_ACPI_RECLAIM | EFI_RUNTIME_DATA) if write => return No(Refused::TableWrite),
- Some(EFI_RESERVED | EFI_ACPI_NVS | EFI_ACPI_RECLAIM | EFI_RUNTIME_DATA) => {}
+ Some(EFI_RESERVED | EFI_ACPI_NVS | EFI_ACPI_RECLAIM) => {}
+ Some(EFI_RUNTIME_DATA) if write => unreachable!(),
Some(_) | None => return No(Refused::MemoryType),
}
if last >= self.mapped_end {p3-runtime-code-is-read — RUN, red. diff --git a/toyos-userbound/src/firmware.rs b/toyos-userbound/src/firmware.rs
index de0eb794b..ce5e3b094 100644
--- a/toyos-userbound/src/firmware.rs
+++ b/toyos-userbound/src/firmware.rs
@@ -179,6 +179,7 @@ impl<D: IntoIterator<Item = (u64, u64)>> Memory<'_, D> {
Some(ty) if toyos_bootmap::is_usable_type(ty) => return No(Refused::UsableMemory),
Some(EFI_ACPI_RECLAIM | EFI_RUNTIME_DATA) if write => return No(Refused::TableWrite),
Some(EFI_RESERVED | EFI_ACPI_NVS | EFI_ACPI_RECLAIM | EFI_RUNTIME_DATA) => {}
+ Some(5) if !write => {}
Some(_) | None => return No(Refused::MemoryType),
}
if last >= self.mapped_end { |
…ype uncacheable With its tables readable, the test machine's load ran 13 of 14: one SSDT reads a byte at an address firmware's map lists nowhere, below 4 GiB, outside the ECAM window, in no page the kernel drives and no function's BAR. By its place it is the chipset's own register space. By the orchestrator's ruling (his, not the owner's): such a read passes where the kernel maps the address and the range registers type it uncacheable; a write stays refused. The direct map's leaves select the PAT's write-back entry, under which the range registers decide, so the kernel reads them at each such access (mtrr::range_type) instead of assuming. That check is also what keeps RAM a truncated map left out refused. Below 1 MiB the fixed range registers decide and this kernel reads none, so nothing unlisted is read there. A read that is refused for it is UnlistedCached. The probe reads q35's PCI hole, where OVMF types everything from the top of low RAM to 4 GiB uncacheable, is refused its write, and is refused the legacy video hole. The server calls such a page "unlisted firmware memory" in its counts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RvnWQFcMuGqTHYhvSnTe8A
|
Mutations for the unlisted-register arm at u1-an-unlisted-address-is-written — RUN, red. diff --git a/toyos-userbound/src/firmware.rs b/toyos-userbound/src/firmware.rs
index bd4986956..9bbab6045 100644
--- a/toyos-userbound/src/firmware.rs
+++ b/toyos-userbound/src/firmware.rs
@@ -191,7 +191,7 @@ impl<D: IntoIterator<Item = (u64, u64)>> Memory<'_, D> {
Some(ty) if toyos_bootmap::is_usable_type(ty) => return No(Refused::UsableMemory),
Some(EFI_ACPI_RECLAIM | EFI_RUNTIME_DATA) if write => return No(Refused::TableWrite),
Some(EFI_RESERVED | EFI_ACPI_NVS | EFI_ACPI_RECLAIM | EFI_RUNTIME_DATA) => {}
- None if !write => {}
+ None => {}
Some(_) | None => return No(Refused::MemoryType),
}
if last >= self.mapped_end {u2-an-unlisted-read-is-not-asked-of-the-range-registers — RUN, red. diff --git a/toyos-userbound/src/firmware.rs b/toyos-userbound/src/firmware.rs
index bd4986956..9f7dd22d2 100644
--- a/toyos-userbound/src/firmware.rs
+++ b/toyos-userbound/src/firmware.rs
@@ -197,7 +197,7 @@ impl<D: IntoIterator<Item = (u64, u64)>> Memory<'_, D> {
if last >= self.mapped_end {
return No(Refused::Unmapped);
}
- if ty.is_none() && !(self.uncached)(at, width.bytes()) {
+ if false && ty.is_none() && !(self.uncached)(at, width.bytes()) {
return No(Refused::UnlistedCached);
}
if write && self.facs.is_some_and(|facs| overlaps(at, last, facs)) {u3-an-unlisted-register-is-not-read — RUN, red. diff --git a/toyos-userbound/src/firmware.rs b/toyos-userbound/src/firmware.rs
index bd4986956..b3b1e26d2 100644
--- a/toyos-userbound/src/firmware.rs
+++ b/toyos-userbound/src/firmware.rs
@@ -191,7 +191,6 @@ impl<D: IntoIterator<Item = (u64, u64)>> Memory<'_, D> {
Some(ty) if toyos_bootmap::is_usable_type(ty) => return No(Refused::UsableMemory),
Some(EFI_ACPI_RECLAIM | EFI_RUNTIME_DATA) if write => return No(Refused::TableWrite),
Some(EFI_RESERVED | EFI_ACPI_NVS | EFI_ACPI_RECLAIM | EFI_RUNTIME_DATA) => {}
- None if !write => {}
Some(_) | None => return No(Refused::MemoryType),
}
if last >= self.mapped_end {p1-runtime-data-is-written — restated; run red at diff --git a/toyos-userbound/src/firmware.rs b/toyos-userbound/src/firmware.rs
index bd4986956..6205e6a8d 100644
--- a/toyos-userbound/src/firmware.rs
+++ b/toyos-userbound/src/firmware.rs
@@ -189,7 +189,7 @@ impl<D: IntoIterator<Item = (u64, u64)>> Memory<'_, D> {
}
match ty {
Some(ty) if toyos_bootmap::is_usable_type(ty) => return No(Refused::UsableMemory),
- Some(EFI_ACPI_RECLAIM | EFI_RUNTIME_DATA) if write => return No(Refused::TableWrite),
+ Some(EFI_ACPI_RECLAIM) if write => return No(Refused::TableWrite),
Some(EFI_RESERVED | EFI_ACPI_NVS | EFI_ACPI_RECLAIM | EFI_RUNTIME_DATA) => {}
None if !write => {}
Some(_) | None => return No(Refused::MemoryType),p2-runtime-data-is-not-read — restated; run red at diff --git a/toyos-userbound/src/firmware.rs b/toyos-userbound/src/firmware.rs
index bd4986956..9f841ef5f 100644
--- a/toyos-userbound/src/firmware.rs
+++ b/toyos-userbound/src/firmware.rs
@@ -190,7 +190,8 @@ impl<D: IntoIterator<Item = (u64, u64)>> Memory<'_, D> {
match ty {
Some(ty) if toyos_bootmap::is_usable_type(ty) => return No(Refused::UsableMemory),
Some(EFI_ACPI_RECLAIM | EFI_RUNTIME_DATA) if write => return No(Refused::TableWrite),
- Some(EFI_RESERVED | EFI_ACPI_NVS | EFI_ACPI_RECLAIM | EFI_RUNTIME_DATA) => {}
+ Some(EFI_RESERVED | EFI_ACPI_NVS | EFI_ACPI_RECLAIM) => {}
+ Some(EFI_RUNTIME_DATA) if write => unreachable!(),
None if !write => {}
Some(_) | None => return No(Refused::MemoryType),
}p3-runtime-code-is-read — restated; run red at diff --git a/toyos-userbound/src/firmware.rs b/toyos-userbound/src/firmware.rs
index bd4986956..60041eb3d 100644
--- a/toyos-userbound/src/firmware.rs
+++ b/toyos-userbound/src/firmware.rs
@@ -191,6 +191,7 @@ impl<D: IntoIterator<Item = (u64, u64)>> Memory<'_, D> {
Some(ty) if toyos_bootmap::is_usable_type(ty) => return No(Refused::UsableMemory),
Some(EFI_ACPI_RECLAIM | EFI_RUNTIME_DATA) if write => return No(Refused::TableWrite),
Some(EFI_RESERVED | EFI_ACPI_NVS | EFI_ACPI_RECLAIM | EFI_RUNTIME_DATA) => {}
+ Some(5) if !write => {}
None if !write => {}
Some(_) | None => return No(Refused::MemoryType),
} |
|
Every mutation not yet run, run once each at k1b-the-power-off-names-settle-and-does-not-call-it — RUN, red. diff --git a/kernel/src/arch/x86_64/power.rs b/kernel/src/arch/x86_64/power.rs
index 0eed43f94..01e6c4963 100644
--- a/kernel/src/arch/x86_64/power.rs
+++ b/kernel/src/arch/x86_64/power.rs
@@ -171,7 +171,7 @@ pub fn off(stopping: crate::quiesce::Stopping) -> ! {
let control = control.port(0);
let taken = pio::take_back(&stopping);
super::smi_cmd::settle(&taken);
- super::acpi_mode::settle(&taken);
+ let _ = super::acpi_mode::settle;
let held = cpu::inw(control);
if held & SCI_EN != 0 {
super::acpi_mode::quiet(&taken); |
|
T14 at
The three boots before it, each red on one refusal the next head answered: |
|
Review round 3 of Net lines, Measurements read at this head: CI run 37740095844 on Earlier BLOCKERs
BLOCKER
NOTE
Judged, and no finding
What the next slices must still prove on the metal machine
SEND BACK |
…rs that are off refuse, and a held Global Lock is denied The bound under 1 MiB was in the kernel's cache check, where no tier could tell it from the range registers' own answer: QEMU's firmware types the legacy hole write-back by the variable registers, so the probe's refusal there was made with or without it. It is `Memory::decide`'s now (`FIXED_RANGE_END`), held by a host case whose cache check answers yes to everything, and the kernel's function is the register read alone. Range registers that are off no longer pass an unlisted read: all RAM is uncacheable under them too, so the answer told a register from nothing. `Effective::typed_uncacheable` is the one place that says so, tabled. `mtrr::range_type` decided a log line until this branch and decides a security boundary from it, so its decision moves to `kernel::mtrr`, pure over the default-type word and the base and mask pairs, and is tabled on the host: the default, a region's last byte, a partly covered range, the overlap rules and the undefined encodings. A valid mask with no address bit, which shifted by 64 in the kernel, matches every address. A map may list a byte twice and the allocator takes every usable range, so `decide` and `lock_word` refuse wherever any usable range holds a byte of the access, whichever range lists it first. The wait for a contended Global Lock goes (the orchestrator's ruling): it zeroed every GPE enable on real hardware, no tier reached it, and the T14's 241 takes found the firmware holding the lock in none. A take answered `Pending` is denied by name and counted; `Claim::released`, `LOCK_WAIT`, `sci::GBL`, `Claim::scis` and the wait's tests are deleted, and the stage's issue records the exit that brings the wait back. The one-entry `evaluations` ledger goes with it; `Loaded` says who reads it. The test's register address is one of the test's own, and the issues record that the range registers are not the effective type everywhere, that the allocator's rule is what keeps RAM out, and that a press waits for the load. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RvnWQFcMuGqTHYhvSnTe8A
…nce at boot With the arm that passed range registers that are off deleted, the probe's read of q35's PCI hole went red: the probe ran on the guest's second CPU, whose IA32_MTRR_DEF_TYPE reads 0 on QEMU 11.1.1 under TCG, where the boot processor's registers type the same address uncacheable. So that read was passed by the deleted arm at the last head, and which CPU a call ran on decided what the kernel answered. The kernel reads the boot processor's default-type word and base and mask pairs once, in `acpi_mode::init`, and `kernel::mtrr` decides every unlisted read from them: one answer whichever CPU asks, and no MSR read at an access. That every other CPU's registers are the boot processor's is the SDM's rule for firmware and is not checked; the claim's issue records it with the guest's measurement and an exit. `acting` says why a claim that exists is the caller's: the ISA row mints no next claim while the process that bound it has a thread left. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RvnWQFcMuGqTHYhvSnTe8A
…address Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RvnWQFcMuGqTHYhvSnTe8A
|
Review round 4 of Net lines, Measurements read at this head: CI run 37746496416, Earlier BLOCKERs
BLOCKER
NOTE
Judged, and no finding
What each measurement must show
SEND BACK |
…he boot processor's, and one that differs stops the unlisted read An unlisted read was passed on the boot processor's range registers and made on whichever CPU ran the call; that the two agree was assumed, and on a q35 guest under TCG it is false: the second CPU's are off. - `kernel::mtrr::beside` is the comparison, pure over two snapshots: the same words, off, or on and not the same. Three host cases. - `arch::mtrr` keeps the boot processor's registers, read before any other CPU starts; each other CPU reads its own in `ap_entry` before it echoes and says which of the three it is, by name. Nothing is asserted: firmware owns these registers, and a guest's second CPU holds them off. - A CPU whose registers are off reads everything uncached, so a register is still read once. On a machine where any CPU's are on and not the boot processor's, `firmware::Memory::decide` refuses every read of an unlisted address `RangeRegistersDiffer`, a name of its own. - `acpi_mode` no longer keeps its own snapshot. - The metal row's judge reads a line for every other CPU and refuses one that is on and different; the guest probe prints the boot processor's line and the second CPU's. - The kernel programs no range register. Who owns the other CPUs' is the owner's question, recorded in the issue with why the guest's second CPU has them off, each with an owner and an exit. Measured, QEMU 11.1.1 q35 under TCG: the boot processor reads IA32_MTRR_DEF_TYPE 0xc06 with 8 variable pairs, cpu1 reads 0. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RvnWQFcMuGqTHYhvSnTe8A
|
Mutations of round 5, at A first invocation of
diff --git a/kernel/pure/mtrr.rs b/kernel/pure/mtrr.rs
index 564421c47..b70f94c1a 100644
--- a/kernel/pure/mtrr.rs
+++ b/kernel/pure/mtrr.rs
@@ -177,7 +177,7 @@ pub enum Beside {
/// snapshots that type every range alike and are not the same words are
/// [`Beside::Different`], which refuses and never passes.
pub fn beside(boot: (u64, &[(u64, u64)]), other: (u64, &[(u64, u64)])) -> Beside {
- if other == boot {
+ if false {
Beside::Same
} else if other.0 & DEF_TYPE_ENABLE == 0 {
Beside::Off
diff --git a/kernel/pure/mtrr.rs b/kernel/pure/mtrr.rs
index 564421c47..dacbc3046 100644
--- a/kernel/pure/mtrr.rs
+++ b/kernel/pure/mtrr.rs
@@ -179,7 +179,7 @@ pub enum Beside {
pub fn beside(boot: (u64, &[(u64, u64)]), other: (u64, &[(u64, u64)])) -> Beside {
if other == boot {
Beside::Same
- } else if other.0 & DEF_TYPE_ENABLE == 0 {
+ } else if false {
Beside::Off
} else {
Beside::Different
diff --git a/kernel/pure/mtrr.rs b/kernel/pure/mtrr.rs
index 564421c47..5d9e72382 100644
--- a/kernel/pure/mtrr.rs
+++ b/kernel/pure/mtrr.rs
@@ -177,7 +177,7 @@ pub enum Beside {
/// snapshots that type every range alike and are not the same words are
/// [`Beside::Different`], which refuses and never passes.
pub fn beside(boot: (u64, &[(u64, u64)]), other: (u64, &[(u64, u64)])) -> Beside {
- if other == boot {
+ if other.0 == boot.0 {
Beside::Same
} else if other.0 & DEF_TYPE_ENABLE == 0 {
Beside::Off
diff --git a/toyos-userbound/src/firmware.rs b/toyos-userbound/src/firmware.rs
index 67ed7691d..392cdd6dd 100644
--- a/toyos-userbound/src/firmware.rs
+++ b/toyos-userbound/src/firmware.rs
@@ -228,7 +228,7 @@ impl<D: IntoIterator<Item = (u64, u64)>> Memory<'_, D> {
if last >= self.mapped_end {
return No(Refused::Unmapped);
}
- if ty.is_none() && self.registers_differ {
+ if false {
return No(Refused::RangeRegistersDiffer);
}
if ty.is_none() && (at < FIXED_RANGE_END || !(self.uncached)(at, width.bytes())) { |
CI's `host` at 3a18a85 (run 37746496416) failed `could not compile kernel (lib)` in every clippy shape of the kernel, on two lints its clippy 1.99 has and this machine's 0.1.98 does not raise: `manual_isolate_lowest_one` at the region's size in `range_type`, and `manual_is_multiple_of` in the tests' `pair`. Both are written as it suggests; neither changes a value. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RvnWQFcMuGqTHYhvSnTe8A
|
T14 at head
The comparison lines of the So on this machine every CPU's range registers equal the boot processor's; the on-and-different arm ran on no machine. One earlier boot of |
|
Review round 5 of Net lines, Measurements read at this head: the orchestrator's two metal boots (comment 6055804005), judge exit 0 each, seven comparison lines, all "are the boot processor's". The implementer's logs: the kernel library's Earlier BLOCKERs
BLOCKER
NOTE
Judged, and no finding
What the landing rests onRun 37748731067 at SEND BACK |
Review round 5's NOTE. The bullet on a CPU whose range registers differ had the TCG guest's reading alone. Beside it now: the T14's acpi_tables_loaded boot at edfd522, where each of the seven other CPUs has the boot processor's words, and the KVM guest of CI run 37748731067 at edfd522, whose second CPU has them too. What stays open is why the second CPU under TCG has them off, and its exit no longer asks for the two readings that exist. No source, test or manifest changes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RvnWQFcMuGqTHYhvSnTe8A
|
Review round 6 of Net lines, Earlier BLOCKER
The diff since the last reviewed head
BLOCKERNone. NOTE
The bodyTrue of the head: it names What the landing rests onRun 37748731067 at LAND |
#749 wrote its new dependency edges into `kernel/Cargo.lock` and `userland/Cargo.lock`, which this branch deletes: both modify/delete conflicts are resolved by deleting the file. Git merged the root `Cargo.lock` without a conflict into a lock `cargo metadata --locked` refuses (exit 101): it took `toyos-userbound`'s edges to `toyos-abi` and `toyos-bootmap`, which #749 also wrote into the root lock, and not `acpiserver`'s to `toyos-acpi` and `toyos-aml`, which it wrote into userland's alone. `cargo metadata --offline` re-resolved it; the only change against git's merge is those two lines, no package is added and no version moves, and `cargo metadata --locked` exits 0. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RvnWQFcMuGqTHYhvSnTe8A
#749 landed sys_acpi and acpi_mode's access and Global Lock calls, which read the row number out of the claim and acted on it with the claim let go: the shape this branch removes, on the row. Resolved onto the borrow: - sys_acpi resolves the claim, copies an access request in, and makes all three operations inside one DeviceClaim::isa borrow, the holder's check (isa::held_by) included; the answer is copied out after the borrow, so no user copy is made under the claim's lock. A claim released under the call answers Gone. - acpi_mode::access, lock_take and lock_release take &isa::Row on both architectures. The port standing is asked about ROW, the one row an acpi claim is on. - Holder::claimed is deleted. It answered Gone to a call that reached acting() after the release had begun; a call now holds the lock the release takes the row with for the whole of the act, and acpi_mode::release runs only after that take, so the flag was never false where it was read. acting() takes the row as its witness and still refuses, under HOLDER, once the stop has begun. - acpi_mode::release gives the Global Lock back and leaves ACPI mode; the row's own release is the drop of the Row that follows it. Lock order of an access: the claim's Held, HOLDER, pcidev's MACHINE (with_bar_memory), paging's DRIVEN (with_driven_windows). inventory::claims takes process data, the claim's Held, MACHINE; settle takes HOLDER alone. Nothing takes a claim's Held or HOLDER under MACHINE or DRIVEN. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RvnWQFcMuGqTHYhvSnTe8A
…nd the SDK resolve together (#746) Stage 3 of `issues/the-tree-says-who-uses-each-thing.md`. The root, `kernel/`, `bootloader/`, `userland/` and `toyos/` were five Cargo resolutions; they are one workspace with one `Cargo.lock`, one `[profile.toyos]`, one `[patch]` table and one tracked `.cargo/config.toml`. No directory moves. Head `dd12c0b32`, on `origin/main` `6f87cdb9c` (#749; none of #757, #759 or #762 had landed when it was merged and measured). It is `9ef866436`, where the CI readings of the fold itself were taken, plus two merges of `main` and the close of the stage's issue. Everything owed at the merged head is in the next section, measured at `dd12c0b32`. ## The merge of #749, measured at `dd12c0b32` #749 wrote its new dependency edges into `kernel/Cargo.lock` and `userland/Cargo.lock`, which this branch deletes. Both modify/delete conflicts are resolved by deleting the file and re-resolving the root lock. Git merged the root `Cargo.lock` without a conflict into a lock that is wrong, as the review found: `cargo metadata --locked` on it exits 101 (`cannot update the lock file … because --locked was passed`). It had `toyos-userbound`'s edges to `toyos-abi` and `toyos-bootmap`, which #749 also wrote into the root lock, and not `acpiserver`'s to `toyos-acpi` and `toyos-aml`, which #749 wrote into userland's alone. `cargo metadata --offline` re-resolved it. `diff` of git's merged lock against the re-resolved one is those two lines under `acpiserver` and nothing else: no package added, no version moved. | Owed | Command | Result | |---|---|---| | The lock resolves as committed | `cargo metadata --locked --format-version 1` | exit 0 at this head by the host suite's step "the licences of what ships", which runs `cargo metadata --locked` for every shipped crate's manifest and is green in `host.log` and in run 37757675374; the hand run's empty stderr (`metadata-locked.err`) predates the merge commit and recorded no exit | | The lock's (name, version) pairs are the union of `main`'s five | `pairs.sh <worktree> 6f87cdb`: the pairs of `Cargo.lock`, `kernel/`, `bootloader/`, `userland/` and `toyos/Cargo.lock` at `6f87cdb9c`, `sort -u`, against the root lock's | 692 against 692, `diff` exit 0 (`pairs.out`) | | The folded kernel and loader are the control's bytes | `prove.sh 6f87cdb dd12c0b …`, the round 3 script unchanged | exit 0; all four `control vs fold` byte rows `cmp` exit 0; every row in "The checks" below (`prove.out`) | | No new reader of a compiled-in path | `git diff -U0 e3bdff8 dd12c0b -- tests src toyos-blackbox toyos-symbols userland/symbolize`, its added lines searched for `\.rs`, `taken at`, `panicked at`, `Location`, `file()`, `PREVIOUS_PANIC`, `strip_prefix`, `src/`, `pure/` | the merge touches five files there, all under `tests/`; 13 hits, of which 4 are diff headers and 9 the field `info.rsdp`; none reads a path. `tests/common/power.rs:429` is still the one reader outside fixtures, and reads `taken at kernel/src/hardlockup/probe.rs` (`readers-merge.diff`, `readers-hits.txt`) | | `cargo run -- --ci host`, once, on the development machine | at `dd12c0b32`, `cargo run -- --ci host > host.log 2>&1; echo EXIT=$?` | exit 0; the log ends `[ci] Host: 77 step(s), all green`; 1-minute load 26.60 when it started (`host.log`) | The logs are in the round's scratch directory (`orch/oneworkspace-r4/`), which a reader of this pull request cannot reach; `prove.out` and `pairs.sh` are in the round 4 comment. ## What changed, per decision - **Members.** `kernel`, `bootloader`, `toyos` and userland's 40 packages join the root `[workspace]`. `userland/Cargo.toml`, four locks, three `rust-toolchain.toml` and three per-directory `.cargo/config.toml` are deleted. The toolchain files chose nothing the build read: every guest `cargo` already runs under `RUSTUP_TOOLCHAIN` naming its sysroot. - **Flags.** `build.target` is gone, since every guest build already passes `--target`. The root config holds one `[target.<triple>]` table per guest triple, six, each with the flags its directory's config gave it. A host build takes none, as before. Two things do change: - The guest crates outside the workspace that are built from their own directory for a ToyOS triple (`tests/toyos-rust-tests` and its `tls-*` crates) now take `-Dwarnings`, because cargo reads the tracked root config from above them. On a checkout without a local config they took no flags. - The one build that sets `RUSTFLAGS` itself (the test binaries linked against a `cdylib`, `src/build.rs`) takes none of the table: the variable replaces it. - **Profiles.** The root's `[profile.dev]` is `opt-level = 2`. The kernel library's host tests, its model controls, the SDK's tests and every surveyed userland crate's host tests used to resolve in their own workspaces and ran at `opt-level = 0`; they now run at 2. - **What stays apart** (the root manifest's `exclude` says why at each entry): `rust/`; `tests/toyos-rust-tests` and its `tls-*` crates and `tests/ssh-client-host`, because `[patch]` is workspace-wide and they patch or refuse what the root patches; and `userland/libc`. libc keeps its own lock because that lock is an input of the sysroot key: as a member it would be resolved by the root lock, and every dependency change of any member would move the key and rebuild every sysroot. The price is a sixth resolution of `toyos`, `toyos-abi`, `toyos-elf`, `toyos-osrelease` and `dlmalloc` that nothing holds to the root's (both carry `dlmalloc` 0.2.13 today). - **The lock** is every `[[package]]` of the five locks, deduplicated and resolved by `cargo metadata`. Nothing was `cargo update`d. Since the lock reviewed at `88bcbf4d3` it has changed by #749's four edges alone (see the section above); `cargo metadata --locked` exits 0 at this head. - **One target directory.** Every guest is built at the root with `-p` into `target/`. A stale sysroot used to `cargo clean` a crate's own target; that would now empty the build system's own, so `Stale::All` removes `target/toyos` and the guest triples' directories instead, and the `cargo clean` path, its member assertion and its test are deleted. - **Kernel and loader build one after the other.** They were built on two threads. In one target directory cargo serialises them anyway (measured in round 1: the second prints `Blocking waiting for file lock on artifact directory`), so the thread scope is deleted. - **The host suite** can no longer be `--workspace`: the kernel binary, the loader and most of userland do not build for a host. `src/hostws.rs` says which members a host tests, and the workspace test and clippy runs `--exclude` the rest by package name. - **Fork clones.** The tracked config includes the gitignored `.cargo/local.toml` when it exists, and `implementer.md` names it. - **The merge of #745.** `src/sysroot.rs` keeps both sides: `SYSROOT_SOURCES` carries `"sdk/std"` and `SYSROOT_MANIFESTS` ends in `".cargo/config.toml"`; its test keeps both loops; `issues/toyos-has-its-own-allocator.md` keeps `sdk/std/sys/alloc.rs` and "from the kernel's graph in `Cargo.lock`". Git merged all three without a conflict. - **The host's own apps build where the userland tests build.** `src/ci.rs`'s apps step passes `--target` only where it checks another host's triple. On `main` the `userland/*` test steps and the host's apps step both named the host triple and shared `userland/target/<host triple>`. The fold took `--target` off the test steps, which no longer need it to keep a guest triple out, and left it on the apps step: the tests filled `target/debug`, the apps `target/<host triple>`, and every dependency was compiled twice. That is what made the sealed tree larger than `main`'s (see CI). - **The merges of `main`.** #747, #748, #750, #751, #753 and #755 merged without a conflict. #749 did not: see the section above. - **The merge of #752.** Git merged it without a conflict: both workflows' `host` jobs keep `CARGO_PROFILE_DEV_DEBUG: line-tables-only` in `env:`, and `carry()` no longer sets it. No manifest and no lock moved in the merge. - **Issues.** `issues/the-tree-resolves-in-five-cargo-locks-not-one.md` is deleted: the one thing it named as left, the T14's run of the metal profile on the folded build, ran green at `db55db96a`, and review round 2 ruled no boot owed for what followed on two conditions, both in the section above. Stages 2 and 3 of `issues/the-tree-says-who-uses-each-thing.md` now read "Landed in #724, #732 and #738" and "Landed in #746". What the file carried that stays true is the root manifest's `exclude`, which says why each excluded directory keeps its own resolution; the deleting commit's message carries the rest (libc's second resolution of five crates, and `miniz_oxide` 0.8.9 beside 0.9.1 until `png` takes 0.9). `issues/cargo-run-inside-kernel-loom-or-kernel-sim-builds-for-a-bare-target.md` is closed on the two in-directory runs at `9ef866436`. `issues/the-sdk-is-linted-by-no-clippy-run.md` is filed and names its owner, the build system. ## The fold changed the kernel's source paths, and the proof did not see it The T14's run of the whole metal profile at `88bcbf4d3` exited 1: 295 passed, 1 failed, 30 boots. The red row was `hard_lockup_ends_a_deaf_cpu`. Its judge looked for `taken at src/hardlockup/probe.rs` in the previous boot's panic record, and the readback's loader log says `taken at kernel/src/hardlockup/probe.rs:145:29`. **What changed in the kernel's strings.** Cargo hands rustc a workspace member's source by its path from the workspace root, and rustc writes that path into every panic and `Location`. The kernel's root was `kernel/`; it is now the repository. So `src/...` became `kernel/src/...`, and a path dependency outside the old root, which the base named by the checkout's absolute path, is now named from the repository root (`toyos-abi/src/...`). Read from the actuator kernel staged at this head: 254 distinct `.rs` paths, 158 under `kernel/`, 38 under a `toyos-*` crate or `bcachefs`, none bare `src/` or `pure/`, none naming the worktree. **Why the proof did not see it.** Both of its oracles were blind to it by construction: - The byte row compared the fold against a control that is the base with its workspace root moved up. The control moved the root too, so it carries the same new paths and the bytes agree. - The `rustc`-lines row compared base against fold after a `sed` that rewrites `(kernel/|bootloader/)?(src|pure)/x.rs` and `ROOT/<crate>/src/lib.rs` to one form. That rewrite is needed, or every path crate's line differs and the row can show nothing else; but it absorbed the change without reporting it. `prove.sh` now reports what that rewrite absorbs: per artifact, how many crates' source arguments were renamed, and a diff of the `.rs` paths the artifact carries, base against fold and control against fold. The script is in the round 3 comment and has run twice since, at `9ef866436` and at this head. **Every reader of a compiled-in path.** I searched the harness, the guest tests, the build system, `toyos-blackbox`, `toyos-symbols`, `userland/symbolize`, the loader and the kernel's panic path for path literals, prefix strips and `Location` readers. One reader matches a compiled-in path by its prefix: `tests/common/power.rs`, the red row's judge, now fixed to the path the kernel records. Everything else is prefix-blind (`panicked at`, a file name with its line) or a synthetic fixture. The kernel's panic slot keeps the last 96 bytes of a path; the longest kernel path is 46, so nothing is cut. Userland's panic sites gain a `userland/` prefix the same way; no test reads one. **The record rows.** The judging asked to record three `boot.testcases-bounds.*` rows. They are not this change's: that boot was already staged on the base and unrecorded, and `main` recorded it in #745. They arrive with the merge and nothing is committed here. ## What the fold changes in what is built The lock row was measured at `dd12c0b32` against `6f87cdb9c`, the `rustc` row by `prove.sh` at the same pair; the two `cargo tree` rows at `88bcbf4d3`, and were not taken again. | Measured | Result | |---|---| | Lock: (name, version) pairs, the fold's against the union of `origin/main`'s five | identical, 692 pairs, `diff` exit 0 | | Lock: sources | registry `getrandom` 0.2.17, 0.3.4, 0.4.2 are gone; the forks at the same versions remain | | Kernel and loader, both arches: every `rustc` command line of `cargo build -v`, base against fold, path and cargo's path-derived hashes taken out | identical, `diff` exit 0: 31 units per kernel, 55 and 37 per loader | | Userland, both triples: `cargo tree -e features` over every program, base against fold | identical, `cmp` exit 0 | | Host members: the same | `diff` exit 1, on `getrandom`'s source alone | So one resolved crate changes: the build system and the other host members compile the ToyOS forks of `getrandom` 0.2.17, 0.3.4 and 0.4.2 instead of the registry's, same versions, same features. And every source path compiled into the kernel and the loader changes, as above. ## The checks (high-risk: build system) Measured at `dd12c0b32` against `origin/main` `6f87cdb9c` by `prove.sh` (the script of the round 3 comment, unchanged), exit 0; its output is in the round 4 comment. Round 3 measured the same rows at `9ef866436` against `b432ed21c`, round 1 at `88bcbf4d3` against `e7010129f`. **Negative control.** The whole change reverted is the base. A second control is the base with only its workspace root moved up, keeping the crate's own base lock and its profile. It is given the fold's root `.cargo/config.toml`, so the control does not hold the flags: the one row that does is base against fold on normalised `rustc` lines. **Oracle.** Bytes and cargo's own command lines. Each cell is its own `cmp` or `diff` exit: | | kernel x86_64 | kernel AArch64 | loader x86_64 | loader AArch64 | |---|---|---|---|---| | control vs fold, bytes | 0 | 0 | 0 | 0 | | fold vs fold rebuilt, bytes | 0 | 0 | 0 | 0 | | base vs fold, bytes | 1 | 1 | 1 | 1 | | base vs fold, `rustc` lines normalised | 0 | 0 | 0 | 0 | | control vs fold, `rustc` lines verbatim | 0 | 0 | 0 | 0 | What the normalisation absorbs, reported by the three `paths` rows: base against fold, cargo hands rustc another source path for 29 of 31 crates of each kernel and for 35 of 50 and 13 of 35 crates of the loaders (`diff` exit 1 each, as expected); the `.rs` paths the x86-64 kernel carries are 250 on both sides, of which the base has 39 under the tree's absolute path and 150 from the crate's own root and the fold none of either (`diff` exit 1); control against fold the artifacts' paths are identical (`diff` exit 0, all four). **Mutations**, each on a fresh copy of the fold: M1 (drop the `[target.x86_64-unknown-uefi]` table) loader build exit 101; M2 (lock `dlmalloc` at 0.2.12) `cmp` exit 1 and lines `diff` exit 1; M3 (select `bcachefs` beside the kernel in one `cargo`) kernel build exit 101. ## Gates The rows of the section "The merge of #749" were read at `dd12c0b32`. Every row below was read at `9ef866436` unless it says otherwise, each once, the narrowest that judges it. `ci.yml` runs on the push of `dd12c0b32`; its result is not in this body. | Gate | Result | |---|---| | `cargo run -- --ci host` | at `dd12c0b32`, development machine: exit 0, `[ci] Host: 77 step(s), all green`. Linux runner at `9ef866436`: `ci.yml` run 37740454881 `host` success; cold inside `--ci seal`, nightly run 37740449787: `[ci] Seal: 80 step(s), all green`; on macOS, the same nightly's `portability-macos`: success | | `cargo test --lib ci::tests` (the changed step's own test) | exit 0, 13 passed | | The images and the guest suite | at `9ef866436`, run 37740454881: `toolchain / build` and `guest / suite` success (KVM); run 37740449787: `toolchain / build` and `tcg / suite` success. At `e3bdff8af`, run 37755369755: `host` and `toolchain / build` success, `guest / suite` still running when read. Not run locally, and not read at `dd12c0b32` | | `prove.sh 6f87cdb dd12c0b …` | exit 0; every row as in the table above | | `cargo test` inside `kernel/loom` | exit 0 | | `cargo test` inside `kernel/sim` | exit 0 | | Cold wall clock, x86-64 kernel and loader (`wall.sh`, one run) | base, two cargos side by side: 24 s, 1-minute load 34.92 before it. Fold, one after the other: 20 s, load 42.23. Other agents' builds were running, so the two are not a controlled pair; the fold was not slower | | Metal profile | every row green at `db55db96a` (comment 6048782042). Since then the branch changed `src/ci.rs` and the root lock's two `acpiserver` edges; the kernel sources that moved are `main`'s own landings (#747, #748, #749), merged in. Review round 2, ruling (3), owes no boot for the merge of #749 on two conditions, both met above | | `cargo test --manifest-path userland/acpiserver/aml/Cargo.toml` at `e3bdff8af` | exit 0 | | `git status --porcelain --ignore-submodules=none` at `dd12c0b32` | empty | `issues/cargo-run-inside-kernel-loom-or-kernel-sim-builds-for-a-bare-target.md`'s close now stands on the two in-directory runs at `9ef866436`. The logs of these rows are files in the scratch directory of the round that took them (`orch/oneworkspace-r3/`), which a reader of this pull request cannot reach; the proof's and the measurements' outputs are in the round 3 comment. ## CI **Why the sealed tree was larger than `main`'s, measured.** A `workflow_dispatch` of `nightly.yml` at `88bcbf4d3` (run 37685714260) sealed `9348536345 B in 20064 files`, red. Units compiled per step, counted from that log and from `main`'s nightly at `b432ed21c` (run 37717000719, sealed `18708 files, 7664839895 B`): | step | `88bcbf4d3` | `main` | |---|---|---| | the driver's own build | 203 | 203 | | the build system | 207 | 207 | | the workspace's host members | 99 | 99 | | clippy, warnings denied | 412 | 417 | | the controls | 56 | 56 | | `userland/*` | 225 | 289 | | the apps for linux | 282 | 47 | | the apps for macos | 248 | 248 | | the apps for windows | 239 | 239 | Of the 256 distinct crates the apps-for-linux step compiled at `88bcbf4d3`, 226 had been compiled by an earlier step of the same run; 30 by none. The cause is the target directory: the test steps built without `--target` into `target/debug`, the apps step with `--target x86_64-unknown-linux-gnu` into `target/x86_64-unknown-linux-gnu`. Profile, features and `RUSTFLAGS` are the same in both. **The fix, measured once on the development machine** (`share.sh` in the round 3 comment; cold, a target of its own, `aarch64-apple-darwin`): after the fourteen test steps' builds (271 units), the ten apps with `--target <host>` compile 270 units and add 616,616 KiB under `target/<host>` and 135,064 KiB under `target/debug`; the same ten without `--target` then compile 47 units and add 107,856 KiB. The 47 are the same crates `main`'s step compiles on the runner. **The seal at `9ef866436`, nightly run 37740449787** (conclusion success: `host`, `portability-linux`, `portability-macos`, `toolchain / build`, `tcg / suite`): ``` the cache entry, read by content: none restored: the run is cold the apps for linux: 10 app(s) pass `cargo build`; … the tree, sealed as the host cache's entry: 17010 files, 7493968284 B of the 8000000000 B an entry may hold; sealed: 2496 sources, built on Linux X64 ubuntu24 20261004.327.1, every target dated as built [ci] Seal: 80 step(s), all green ``` Units per step in its log, against the two columns above: | step | `9ef866436` | `88bcbf4d3` | `main` | |---|---|---|---| | `userland/*` | 225 | 225 | 289 | | the apps for linux | 42 | 282 | 47 | | the apps for macos | 264 | 248 | 248 | | the apps for windows | 240 | 239 | 239 | Every other step compiles what it did at `88bcbf4d3`. I expected 47 for the Linux apps: it is `main`'s 47 less `crc32fast`, `log`, `memchr`, `smallvec` and `toyos-keymap`, which an earlier step had compiled. I did not expect the macOS step's 16 more: all are host-side units (`syn`, `thiserror-impl`, `tokio-macros`, `futures-macro`, `autocfg` and the like), which the Linux step's `--target` build used to compile for the host and which the first `--target` step now compiles instead. The four steps together compile 771 units against 994 at `88bcbf4d3` and 823 on `main`. - Margin: 506,031,716 B under the limit, 6.3 %, on image 20261004.327.1. `main`'s 7,664,839,895 B was sealed on 20260927.320.1. The one pair of figures there is for the two images is `f260e0b98`, built with full debuginfo before #752 cut it to line tables: 8,540,783,725 B on 20260927.320.1 (run 37292450697) against 8,182,940,473 B on 20261004.327.1 (run 37601225884), 357,843,252 B or 4.2 % less on the newer. So this head's figure and `main`'s are not a pair, and this head is unmeasured on the older image. - Against the same branch before the fix and before #752: 9,348,536,345 B at `88bcbf4d3` on 20260927.320.1. **`ci.yml` run 37740454881 at `9ef866436`:** `host`, `toolchain / build` and `guest / suite` success. After this lands every `host` check runs cold until the first nightly on `main` seals and saves: the path list is the cache's version. **Toolchain keys.** The fold moves the sysroot key once: `userland/.cargo/config.toml` was one of its inputs and `.cargo/config.toml` replaces it. From now on a change to any guest triple's flags moves that key. The merges of #747 and #749 moved `toyos-abi` and `toyos`, so the sysroot key moved with `main`; the key at this head was not read here. ## No new gate, test or dependency No guest test is added or changed. No dependency is added. The proof is a one-off script because its subject is this one change against its base. ## Size `git diff --shortstat origin/main...HEAD` at `dd12c0b32`: 53 files, +5454 −7765. Without the locks: 48 files, +446 −704. `src/`, `tests/toyos.rs` and `tests/common/`: 12 files, +237 −360, of which tests are roughly +65 −115 by my reading of the hunks (an estimate, not a count). `issues/`: 16 files, +49 −115. ## What I am unsure of - **The seal on the older runner image.** GitHub serves two; this branch was sealed on the newer one, at `9ef866436`. The only pair of figures for the two is `f260e0b98` with full debuginfo (above): the older image sealed it 357,843,252 B larger. Carried unscaled onto this tree that leaves 148,188,464 B under the limit on the older image; scaled by the pair's ratio, about 178 MB. Both are arithmetic, not a run. - **`dd12c0b32` itself:** `ci.yml` run 37757675374 has `host` and `toolchain / build` success at it; its `guest / suite` is what the landing waits on. #757 (`b6bcb9691`) landed on `main` after this head was merged and measured: ten source files under `kernel/src`, `toyos-abi/src`, `toyos-userbound/src` and `tests/toyos-rust-tests`, no manifest and no lock; `git merge-tree --write-tree dd12c0b b6bcb96` exits 0. Nothing here was measured with it in. It differs from the sealed head by `main`'s #749, #750, #753 and #755 and the root lock's two edges; the seal's byte count at this head is unmeasured. - **Build wall clock.** One run under load; the fold was not slower. - **Clippy reaches further.** The bare-target shapes now also lint the kernel's and the loader's path dependencies for those targets. - **The licence gate reads a superset.** `--all-features` for the kernel now turns on every member's features. It judges more than ships. - **The runner's cargo.** The nightly's `host` at `88bcbf4d3` parsed the optional `include`, so the runner's cargo accepts it. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01RvnWQFcMuGqTHYhvSnTe8A
…pinned in its row, and the dropped press decided where a host test reads it A holder supplied `\_S5`'s sleep type as often as it liked and each call wrote a kernel record. `acpi_mode::s5` now refuses a second under one claim (`AlreadyExists`), and `release` clears the flag, so "replaceable" means by the next claim's holder and the log carries one line a claim. The guest probe reads both: its keeper supplies a sleep type q35 does not power off on and is refused a second; the probe, the next holder, supplies q35's over it and is refused a second in its turn; the harness reads exactly those two kernel lines and that QEMU stopped the guest for `guest-shutdown`, which it does on the probe's value alone. The probe's first refused shutdown moves ahead of the keeper, since the keeper's value outlives it. The `acpi_tables_loaded` row compared the server's line with the kernel's echo of the same word. It now takes the kernel's line whole to the value, as `Q35_S5_SUPPLIED` holds q35's, and the T14's is `T14_S5_SUPPLIED`: PM1a control at 0x1804 and SLP_TYPa 7, which the kernel's byte scan of that machine's DSDT logged on the boot #749 landed on (`ACPI: PM1a=0x1804 SLP_TYPa=7`). The row also reds on the server's word that the machine has no power-off. What a press is whose power-off came back refused was a match arm in `Server::press` that no test reached. It is `sci::unstopped`, pure, with a host test: only the kernel's `NotSupported` on a machine this server handed no sleep type drops the press. The track records what the claim's holder gains, the sleep type a power-off enters, with its owner and exit; says which machines without a power-off are the ruled state and which a weakness with an exit; says the refusal during the load stays; and gives "Go on, say it loudly" the breadth it was ruled with. The T14 power-off issue names the re-owning as this slice's placement. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RvnWQFcMuGqTHYhvSnTe8A
Slice S1 of the ACPI stage, both halves, landing as one merge: the kernel's mediated access for the
acpiclaim's holder (SYS_ACPI) with the firmware's Global Lock, andacpiserverloading the machine's definition blocks through it and evaluating\_S5. The kernel half's account is first, kept true of this head; the server half's is under it.Head
54e08c632. It differs fromedfd5220ainissues/only:git diff --stat edfd5220a 54e08c632is one file,issues/the-acpi-claims-holder-reaches-every-port-and-firmware-range-the-kernel-did-not-declare.md, 16 insertions and 9 deletions, review round 5's NOTE. No source, test, manifest or lockfile differs, so every measurement below that namesedfd5220ais of the code at this head, and "this head" below, where it speaks of code, isedfd5220a's tree.edfd5220ais review round 4's answer (9b928ca4e) and two lines written as CI's clippy asks, on3a18a85e6. The owner's word on this machine's compute is "try to be economic": the narrowest tests that judge the change were run locally, once each, each mutation of round 4 once, and the guest probe; no whole suite was run locally, andhost,toolchain / buildandguest / suiteare CI's, which ran them atedfd5220a.Measured at
edfd5220a:edfd5220a, read withgh run view 37748731067once it ended:completed,success, and each of its three jobssuccess.host(job 113216910123), its log read whole from a saved copy:[ci] Host: 78 step(s), all green. Of what review round 5's BLOCKER lists, all of it is there:mtrrtests, each... okby name under[ci] the kernel's library(cargo test --manifest-path kernel/Cargo.toml --target-dir target --lib --features sched-check, 168 passed, 0 failed), the three of round 4 among them:registers_that_are_word_for_word_the_boot_processors_are_the_same,registers_that_are_off_and_not_the_boot_processors_are_off,registers_that_are_on_and_not_the_boot_processors_are_different;toyos-userbound'stests/firmware.rs,running 20 tests, each... ok, 20 passed, 0 failed,no_unlisted_address_is_read_where_a_cpus_range_registers_differ ... okamong them, under[ci] the host workspace;acpiserver's,running 26 tests, each... ok, 26 passed, 0 failed, under[ci] userland/acpiserver(cargo test --manifest-path userland/acpiserver/Cargo.toml --target x86_64-unknown-linux-gnu), and[ci] userland/acpiserver/amlafter it;[ci] clippy, warnings denied: clean: the kernel library and its tests in two shapes, the kernel forx86_64-unknown-nonein six and foraarch64-unknown-none-softfloatin four. Neithermanual_isolate_lowest_onenormanual_is_multiple_ofis anywhere in the log, and nocould not compile.FAILEDin the log is between the first and the last[ci] controlheading, a negative control that is to fail. The oneerror:outside them,unclosed table, expected ], is the output of a build-system test that feeds a malformed manifest, among tests that pass.toolchain / build(job 113216910735): success.guest / suite(job 113220132648), under KVM, QEMU 11.1.1:test result: ok. 31 passed, 31 total,PASS acpi_power_buttonandPASS acpi_mediated_accessby name, and the probe's two lines:So under KVM the second CPU's range registers are the same, where under TCG on this host they are off.
edfd5220a, the hashes as the Gates table has them:acpi_tables_loadedboot exit 0 and judge exit 0,[metal] 1 passed, 0 failed, 1 boot(s);acpi_server_deaththe same. Theacpi_tables_loadedboot printed the boot processor's line,IA32_MTRR_DEF_TYPE 0xc06 and 10 variable pairs, and a comparison line for each of its seven other CPUs, every onerange registers are the boot processor's. So on that machine no CPU's registers are off or different, the one unlisted read is passed on registers every CPU shares, and the on-and-different arm has run on no machine. One earlier boot of that row in the round was of the image staged at9b928ca4eand is not counted.Measured at the head reviewed before it,
3a18a85e6:acpi_tables_loadedEXIT=0, 1 passed, 0 failed, 14 of 14 tables loaded in 78 ms, the AML's 385 SystemMemory and 10 PCI_Config reads in 6 pages of type 10, 5 of type 11 and 1 of unlisted firmware memory, 241 takes of the Global Lock and none from the firmware,\_S57 and 7;acpi_server_deathEXIT=0. So with the boot processor's range registers deciding, the one unlisted read still passes on the real machine and nothing else is refused.gh run view 37746496416once it ended:toolchain / buildsuccess;guest / suitesuccess under KVM, 31 passed of 31,PASS acpi_power_buttonandPASS acpi_mediated_accessby name in its log, so the read of q35's PCI hole passes there on the boot processor's registers and the read below 1 MiB is refused;hostred, and then cancelled by this round's push while it ran. Its log (job 113209106784) haserror: could not compile kernel (lib) due to 1 previous errorin each of the kernel's clippy shapes, 12 times, and(lib test) due to 2 previous errorstwice, for two lints in round 3'skernel/pure/mtrr.rs:manual_isolate_lowest_oneat(phys_mask & phys_mask.wrapping_neg())inrange_type, andmanual_is_multiple_ofatbase % size == 0in the tests'pair. No other error is in that log: every otherFAILEDthere is under a[ci] controlheading, a negative control that is to fail. CI's clippy is 1.99 and this machine's is 0.1.98, which raises neither, so no local run could have shown them. Fixed atedfd5220aas that clippy suggests (isolate_lowest_one(),is_multiple_of), neither changing a value: the kernel library's ninemtrrtests are green on it, and this machine's clippy, which cannot see the two lints, is green over the kernel's library and tests, the x86-64 kernel with and without the actuator features, the AArch64 kernel, andtoyos-abi,toyos-userboundand the harness. CI's clippy passes atedfd5220a(above).Earlier boots of the metal row, at
4284062c1,2484aa3a5and253d4f5f4, were red each for the next thing, as the sections below say; it was green at88f38a289too.Answers to review round 5
cargo run -- --ci hostand the guest tests the change reaches had no result atedfd5220aedfd5220a, with no change to the code:host,toolchain / buildandguest / suitesuccess, each item the BLOCKER lists read in the logs (at the top). KVM gives the second CPU the boot processor's registers, so the probe's read of the PCI hole passes there with nothing refused.54e08c632: the bullet carries all three readings, by count and kind: the test machine's seven other CPUs the same, KVM's second CPU the same, TCG's second CPU off. Its second open thing is now only why TCG's second CPU is off, and its exit is the firmware's source or the emulator's read for that CPU.cargo test --test toyos-checksat54e08c632: EXIT=0, 36 passed.Answers to review round 4
kernel::mtrr::beside, pure over two snapshots besiderange_type, answersSame(word for word),Off(not the same, the enable bit clear) orDifferent(not the same, and on).arch::mtrr::initkeeps the boot processor's registers before any other CPU starts; each other CPU reads its own inap_entry, before it echoes to the roster, and says one line naming which of the three it is. A CPU whose registers are off reads everything uncached by the architecture, so nothing is refused for it. Where any CPU's are on and not the boot processor's,Memory::deciderefuses every read of an unlisted address under a name of its own,Refused::RangeRegistersDiffer(16), decided before the bound under 1 MiB and the cache check; listed memory and every other refusal are as they were.acpi_modekeeps no snapshot of its own any more. The kernel programs no range register: who owns the other CPUs' is recorded in the claim's issue as the owner's question.hostandguest / suitehad no result3a18a85e6guest / suitewas success with both ACPI tests passing by name andhostwas red on two clippy lints inkernel/pure/mtrr.rs, fixed atedfd5220a. CI's run 37748731067 atedfd5220ahas all three jobs success (at the top).Measured on
9b928ca4e's tree before its commit,cargo test --test toyos-build -- acpi_mediated_access, EXIT=0, QEMU 11.1.1 q35 under TCG on this host, the kernel's two lines as the test prints them:So this host's emulation gives the second CPU off. The probe's read of the PCI hole passes and its read below 1 MiB is refused
UnlistedCached, as before. The test now requires both lines and prints them, andguest / suiteatedfd5220ashows which of the three KVM gives: the same (at the top).Mutations, one per case of the comparison and one for the refusal, each applied as a checked patch, run once and reversed by one script at
9b928ca4e, the tree clean after each; every one EXIT=101 by a failed assertion (the patches are in the pull request's newest mutation comment):c1the same words are not the samecargo test --manifest-path kernel/Cargo.toml --target-dir target --lib mtrrregisters_that_are_word_for_word_the_boot_processors_are_the_samec2registers that are off read as differentregisters_that_are_off_and_not_the_boot_processors_are_offc3only the default type is comparedregisters_that_are_on_and_not_the_boot_processors_are_differentc4an unlisted read passes where registers differcargo test -p toyos-userbound --test firmwareno_unlisted_address_is_read_where_a_cpus_range_registers_differA first invocation of
c1toc3handed the script its command as one word, so cargo never started (EXIT=127): no result, and the runs in the table are the first of each test.Unsure, and reached by no tier:
Differentarm has run on no machine. Its decision is host-tested and the policy's refusal is host-tested; the two lines between them, the flagcomparesets and the fieldacpi_mode::memorypasses, are read and not run. No QEMU flag gives a CPU range registers that are on and differ, and staging it would be a write to an AP's range registers shipped for a test.Different, which refuses. Chosen as the answer that cannot pass wrongly; the test machine's firmware leaves no such words: all seven of its other CPUs compared the same.RangeRegistersDiffer, notUnlistedCached: both refuse.edfd5220a:cargo run -- --ci host, the AArch64 kernel and userland,acpiserver's andtoyos-aml's host tests, and every guest test but the probe. CI ran them there (at the top). At54e08c632no CI run has a result as this is written; it differs in one issue file, and the one gate run on it locally iscargo test --test toyos-checks, EXIT=0.Answers to review round 3
Where a choice was the reviewer's to offer, the ruling taken is the orchestrator's, not the owner's.
Memory::decide's (firmware::FIXED_RANGE_END): an unlisted read below it is refusedUnlistedCachedbefore the cache check is asked. Host casean_unlisted_address_below_1_mib_is_refused_whatever_the_range_registers_answer, whose cache check answers yes to everything. The review's patch, moved with the bound, isr1: red at that test. The probe's assertion stays, and stays unable to tell: its guest types the legacy hole write-back.Effective::typed_uncacheableis the one place that says which answer is a register's, andregisters_that_are_off_type_nothing_uncacheabletables it on the host;r2puts the arm back and is red there. Deleting it turned the probe red, which is how the next section was found. No guest reaches the arm after that section's change: the decision is the boot processor's registers, which are on.Pendingis denied by name,the Global Lock: the firmware holds it, and this server waits for no release yet, and counted in the ledger.Claim::released,LOCK_WAIT,sci::GBL,Claim::scis,Firmware::beginand the wait's host tests are deleted;a_lock_the_firmware_holds_is_denied_by_name_and_countedand the Lock field's load test hold the denial, andr3(a pending lock reported taken) is red at both. The stage's issue records it with the 241 takes and the exit: a machine's log carries the denial, whichacpi_tables_loadedreds on as on every refusal.REGISTERS + 0x12_3000, an address of the test's own.mtrr::range_typedecides a security boundary untestedkernel::mtrr::range_type, pure over the default-type word and the base and mask pairs, in the kernel's host-tested library besidepcid; the MSR reads stay inarch/x86_64/mtrr.rs. Six host tests table it: the default type, a region to its last byte, a partly covered range, every overlap of two types, the undefined encodings, registers that are off.r6(a partly covered range takes the register's type) andr7(uncacheable does not win an overlap) are red. One defect found on the way: a valid mask with no address bit shifted by 64, a kernel panic by overflow check that a holder's read could now reach on firmware that sets one; it matches every address now, tabled.type_ofanswers the first rangedeciderefusesUsableMemorywhere any usable range of the map holds a byte of the access, andlock_wordrefuses a word any usable range holds a byte of. Host casememory_any_usable_range_holds_is_refused_whatever_lists_it_first, over each firmware type listed before each usable one;r4andr5are red at it. A read across two types is stillStraddles, decided first.Loaded, and theevaluationsledgerLoadedstays and its doc says who reads it: whoever evaluates a method after the load asksblockswhether there is a namespace, and the power-off through the server writess5.mainacts on neither yet; see "unsure".Mutations of round 3, each applied as a checked patch, run once, and reversed by one script at
e3449c6f5, the tree clean after each; every one EXIT=101 by a failed assertion:r1no bound below 1 MiBcargo test -p toyos-userbound --test firmwarean_unlisted_address_below_1_mib_is_refused_whatever_the_range_registers_answerr2registers that are off passcargo test --manifest-path kernel/Cargo.toml --target-dir target --lib mtrrregisters_that_are_off_type_nothing_uncacheabler3a pending lock is reported takencargo test --manifest-path userland/acpiserver/Cargo.toml --target aarch64-apple-darwina_lock_the_firmware_holds_is_denied_by_name_and_counted, and the Lock field's load testr4the first range listed types a byter1memory_any_usable_range_holds_is_refused_whatever_lists_it_firstr5the lock word is typed by the first ranger1r6a partly covered range takes the register's typer2a_register_types_its_region_to_the_last_byte_and_no_furtherr7uncacheable does not win an overlapr2two_registers_over_one_range_answer_as_the_architecture_orders_themThe boot processor's range registers decide, read once (
c62f75db4)At
e3449c6f5, with BLOCKER 2's arm deleted and the registers still read at each access,cargo test --test toyos-build -- acpi_mediated_accesswas EXIT=1: the probe's read of q35's PCI hole answeredUnlistedCached. Measured with one temporary log line, applied as a patch and reversed: the probe ran on the guest's second CPU, whoseIA32_MTRR_DEF_TYPEread 0 — its range registers off — on QEMU 11.1.1 under TCG on this host, where the boot processor's registers type the same address uncacheable (the kernel'smmio: … (MTRR UC)lines, all on cpu0). So at88f38a289that read was passed by the arm the review named, and which CPU a call ran on decided the kernel's answer. Under KVM in CI the second CPU's registers are the boot processor's (read atedfd5220a, at the top); why the second CPU under TCG has them off is unread, and the claim's issue owns it.acpi_mode::initat that head; inarch::mtrr::init, before any other CPU starts, at this one), and every unlisted read is decided from them (acpi_mode::uncachedoverkernel::mtrr::range_type): one answer whichever CPU asks, and no MSR read at an access.3a18a85e6it was assumed that every other CPU's range registers are the boot processor's; at this head each is compared (round 4's answer, at the top).acpi_mediated_accessatc62f75db4: EXIT=0. On the test machine at3a18a85e6the one unlisted page still loads (the orchestrator's boot, at the top).Outside finding T001-PR-01
An outside audit of
88f38a289reports thatSYS_ACPIcan act for a replacement claim after it validated an earlier holder: a thread of process P passes the handle and row-binding checks, another thread of P closes the claim, a new claim is minted for process Q, which takes the Global Lock, and the first thread then resumes and gives Q's lock back.It does not hold, at that head or this one. The step that fails is the new claim for Q.
isa::claim_rowrefuses a claim (Owned) while the row's ports are bound to a process, and the binding goes back only inisa::process_ends, which the process's teardown calls once every thread of it has left (kernel/src/process.rs, afterclose_all). A thread of P paused insideSYS_ACPIis a thread of P that has not left, so no claim, Q's or P's own, is minted while it can still resume. When it does resume after the close,acting()findsclaimedfalse and answersGone. None ofkernel/src/isa.rs,kernel/src/syscall/device.rsandkernel/src/device.rsdiffers between88f38a289and this head. By reading; nothing was run for it, and no test stages the interleaving.acting's doc now says what itsclaimedrests on.The reviewer traced it independently in round 4 and found the same, with more than the above: the binding leaves the process only in
isa::process_ends, called fromteardown_resources, whichprocess::leaveruns only on itsLastarm, so the thread that runs it is the last one out, and a kill only posts a retire a thread meets later;claim_rowrefusesOwnedwhile the binding is anyone's, under the row's own lock. Two variations fail too: a handle moved to another process answersPermissionDeniedthere and never rebinds, and a claim minted and never read is bound to nobody and passes for nobody. His reason for no new test: the half a test reaches cheaply is already onmainin the ISA row's guest test, which closes a claim in a child and asserts a second claim answersAlreadyExistswhile the binding process lives, and the ACPI claim mints through the sameclaim_row; staging the interleaving itself needs a pause inside the syscall, which is kernel code shipped for a test.The read passes at an unlisted register (
88f38a289)The boot at
253d4f5f4loaded 13 of 14 tables in 74 ms, and\_S5evaluated toSLP_TYPa=7, the kernel's own. Its numbers, the first of each: the tables' bytes took 42893 reads, in 109 pages of type 6, 2 of type 9 and 1 of type 10; the AML read SystemMemory 316 times and PCI_Config 10 times, its memory in 6 pages of type 10 and 5 of type 11; the Global Lock was taken 204 times and never found with the firmware. Table 11, an SSDT, was refused for one read:a SystemMemory read the kernel refused MemoryType, in memory of no type, being unlisted.What that address is, from the boot's own log: one byte, below 4 GiB and above everything the firmware's map lists there; outside the ECAM window the MCFG names, so no routing defect; inside the direct map; in none of the eleven windows the kernel mapped; and no function's BAR, none of which the map lists either. By its place it is the chipset's fixed register space under 4 GiB. The 5 pages of type 11 the AML read are the ECAM window's, which the firmware types memory-mapped I/O and the policy routed to configuration reads, as designed.
42893 reads, explained to the read: the fetch reads qwords, then single bytes for a range's last seven at most, and fetches each table once whole after its 36-byte header once (8 reads, repeated inside the whole). Recomputed from the lengths Linux prints for that machine's tables — the RSDP, the XSDT's header and body, a header for each of its 31 entries, and the FADT, the DSDT and the 13 SSDTs whole — the sum is 42893.
The orchestrator's ruling, not the owner's: a read at an address the map does not list passes where it is no usable RAM by construction, none of the kernel's driven pages, no decoded BAR, and reachable; a write stays refused.
toyos-userbound/src/firmware.rs: an unlisted read passes where it is inside what the kernel maps andMemory::uncachedanswers yes; the device pages and the ECAM window are decided before it, as before. A write isMemoryTypeas it was. A read the range registers do not type uncacheable is refused under a new name,Refused::UnlistedCached.88f38a289the kernel read those registers at each such access and passed where they answered uncacheable or were off; at this head the boot processor's, read once, decide, and registers that are off refuse (the sections at the top). On the test machine the kernel's log givesMTRR UCfor each register window it maps in the same region.unlisted firmware memory.UnlistedCached. Measured at88f38a289:acpi_mediated_accesspasses on an x86-64 guest under TCG on this host. Under KVM it passes in CI, at88f38a289,3a18a85e6andedfd5220a(Gates).an_unlisted_register_is_read_where_it_is_uncached_and_never_written, and three mutations run once each at88f38a289withcargo test -p toyos-userbound --test firmware, each EXIT=101 by failed assertions with the other 15 tests passing in the same run:u1an unlisted address is writtenevery_other_type_and_an_unlisted_address_is_refused_with_its_typeu2the range registers are not askedu3an unlisted register is not read (the arm reverted)Booted as staged at
88f38a289: the row green, the figures at the top of this body.The read passes in runtime-services data (
253d4f5f4)The boot at
2484aa3a5read what the first could not:acpiserver: table 1 of 31 (DSDT) refused: its bytes could not be read: a SystemMemory read the kernel refused MemoryType, in memory of type 6, andreads of the tables' bytes the kernel refused: a SystemMemory read the kernel refused MemoryType, in memory of type 6 x60. That machine's firmware keeps its FADT and every definition block its XSDT lists inEfiRuntimeServicesData. UEFI 2.10 §2.3.4 has "ACPI Tables loaded at boot time can be contained in memory of type EfiACPIReclaimMemory (recommended) or EfiACPIMemoryNVS", read from the Internet Archive's capture of 2025-01-24 of the specification's chapter 2; this firmware does otherwise.The orchestrator's ruling, not the owner's: the mediated read passes in
EfiRuntimeServicesDataas it does in reserved, ACPI reclaim and ACPI NVS memory; a write there stays refused by name,TableWrite, until a machine's AML is measured making one;EfiRuntimeServicesCodestays refused both ways. His reasons:toyos_bootmap::is_usable_typenever hands type 5 or 6 to the allocator, so no kernel or process memory carries either; and the kernel's own reader already reads the tables there. The cost — the holder reads whatever else a firmware keeps in runtime-services data, which nothing has listed — is recorded inissues/the-acpi-claims-holder-reaches-every-port-and-firmware-range-the-kernel-did-not-declare.md.toyos-userbound/src/firmware.rs: type 6 joins the types read, and the types whose write isTableWrite.Refused::TableWrite's doc says both.253d4f5f4withcargo test -p toyos-userbound --test firmware, each EXIT=101 by failed assertions, the other new testokin the same run:p1a write in type 6 passesruntime_services_data_is_read_as_the_tables_memory_is_and_never_written, and the sweepp2a read in type 6 is refusedp3a read in type 5 passesruntime_services_code_is_refused_both_ways, and the sweepThe boot at
253d4f5f4read the tables through: the section above has it.The first load on the real machine, and what
2484aa3a5changesThe server said its DSDT was refused as absent, counted 31 tables and loaded none. Read from that boot's log:
Absentwas this branch's defect, not the firmware's. The walk looked for the FADT asfind_tabledoes, passing an unreadable entry over, found none, and answered that nothing names a DSDT. Neither FADT field was ever read, so which ofDSDTandX_DSDTis followed did not come into it;dsdt_addressis the kernel's own function and prefers a non-zeroX_DSDTfrom revision 2 on.Unmappedbecause nothing says an entry whose header was not read is no SSDT. Linux's 14 are the DSDT and the 13 entries whose signature isSSDT; its 8 dynamically loaded tables are no XSDT entries and the walk does not count them. With the entries readable the count is 14.reserved, the RSDP and XSDTACPI data, and the one readable entryACPI NVS. e820'sreservedcovers several UEFI types, and the policy passes a read only in type 0, 9 and 10. Which type it is has not been read, and the kernel reads these same tables for itself through the direct map whatever their type, which is why it finds\_S5there.What changed:
definition_blocksrefuses the DSDT as the first entry that could not be read where no FADT was found, and saysAbsentonly where every entry was read and none is a FADT.find_tableis as onmain.a_dsdt_whose_fadt_could_not_be_read_is_refused_as_unread_and_not_as_absent(toyos-acpi), andtables_in_memory_of_a_type_the_kernel_keeps_are_refused_by_that_name_and_type(acpiserver).The policy was not changed at
2484aa3a5, and the row was red there as expected; its lines are in the section above.The merge with
main, hunk by hunkmaintook #747 (UserSafeproved bytoyos_abi::user_safe!) and #748 (every write toSMI_CMDthroughkernel/src/arch/x86_64/smi_cmd.rs, on the boot processor). Four files conflicted; two more merged without a conflict and were wrong.toyos-abi/src/acpi.rs:Blockismain's.AcpiInfois declared throughuser_safe!with this branch'srsdpandreservedfields.Accessis declared throughuser_safe!too. Both pass the macro's check as they stood; neither layout changed. Their hand size assertions andAcpiInfo::as_bytesare gone, as onmain.kernel/src/user_ptr.rs:main's side whole. This branch's handunsafe impl UserSafe for Accessis deleted with every other.kernel/src/arch/x86_64/acpi_mode.rs:main's side for the port:smi_cmddeclares it, holds its lock and makes its writes, andHardware::legacyismain's. This branch's side for the holder:HOLDER, the lock word, the mediated access.settlehere keeps only the holder's half;SMI_CMD's half issmi_cmd::settle.kernel/src/arch/x86_64/smi_cmd.rs(no conflict): itspio::declaregains the argument this branch made required,Mediated::ReadOnly. That is where a holder's write toSMI_CMDis refused now, said at the declaration.kernel/src/arch/x86_64/power.rs(no conflict, and wrong as merged):mainreplacedacpi_mode::settlewithsmi_cmd::settleon the line this branch's wait hangs off, and git tookmain's line cleanly. The power-off would have stopped waiting out a mediated access. It calls both now.kernel/src/arch/x86_64/acpi_mode.rs's imports (no conflict, did not compile):maindroppedcrate::sync::{Lock, LockGuard}, which this branch'sHOLDERneeds. Restored.tests/toyos.rs:acpi_death_on_metalreadsmain's line shape for both writes, its boot-processor judgement and its "asked from another CPU" check, and this branch's lock-word line.main's merged as it stands onmain.What changed, per decision
SYS_ACPI(claim, op, ptr): an access (a struct in and out), take the lock, give it back.toyos_abi::acpi::Refused), one variant a row of the policy, with the UEFI type of the address. The kernel logs no refusal.toyos-userbound/src/firmware.rs, and answers a witness or a refusal; the kernel's accessors take only witnesses (fourcompile_faildoctests).DeviceMemory): every windowmap_mmiomade, every memory BAR as firmware left it, whoever drives the function, and the local APIC's range, each grown to the 4 KiB pages it lies in. A windowpcidevcuts for a BAR is no longer fed to the policy (round 2's NOTE, decided: deleted, with its host case):publishseeds what is taken with every range of firmware's map, so a window is cut only at an address the map does not list, andplace_barreads every address it tries throughmap_mmio, so a cut window is among the driven windows before it is a BAR's; the half changed nothing the policy answers.Mediated). COM1, the 8259 pair, CMOS, 0xCF8/0xCFC, the reset register and a kernel-driven i8042 are kept;PM1a_CNT, the TCO block andSMI_CMDare read and never written; the POST port is open; another claim's row is refused; anything else passes.ConfigWrite, until a machine's AML makes one. The measurement behind it: no path of the real tables writes configuration space.config_write, theConfigWritewitness,pcidev::mediated_standing,caps::programmed_lenand its test, and four refusal names are deleted.toyos-acpidecodes the FACS, now held to §5.2.10's 64-byte boundary, and holds §5.2.10.1's two transitions as pure functions. The kernel exchanges the word only through a witness (firmware::lock_word) answered where all four of the word's bytes are ACPI NVS or reserved memory inside the direct map; round 1 typed the structure's first byte. A lock its holder left taken goes back at the claim's end and before the power-off. A FACS the FADT names and the kernel refuses answers every takeNotSupported(round 2's NOTE): only a FADT that names no FACS answers taken, since a holder told it holds a lock that excludes nothing is told a falsehood. No tier reaches that arm: no guest has a FACS the kernel refuses.HOLDER, across decision and act. Every access and every lock exchange is made under it and refusedGoneonce the claim is gone or the stop has begun;settletakes it before the power-off owns the hardware, which waits out the one in flight. The records of device memory are read under their own locks and released before the access: a window mapped after the decision is one the access was made a moment before.mm::firmware_map).toyos-userboundontoyos-abiandtoyos-bootmap, so the access words, the map entry and "which types are RAM" are declared once.issues/the-acpi-claims-holder-reaches-every-port-and-firmware-range-the-kernel-did-not-declare.md, now with what the review found it omitted.Answers to review round 1
pcidev'sdecoded; thewindowshalf went in round 2. Measured on the test machine instead of guessed, below.HOLDER, as above; it takes the first NOTE with it.DRIVEN's growth is stated at its site.The test machine's memory, read
From the kernel log of the tree's
countersrow on that machine and from Linux's print of the same firmware's map (types and counts only):So on that machine, and on q35, round 1 already answered a BAR and a kernel-driven window
MemoryTypeorUnmapped. Items 2 and 3 were holes only where firmware lists such a range as reserved; the record now refuses them there.Answers to review round 2
tests/toyos-rust-tests/src/bin/acpi_mediated.rs). A stop ends no process, sopower::offfinds a live holder's lock taken.acpi_mediated_accesswaits for the kernel'sacpi: the Global Lock given back for a holder that left it taken (the machine is stopping)after the probe's own line, or for the job's end, which is a probe whose arm failed. The review's patch isk1in the mutation comment, andk2drops the give-back insidesettle. Run at88f38a289: the review's patch as written does not build — with the call goneacpi_mode::settleis dead code, which the kernel's build refuses (error: function settle is never used), so that exact loss cannot land.k1bkeeps the function named and drops the call, andk2drops the give-back inside it: each redsacpi_mediated_access, which stalls waiting for the kernel's line.NotSupported; above.windowshalfm4is restated for it.m5tom8at2484aa3a5against the host tests,m1tom4at88f38a289against the probe. The tables are under the checks below.SYS_ACPIfrom hardwareacpi_tables_loadedis staged; below.acpiservercalls it at this head.Why the probe is a guest test
Its test changed at
9b928ca4e: it requires and prints the kernel's line for the boot processor's range registers and the second CPU's line beside them. How a hypervisor hands a second CPU its range registers is that hypervisor's answer and no host test has one; the metal row reads the same lines from the real machine, and this is the only reading under TCG and KVM, where the answer was measured to be other than the SDM's rule.Its behaviour changed at
88f38a289: it ends by powering the machine off with the Global Lock held, and its test reads the kernel's line for that instead of the job's exit. That line is said inside the power-off, by the kernel, of a live process holding a claim: no host test has a kernel, and the T14 is not powered off by a row. For the rest: a type and the host tests hold the policy. What is left is the kernel between the syscall and the hardware, and the probe's red arm is the kernel making those writes for real, on a machine nothing powers on again. It boots withi8042-withheldbecause only there is a port another claim's row rather than the kernel's.The kernel half: unsure, and reached by no tier
GBL_RLSassertion rests on QEMU keeping the bit as written; CI's guest run at377153444passed on it.acting()answers.pcidev'sdecodedrecord.NotSupportedhas no test: no guest's FACS is one the kernel refuses, and nothing stages one.The server half
What changed, per decision
toyos-acpi:definition_blockswalks the DSDT the FADT names and then every SSDT the XSDT lists, in the XSDT's order, each validated (Table::open) or answered as its refusal, the walk going on past it. The DSDT's item is always first. An entry of another signature and a null entry are passed over. An entry whose header cannot be read is answeredUnmapped, not passed over asfind_tablepasses it: nothing says it is no SSDT, and the ruling is to say a refused table loudly.find_tableis the same function it was, over a helper the walk shares.acpiserverarms, then loads, then serves. A press during the load latches inPWRBTN_STSand is served when the load ends.acpi_power_buttonsends its press as soon as the server says it armed, so the guest suite runs that order.tables.rs):toyos_acpi::Physover mediated reads, a range fetched whole inreadableand read from what is held inbyte, which is that trait's contract. Qwords, then single bytes for the last seven at most, so no read reaches past the range asked for into memory of another type. Address zero is no table's.Host(host.rs) is generic over a small trait,Kernel, that the claim implements inmain.rsand a scripted stand-in implements in the host tests.toyos-userbound's, once.\_S5.toyos_amlrefuses that space itself (field.rs,Unsupported("the SystemCMOS address space")), and itsAddresshas no variant for it, so there is nothing to deny here.Free, so one path does both and I built no second.Pendingis denied by name and counted in the ledger; the access under it is not made, and the table or method that asked is refused. The server waits for no release of the firmware's (review round 3, at the top).std::thread::sleepand Stall a spin, each for what the firmware asked, bounded by the interpreter. Notify is counted.Goneonce a stop begins,machine_shutdowncan begin one while the server loads, and a server that panicked there would put a panic in every such boot's log. Any other error from a call the server formed is a panic naming it.ledger.rs) says a refusal the first time it is seen and counts it after; one line at the load's end gives the counts of the accesses refused. A refused\_S5is one line.\_S5is evaluated after the load and said asacpiserver: \_S5 evaluated: SLP_TYPa=… SLP_TYPb=…. The server cannot see the kernel's value; the guest test and the T14 row hold the two lines against each other.\_S5. Nothing reads it afterwards in this slice, and a field kept for S2 would be dead code until then.toyos_aml::Error::Bridge { segment, bus, device, function, header_type, secondary }for the interpreter's two refusals of a bridge's registers, which wereError::Rulewith a sentence.toyos::AcpiDevgainsaccess,lock_takeandlock_release, the typed wrappers over the three calls.toyosis in the sysroot, so this rebuildsstd.The lines
toyos-amlchanges, for the merge with #750userland/acpiserver/aml/src/lib.rs: six lines added afterHost(String),inenum Error(theBridgevariant and its doc). The AML interpreter's 16 MiB counts the heap it holds, and a refused load gives its memory back #750's hunks in that file are at its header, atMAX_LIVE, and fromInterpreter::newdown.userland/acpiserver/aml/src/field.rs, inpci: the tworeturn Err(Error::Rule(…))of the bridge walk and the line that reads the Header Type, five lines for three. The AML interpreter's 16 MiB counts the heap it holds, and a refused load gives its memory back #750's hunk inpciends 14 lines above, atbelow.push(host).userland/acpiserver/aml/tests/regions.rs: two assertions ina_pci_config_region_below_bridges_is_on_the_nearest_ones_secondary_bus, a line each. The AML interpreter's 16 MiB counts the heap it holds, and a refused load gives its memory back #750 adds a test after that function's end, 12 lines below the second.mainas017451624and is merged into this head: no conflict, and the interpreter's and the server's host tests are green on the merge (Gates).What a line may be quoted from
A line anyone may quote carries a table's place and whether it is the DSDT or an SSDT, a refusal's kind, the address space, the kernel's name for a refusal, the memory type and counts. Every address, PCI function, table offset, bridge register and name the firmware chose is on a separate line that opens
acpiserver: (this machine's own, quoted in no record).every_refusals_kind_is_free_of_what_the_firmware_choseholds the first kind for the interpreter's errors that carry such a thing.Tests, by tier
kindmatchestoyos_aml::Errorwithout a wildcard, so a new error is a compile error until it has a quotable name.toyos-acpi(4 new tests, and one line in the corpus's single-byte mutation walk): QEMU's own tables yield its DSDT alone; a crafted XSDT yields the DSDT first, the SSDTs in order, each refusal in its place; a DSDT that cannot be found is the first item refused and the SSDTs follow.acpiserver: the host's reads, refusals and denials against the scripted kernel, a held Global Lock's among them; the fetch's widths and refusals; the ledger; and the load end to end — QEMU 11.1.1's own tables through the whole path every guest boot takes (walk, fetch, checksum, load,\_S5= 0), a refused SSDT, a refused DSDT, tables the kernel will not read, a stop mid-load, and a Lock field read at load that takes the lock and is refused, unread, where the firmware holds it.toyos-aml: the two bridge assertions now name the registers answered.acpi_power_buttonreads every table line as loaded, the DSDT first, and\_S5'sSLP_TYPaequal to the kernel'sACPI: PM1a=… SLP_TYPa=line, and that the press was served after it. Why a guest: the host test loads the same DSDT against a stand-in for the kernel; what is left is the kernel's mediation answering a real firmware's table memory, on the boot path every guest test shares, and the T14 row reads another firmware. No new guest test: the assertions ride a boot that exists.acpi_tables_loaded, booted green atedfd5220a, below.Checks of the high-risk code
g00. Both arms run and red: the policy's host tests at2484aa3a5(11 of 14), and the probe at88f38a289, at "acpi: RAM was read".s1(a write passed to the kernel),s2(the controller's space reads all ones) ands3(a refused read answers zero), each against a named host test inhost.rs. The server has no policy of its own over reads, so "a read it should refuse" is a read the kernel refused and the host passed off as made:s3.\_S5, a second implementation over the same bytes read another way; each table's checksum, which is its firmware's seal over bytes the server read throughSYS_ACPI; and the real machine, booted atedfd5220a, with Linux's count of its definition blocks (14 ACPI AML tables successfully acquired and loaded).k1), 16 for this half, three for the runtime-services arm and three for the unlisted-register arm, the last six in their own sections above. Each passesgit apply --checkat88f38a289;p1top3are restated there, their context having changed, and were run at253d4f5f4. Nine were run at2484aa3a5, once each, applied as a checked patch, run, and reversed by one script, the tree clean after each; every one is red by a failed assertion and none by a build error:g00policy passes everythingcargo test -p toyos-userbound --test firmwareram_is_refused_both_ways_whatever_usable_type_it_isamong themm5no page roundingevery_page_a_window_the_kernel_drives_lies_in_is_refused_inside_any_type, and the BAR testm7first byte typedthe_lock_word_is_exchanged_only_where_all_four_bytes_are_the_firmwares_ownm8config write passesevery_configuration_write_is_refused_by_one_namem6FACS aligned to fourcargo test -p toyos-acpi --test facsa_facs_off_its_sixty_four_byte_boundary_is_refusedi1a refused SSDT passed overcargo test -p toyos-acpi --test corpus definition_blocksthe_definition_blocks_are_the_dsdt_and_then_each_ssdt_in_the_xsdts_orderi2the DSDT not firstcargo test -p toyos-acpi --test corpus --test fixtures definition_blocksfixtures.rsdid not runi3an unread FADT is an absent DSDTcargo test -p toyos-acpi --test corpus a_dsdt_whose_fadta_dsdt_whose_fadt_could_not_be_read_is_refused_as_unread_and_not_as_absentb1a bridge on its own bus walkedcargo test --manifest-path userland/acpiserver/aml/Cargo.toml --target aarch64-apple-darwin --test regions a_pci_config_region_below_bridgesa_pci_config_region_below_bridges_is_on_the_nearest_ones_secondary_busg00is the negative control's host arm; its guest arm, the probe, is unrun.i3's test is new at this head, so its green arm is CI's next run.88f38a289, by the same script, the tree clean after each:g00policy passes everythingcargo test --test toyos-build -- acpi_mediated_accessk1the review's patchsettleis never usedk1bsettlenamed, not calledk2a stop leaves the lock takenm1no window recordedm2noGBL_RLSm3another row's port freem4no BAR feds10the server loads nothingcargo test --test toyos-build -- acpi_power_buttons1a write passed to the kernelcargo test --manifest-path userland/acpiserver/Cargo.toml --target aarch64-apple-darwinnothing_is_written_and_the_controllers_space_is_not_reacheds2the controller's space reads all oness3a refused read answers zeroa_read_the_kernel_refuses_is_denied_under_the_kernels_name_and_counteds4a pending lock reported taken88f38a289, the wait's tests, since deleted; restated for this head asr3, at the tops5the lock wait not spent88f38a289, a test of the wait; the wait and the patch's subject are deleteds6a fetch reads whole qwordsa_range_is_fetched_whole_in_qwords_and_then_bytes_and_kept, and eight mores7SSDTs load onto a refused DSDTa_refused_dsdt_leaves_no_namespace_and_loads_no_ssdt, and one mores8a refused SSDT ends the loada_refused_ssdt_is_one_block_refused_and_the_rest_loads9a refusal's kind names what the firmware choseevery_refusals_kind_is_free_of_what_the_firmware_choseNo patch of this pull request is unrun;
s5has no subject left. One thing still has no test and so no patch: the take a refused FACS answersNotSupported.The T14 row
acpi_tables_loaded, on the bootacpi_server_eventsalready takes (testcases-hold). Booted at4284062c1,2484aa3a5and253d4f5f4, red each time for the next thing, as the top of this body says; green as staged at88f38a289, at3a18a85e6and atedfd5220a. Its judge reads:a line of the kernel's for every CPU but the boot processor saying how its range registers stand beside the boot processor's, as many as the roster brought up, and none on and different; it prints how many are off;
every table line, as many as Linux loads on that machine (14), each loaded, the DSDT first;
\_S5'sSLP_TYPaequal to the kernel's own line;no refusal line of any kind, which holds no bridge refusal, no
Unmapped, and no access the policy kept from the load;that the load's AML read memory, read configuration space and took the Global Lock at least once each — the scouts measured all three for these tables — so the real lock word was exchanged and given back;
and prints the load's time, the reads by address space, the takes that found the firmware holding the lock, and the pages of memory by UEFI type, for the tables' bytes and for the AML's reads apart.
Of what review round 2 lists for the metal machine, this row reaches: the mediated reads against an independent reading, for the memory the tables are in only (their checksums, and
\_S5against the scan); the memory type of every page touched, noneUnmapped; the configuration reads through the real ECAM window; takes and releases of the real lock word. It does not hold a value read from ACPI NVS or reserved memory against an independent reading: the load's AML reads such memory, and nothing else in this slice reads the same bytes another way. The server reads no FACS signature, which would be that check, because it has no other use for one. Later slices own: what the refusedSMI_CMDwrite breaks in the methods that make it (S3a/S3b, where a write is first made); a port access that traps into SMM under the mediation's lock (S3b); a release that owes the firmware its signal, read by the SMI count (S3b, if contention is ever counted); the power-off with the server alive and holding the lock (S2, and no row powers the T14 off); the server killed mid-load with the lock held (no slice stages it).acpi_server_deathkills the server as soon as it says it armed, which from this head is as its load begins, so that row now reads legacy mode again after a server killed while loading; whether a take was in flight at the kill is chance. It was green at3a18a85e6and atedfd5220a.Gates
host(job 113216910123, 78 steps all green),toolchain / build(job 113216910735),guest / suite(job 113220132648, 31 of 31), CI run 37748731067edfd5220aacpi_tables_loaded, the test machine, the image6c0e19dc…e4ebad19(comment 6055804005)[metal] 1 passed, 0 failed, 1 boot(s); seven comparison lines, each the boot processor'sedfd5220aacpi_server_death, the test machine, the imagec6d36024…7a611a6e(comment 6055804005)[metal] 1 passed, 0 failed, 1 boot(s)edfd5220acargo test --test toyos-checks54e08c632host,toolchain / build,guest / suite(31 of 31), CI run 3774009584488f38a289toolchain / build,guest / suite(31 of 31), CI run 377464964163a18a85e6host, CI run 37746496416kernel/pure/mtrr.rs; then cancelled by the push of9b928ca4e3a18a85e6boot-actuators,test-actuators, the AArch64 kernel, and-p toyos-userbound -p toyos-abi -p toyos-build --all-targets, withsrc/clippy.rs's adopted lints and-D warningsedfd5220a's treeacpi_tables_loaded, the test machine88f38a289, and3a18a85e6acpi_server_death, the test machine4284062c1, and3a18a85e6acpi_tables_loaded, the test machine, three earlier boots4284062c1,2484aa3a5,253d4f5f4cargo test -p toyos-userbound --test firmware9b928ca4ecargo test --manifest-path kernel/Cargo.toml --target-dir target --lib mtrr9b928ca4e, andedfd5220a's treecargo test --test toyos-build -- acpi_mediated_access9b928ca4e's tree before its commitcargo run -- --build-onlydbdc05f35cargo test --test toyos-build -- acpi_power_buttondbdc05f35cargo test --test toyos-build -- acpi_mediated_accessdbdc05f35dbdc05f35and a one-line patchcargo test --manifest-path userland/acpiserver/aml/Cargo.toml --target aarch64-apple-darwin87bf03b60cargo test --manifest-path userland/acpiserver/Cargo.toml --target aarch64-apple-darwin87bf03b60cargo test --test toyos-build -- --metal --metal-readback <dir> acpi_tables_loaded6c0e19dc…e4ebad19edfd5220a, clean treecargo test --test toyos-build -- --metal --metal-readback <dir> acpi_server_deathc6d36024…7a611a6eedfd5220a, clean treecargo run -- --ci host, the guest suite,toolchain / buildedfd5220ahost,toolchain / build,guest / suiteedfd5220ain one issue file54e08c632The stagings compiled the kernel, userland, the guest test binaries and
tests/toyos.rsatedfd5220a; the probe's run before them rebuilt the sysroot fortoyos-abi's new variant.The server half: unsure, and reached by no tier
aml::loadreturns what became of each block and\_S5, andmainacts on neither. Its tests read it; its doc says which later slice reads which field. If the reviewer holds that to be a return for the tests alone, the alternative is tests that read the server's lines.toyos-abi's wrappers are called throughtoyos::AcpiDevin the server and directly in the probe, which must ask on an unbound raw claim.Lines
git diff --shortstat origin/main...54e08c632: 53 files changed, 4786 insertions(+), 195 deletions(-).🤖 Generated with Claude Code
https://claude.ai/code/session_01RvnWQFcMuGqTHYhvSnTe8A