S127 · SOURCE-BOUND GATE EVIDENCE
K1/MEM0: per-frame domain sınıfı, hard quota ve fiziksel reconciliation
Operations --test hedefi → focused test içindeki include_str!/#[path] bağı → kaynak kesiti Bu sayfa yalnız S127 kapısına aittir; komşu kapıların kaynakları bu kabulün içine katılmaz.
S127Focused kod testiOperations id exactsource SHA exacttest target exact
operation: k1-mem0-per-frame-ownership-reconciliation-partial
uygulama/model · focused test · Operations · 3 exact excerpt
sequence-bound=true · implementation-bound=false
01 · Testin bağlı olduğu uygulama/model kodu
Kapının yürüttüğü gerçek kaynak
tam Rust öğesiL1212–L3355
kernel/src/mm/runtime_memory.rs::audited_mem0_reconciliation
impl<'metadata> RuntimeMemoryState<'metadata> {
/// Construct the sole state for a claimed inventory.
///
/// # Safety
///
/// `metadata` must be stable, exclusively writable bookkeeping storage
/// which cannot physically alias any allocatable frame in `inventory`.
/// Its backing pages must remain reserved from this and every other
/// allocator for the complete state lifetime. The inventory authority
/// itself proves the separate physical-region uniqueness obligation.
pub(crate) unsafe fn try_new(
inventory: RuntimeMemoryInventory,
metadata: &'metadata mut [u8],
) -> Result<Self, RuntimeAllocationError> {
let mut destination = core::mem::MaybeUninit::<Self>::uninit();
// SAFETY: `destination` is aligned, writable, and uninitialized. This
// function carries the remaining inventory and metadata contracts.
unsafe { Self::try_initialize_at(destination.as_mut_ptr(), inventory, metadata)? };
// SAFETY: success writes every field exactly once.
Ok(unsafe { destination.assume_init() })
}
/// Build a runtime state directly in permanent manager-owned storage.
/// This is crate-private so arbitrary production callers cannot obtain a
/// raw placement constructor or bypass the boot authority manager.
///
/// # Safety
///
/// In addition to [`Self::try_new`]'s contracts, `destination` must be
/// aligned, writable storage for one uninitialized `Self`. It must never
/// have held a live state and must not be observed until success returns.
pub(crate) unsafe fn try_initialize_at(
destination: *mut Self,
inventory: RuntimeMemoryInventory,
metadata: &'metadata mut [u8],
) -> Result<(), RuntimeAllocationError> {
let instance_epoch = mint_instance_epoch()?;
#[allow(unused_unsafe)]
// SAFETY: `RuntimeMemoryInventory::claim_bounded` and this function's
// metadata contract jointly satisfy the raw constructor requirements.
let pmm = unsafe {
RuntimePmm::try_new_bounded(
inventory.regions(),
inventory.reserved(),
metadata,
inventory.max_end,
)
}
.map_err(RuntimeAllocationError::Pmm)?;
// No fallible operations remain. Initialize fields without first
// materializing the large ledger as a stack value.
// SAFETY: The caller supplied exclusive uninitialized storage.
unsafe {
core::ptr::addr_of_mut!((*destination).inventory).write(inventory);
core::ptr::addr_of_mut!((*destination).pmm).write(pmm);
RuntimeMemoryLedger::initialize_at(core::ptr::addr_of_mut!((*destination).ledger));
core::ptr::addr_of_mut!((*destination).instance_epoch).write(instance_epoch);
}
Ok(())
}
pub const fn snapshot(&self) -> RuntimeMemorySnapshot {
RuntimeMemorySnapshot {
instance_epoch: self.instance_epoch,
inventory_region_count: self.inventory.region_count,
inventory_reserved_count: self.inventory.reserved_count,
inventory_max_end: self.inventory.max_end,
pmm: self.pmm.snapshot(),
registered_domains: self.ledger.registered_domains,
active_allocations: self.ledger.active_allocations,
retired_allocations: self.ledger.retired_allocations,
pin_references: self.ledger.pin_references,
prepared_mappings: self.ledger.prepared_mappings,
active_mappings: self.ledger.active_mappings,
pending_tlb_invalidations: self.ledger.pending_tlb_invalidations,
kernel_access_references: self.ledger.kernel_access_references,
scrub_access_references: self.ledger.scrub_access_references,
scrubs_in_progress: self.ledger.scrubs_in_progress,
release_scrubbed_allocations: self.ledger.release_scrubbed_allocations,
last_allocation_generation: self.ledger.last_allocation_generation,
last_pin_generation: self.ledger.last_pin_generation,
last_mapping_generation: self.ledger.last_mapping_generation,
last_access_generation: self.ledger.last_access_generation,
last_scrub_generation: self.ledger.last_scrub_generation,
}
}
/// Rebuild all internal ledgers and require exact PMM agreement.
pub fn audited_snapshot(&self) -> Result<RuntimeMemorySnapshot, RuntimeAllocationError> {
let snapshot = self.snapshot();
let pmm = self
.pmm
.audited_snapshot()
.map_err(RuntimeAllocationError::Pmm)?;
if pmm != snapshot.pmm
|| self.instance_epoch == 0
|| self.inventory.region_count == 0
|| self.inventory.region_count > MAX_RUNTIME_REGIONS
|| self.inventory.reserved_count > MAX_RUNTIME_RESERVED_RANGES
{
return Err(RuntimeAllocationError::InvariantViolation);
}
let allocatable_frames = pmm
.total_frames
.checked_sub(pmm.reserved_frames)
.ok_or(RuntimeAllocationError::InvariantViolation)?;
let mut observed_domains = 0usize;
for (index, record) in self.ledger.domains.iter().copied().enumerate() {
if !record.occupied {
if record != DomainRecord::EMPTY {
return Err(RuntimeAllocationError::InvariantViolation);
}
continue;
}
if record.generation == 0
|| record.hard_limit_frames == 0
|| record.hard_limit_frames > allocatable_frames
|| self.domain_allocated_frames(record.id)? > record.hard_limit_frames
{
return Err(RuntimeAllocationError::InvariantViolation);
}
observed_domains = observed_domains
.checked_add(1)
.ok_or(RuntimeAllocationError::CounterOverflow)?;
if self.ledger.domains[index + 1..]
.iter()
.any(|other| other.occupied && other.id == record.id)
{
return Err(RuntimeAllocationError::InvariantViolation);
}
}
if observed_domains != self.ledger.registered_domains {
return Err(RuntimeAllocationError::InvariantViolation);
}
let mut observed_pin_records = 0u64;
for (index, pin) in self.ledger.pins.iter().copied().enumerate() {
if !pin.active {
if pin != PinRecord::EMPTY {
return Err(RuntimeAllocationError::InvariantViolation);
}
continue;
}
if pin.generation == 0
|| pin.generation > self.ledger.last_pin_generation
|| pin.owner.instance_epoch != self.instance_epoch
|| self.ledger.pins[index + 1..]
.iter()
.any(|other| other.active && other.generation == pin.generation)
{
return Err(RuntimeAllocationError::InvariantViolation);
}
let allocation = self
.allocation_record_by_generation(pin.allocation_generation)
.map(|(_, record)| record)
.ok_or(RuntimeAllocationError::InvariantViolation)?;
if allocation.owner != pin.owner || pin.frame_offset >= allocation.frame_count {
return Err(RuntimeAllocationError::InvariantViolation);
}
observed_pin_records = observed_pin_records
.checked_add(1)
.ok_or(RuntimeAllocationError::CounterOverflow)?;
}
let mut observed_prepared = 0u64;
let mut observed_mapped = 0u64;
let mut observed_pending_tlb = 0u64;
for (index, mapping) in self.ledger.mappings.iter().copied().enumerate() {
if !mapping.active {
if mapping != MappingRecord::EMPTY {
return Err(RuntimeAllocationError::InvariantViolation);
}
continue;
}
if mapping.generation == 0
|| mapping.generation > self.ledger.last_mapping_generation
|| mapping.owner.instance_epoch != self.instance_epoch
|| !mapping_descriptor_is_valid(mapping.descriptor)
|| self.ledger.mappings[index + 1..].iter().any(|other| {
other.active
&& (other.generation == mapping.generation
|| other.descriptor == mapping.descriptor)
})
{
return Err(RuntimeAllocationError::InvariantViolation);
}
let allocation = self
.allocation_record_by_generation(mapping.allocation_generation)
.map(|(_, record)| record)
.ok_or(RuntimeAllocationError::InvariantViolation)?;
if allocation.owner != mapping.owner
|| allocation.frame_count != mapping.descriptor.page_count
{
return Err(RuntimeAllocationError::InvariantViolation);
}
match mapping.phase {
MappingPhase::Prepared => {
observed_prepared = observed_prepared
.checked_add(1)
.ok_or(RuntimeAllocationError::CounterOverflow)?
}
MappingPhase::Mapped => {
observed_mapped = observed_mapped
.checked_add(1)
.ok_or(RuntimeAllocationError::CounterOverflow)?
}
MappingPhase::PendingTlb => {
observed_pending_tlb = observed_pending_tlb
.checked_add(1)
.ok_or(RuntimeAllocationError::CounterOverflow)?
}
}
}
let mut observed_kernel_accesses = 0u64;
let mut observed_scrub_accesses = 0u64;
for (index, access) in self.ledger.accesses.iter().copied().enumerate() {
if !access.active {
if access != AccessRecord::EMPTY {
return Err(RuntimeAllocationError::InvariantViolation);
}
continue;
}
if access.generation == 0
|| access.generation > self.ledger.last_access_generation
|| access.owner.instance_epoch != self.instance_epoch
|| !kernel_access_descriptor_is_valid(access.descriptor)
|| self.ledger.accesses[index + 1..].iter().any(|other| {
other.active
&& (other.generation == access.generation
|| other.descriptor == access.descriptor)
})
{
return Err(RuntimeAllocationError::InvariantViolation);
}
let allocation = self
.allocation_record_by_generation(access.allocation_generation)
.map(|(_, record)| record)
.ok_or(RuntimeAllocationError::InvariantViolation)?;
if allocation.owner != access.owner
|| !kernel_access_range_is_valid(access.descriptor, allocation.frame_count)
{
return Err(RuntimeAllocationError::InvariantViolation);
}
match access.kind {
AccessKind::Kernel => {
if access.descriptor.purpose == KernelAccessPurpose::Scrub
|| allocation.scrub_in_progress
{
return Err(RuntimeAllocationError::InvariantViolation);
}
observed_kernel_accesses = observed_kernel_accesses
.checked_add(1)
.ok_or(RuntimeAllocationError::CounterOverflow)?;
}
AccessKind::Scrub { scrub_generation } => {
if scrub_generation == 0
|| !allocation.scrub_in_progress
|| allocation.scrub_generation != scrub_generation
|| allocation.scrub_access_completed
|| access.descriptor.purpose != KernelAccessPurpose::Scrub
|| access.descriptor.permissions != KernelAccessPermissions::ReadWrite
|| access.descriptor.frame_offset != 0
|| access.descriptor.frame_count != allocation.frame_count
{
return Err(RuntimeAllocationError::InvariantViolation);
}
observed_scrub_accesses = observed_scrub_accesses
.checked_add(1)
.ok_or(RuntimeAllocationError::CounterOverflow)?;
}
}
}
let mut observed_allocations = 0usize;
let mut observed_retired = 0usize;
let mut observed_frames = 0u64;
let mut observed_pin_references = 0u64;
let mut observed_pinned_frames = 0u64;
let mut observed_scrubs = 0usize;
let mut observed_release_scrubbed = 0usize;
let mut allocation_prepared = 0u64;
let mut allocation_mapped = 0u64;
let mut allocation_pending = 0u64;
let mut allocation_kernel_accesses = 0u64;
let mut allocation_scrub_accesses = 0u64;
for (index, record) in self.ledger.allocations.iter().copied().enumerate() {
if !record.active {
if record != AllocationRecord::EMPTY {
return Err(RuntimeAllocationError::InvariantViolation);
}
continue;
}
if record.generation == 0
|| record.generation > self.ledger.last_allocation_generation
|| record.frame_count == 0
|| record.owner.instance_epoch != self.instance_epoch
{
return Err(RuntimeAllocationError::InvariantViolation);
}
let (_, domain) = self
.domain_record(record.owner.id)
.ok_or(RuntimeAllocationError::InvariantViolation)?;
if record.owner.generation > domain.generation {
return Err(RuntimeAllocationError::InvariantViolation);
}
if record.owner.generation < domain.generation {
observed_retired = observed_retired
.checked_add(1)
.ok_or(RuntimeAllocationError::CounterOverflow)?;
}
if self.ledger.allocations[index + 1..].iter().any(|other| {
other.active
&& (other.generation == record.generation
|| allocation_ranges_overlap(record, *other))
}) {
return Err(RuntimeAllocationError::InvariantViolation);
}
let (pmm_pins, pinned_frames) = self.observed_record_pins(record)?;
let token_pins = u64::try_from(
self.ledger
.pins
.iter()
.filter(|pin| pin.active && pin.allocation_generation == record.generation)
.count(),
)
.map_err(|_| RuntimeAllocationError::CounterOverflow)?;
if pmm_pins != record.pin_references || token_pins != record.pin_references {
return Err(RuntimeAllocationError::InvariantViolation);
}
let record_prepared = count_mapping_phase(
&self.ledger.mappings,
record.generation,
MappingPhase::Prepared,
)?;
let record_mapped = count_mapping_phase(
&self.ledger.mappings,
record.generation,
MappingPhase::Mapped,
)?;
let record_pending = count_mapping_phase(
&self.ledger.mappings,
record.generation,
MappingPhase::PendingTlb,
)?;
let record_kernel_accesses =
count_access_kind(&self.ledger.accesses, record.generation, false)?;
let record_scrub_accesses =
count_access_kind(&self.ledger.accesses, record.generation, true)?;
let mapping_references = record.mapping_references()?;
let access_references = record.access_references()?;
if record_prepared != record.prepared_mappings
|| record_mapped != record.active_mappings
|| record_pending != record.pending_tlb_invalidations
|| record_kernel_accesses != record.kernel_access_references
|| record_scrub_accesses != record.scrub_access_references
|| (record.release_scrubbed
&& (record.pin_references != 0
|| mapping_references != 0
|| record.scrub_in_progress))
|| (record.scrub_in_progress
&& (record.scrub_generation == 0
|| record.scrub_generation > self.ledger.last_scrub_generation
|| record.release_scrubbed
|| record.pin_references != 0
|| mapping_references != 0
|| record.kernel_access_references != 0
|| (record.scrub_access_completed && record.scrub_access_references != 0)
|| self.ledger.allocations[index + 1..].iter().any(|other| {
other.active
&& other.scrub_in_progress
&& other.scrub_generation == record.scrub_generation
})))
|| (!record.scrub_in_progress
&& (record.scrub_generation != 0
|| record.scrub_access_completed
|| record.scrub_access_references != 0))
|| (record.owner.generation < domain.generation
&& (!record.release_scrubbed
|| record.pin_references != 0
|| mapping_references != 0
|| access_references != 0
|| record.scrub_in_progress))
{
return Err(RuntimeAllocationError::InvariantViolation);
}
observed_allocations = observed_allocations
.checked_add(1)
.ok_or(RuntimeAllocationError::CounterOverflow)?;
observed_frames = observed_frames
.checked_add(
u64::try_from(record.frame_count)
.map_err(|_| RuntimeAllocationError::CounterOverflow)?,
)
.ok_or(RuntimeAllocationError::CounterOverflow)?;
observed_pin_references = observed_pin_references
.checked_add(record.pin_references)
.ok_or(RuntimeAllocationError::CounterOverflow)?;
observed_pinned_frames = observed_pinned_frames
.checked_add(pinned_frames)
.ok_or(RuntimeAllocationError::CounterOverflow)?;
allocation_prepared = allocation_prepared
.checked_add(record.prepared_mappings)
.ok_or(RuntimeAllocationError::CounterOverflow)?;
allocation_mapped = allocation_mapped
.checked_add(record.active_mappings)
.ok_or(RuntimeAllocationError::CounterOverflow)?;
allocation_pending = allocation_pending
.checked_add(record.pending_tlb_invalidations)
.ok_or(RuntimeAllocationError::CounterOverflow)?;
allocation_kernel_accesses = allocation_kernel_accesses
.checked_add(record.kernel_access_references)
.ok_or(RuntimeAllocationError::CounterOverflow)?;
allocation_scrub_accesses = allocation_scrub_accesses
.checked_add(record.scrub_access_references)
.ok_or(RuntimeAllocationError::CounterOverflow)?;
if record.scrub_in_progress {
observed_scrubs = observed_scrubs
.checked_add(1)
.ok_or(RuntimeAllocationError::CounterOverflow)?;
}
if record.release_scrubbed {
observed_release_scrubbed = observed_release_scrubbed
.checked_add(1)
.ok_or(RuntimeAllocationError::CounterOverflow)?;
}
}
if observed_allocations != self.ledger.active_allocations
|| observed_retired != self.ledger.retired_allocations
|| observed_frames != pmm.allocated_frames
|| observed_pin_references != observed_pin_records
|| observed_pin_references != self.ledger.pin_references
|| observed_pin_references != pmm.pin_references
|| observed_pinned_frames != pmm.pinned_frames
|| observed_prepared != allocation_prepared
|| observed_prepared != self.ledger.prepared_mappings
|| observed_mapped != allocation_mapped
|| observed_mapped != self.ledger.active_mappings
|| observed_pending_tlb != allocation_pending
|| observed_pending_tlb != self.ledger.pending_tlb_invalidations
|| observed_kernel_accesses != allocation_kernel_accesses
|| observed_kernel_accesses != self.ledger.kernel_access_references
|| observed_scrub_accesses != allocation_scrub_accesses
|| observed_scrub_accesses != self.ledger.scrub_access_references
|| observed_scrubs != self.ledger.scrubs_in_progress
|| observed_release_scrubbed != self.ledger.release_scrubbed_allocations
{
return Err(RuntimeAllocationError::InvariantViolation);
}
Ok(snapshot)
}
/// Reconcile every live ownership record with the authoritative PMM and
/// aggregate it into the closed MEM0 class vocabulary.
pub fn audited_reconciliation(
&self,
) -> Result<RuntimeMemoryReconciliationSnapshot, RuntimeAllocationError> {
let memory = self.audited_snapshot()?;
let mut classes = [RuntimeMemoryClassSnapshot::default(); RUNTIME_MEMORY_CLASS_COUNT];
for record in self
.ledger
.allocations
.iter()
.copied()
.filter(|record| record.active)
{
let (_, domain) = self
.domain_record(record.owner.id)
.ok_or(RuntimeAllocationError::InvariantViolation)?;
let (_, pinned_frames) = self.observed_record_pins(record)?;
accumulate_class_snapshot(
&mut classes[record.class.index()],
record,
pinned_frames,
record.owner.generation < domain.generation,
)?;
}
let snapshot = RuntimeMemoryReconciliationSnapshot { memory, classes };
if !snapshot.is_consistent() {
return Err(RuntimeAllocationError::InvariantViolation);
}
Ok(snapshot)
}
/// Strict MEM0 gate: physical reconciliation alone is insufficient while
/// any live allocation remains in the compatibility bucket.
pub fn audited_mem0_reconciliation(
&self,
) -> Result<RuntimeMemoryReconciliationSnapshot, RuntimeAllocationError> {
let snapshot = self.audited_reconciliation()?;
let unclassified = snapshot.class(RuntimeMemoryClass::Unclassified);
if unclassified != RuntimeMemoryClassSnapshot::default() {
return Err(RuntimeAllocationError::UnclassifiedAllocations {
allocations: unclassified.allocations,
frames: unclassified.frames,
});
}
Ok(snapshot)
}
/// Rebuild one quota domain's current and retired ownership without
/// exposing the underlying allocation records or raw PMM.
pub fn audited_domain_memory(
&self,
current: AllocationDomain,
) -> Result<RuntimeDomainMemorySnapshot, RuntimeAllocationError> {
self.validate_current_domain(current)?;
self.audited_snapshot()?;
let mut classes = [RuntimeMemoryClassSnapshot::default(); RUNTIME_MEMORY_CLASS_COUNT];
for record in self.ledger.allocations.iter().copied().filter(|record| {
record.active
&& record.owner.instance_epoch == current.instance_epoch
&& record.owner.id == current.id
}) {
let (_, pinned_frames) = self.observed_record_pins(record)?;
accumulate_class_snapshot(
&mut classes[record.class.index()],
record,
pinned_frames,
record.owner.generation < current.generation,
)?;
}
let snapshot = RuntimeDomainMemorySnapshot {
domain: current,
classes,
};
if !snapshot.is_consistent() {
return Err(RuntimeAllocationError::InvariantViolation);
}
Ok(snapshot)
}
/// Reconcile one domain's hard limit against its current and retired
/// physical ownership. This derives usage from allocation records instead
/// of trusting a second mutable quota counter.
pub fn audited_domain_quota(
&self,
current: AllocationDomain,
) -> Result<RuntimeDomainQuotaSnapshot, RuntimeAllocationError> {
let memory = self.audited_domain_memory(current)?;
let (_, domain) = self
.domain_record(current.id)
.ok_or(RuntimeAllocationError::InvariantViolation)?;
let mut allocated_frames = 0u64;
let mut retired_frames = 0u64;
let mut pinned_frames = 0u64;
let mut pin_references = 0u64;
for class in memory.classes {
allocated_frames = allocated_frames
.checked_add(class.frames)
.ok_or(RuntimeAllocationError::CounterOverflow)?;
pinned_frames = pinned_frames
.checked_add(class.pinned_frames)
.ok_or(RuntimeAllocationError::CounterOverflow)?;
pin_references = pin_references
.checked_add(class.pin_references)
.ok_or(RuntimeAllocationError::CounterOverflow)?;
}
for record in self.ledger.allocations.iter().copied().filter(|record| {
record.active
&& record.owner.instance_epoch == current.instance_epoch
&& record.owner.id == current.id
&& record.owner.generation < current.generation
}) {
retired_frames = retired_frames
.checked_add(
u64::try_from(record.frame_count)
.map_err(|_| RuntimeAllocationError::CounterOverflow)?,
)
.ok_or(RuntimeAllocationError::CounterOverflow)?;
}
if allocated_frames != self.domain_allocated_frames(current.id)? {
return Err(RuntimeAllocationError::InvariantViolation);
}
let remaining_frames = domain
.hard_limit_frames
.checked_sub(allocated_frames)
.ok_or(RuntimeAllocationError::InvariantViolation)?;
let snapshot = RuntimeDomainQuotaSnapshot {
domain: current,
hard_limit_frames: domain.hard_limit_frames,
allocated_frames,
remaining_frames,
retired_frames,
pinned_frames,
pin_references,
};
if !snapshot.is_consistent() {
return Err(RuntimeAllocationError::InvariantViolation);
}
Ok(snapshot)
}
/// Resolve one physical frame to its exact domain/allocation/class only
/// after a complete ledger/PMM audit. Orphan allocated frames and records
/// covering free or reserved PMM entries are rejected fail-closed.
pub fn audited_frame_ownership(
&self,
address: PhysAddr,
) -> Result<RuntimeFrameOwnership, RuntimeAllocationError> {
self.audited_snapshot()?;
let state = self
.pmm
.frame_state(address)
.map_err(RuntimeAllocationError::Pmm)?;
let mut matched = None;
for record in self
.ledger
.allocations
.iter()
.copied()
.filter(|record| record.active && allocation_contains_address(*record, address))
{
if matched.replace(record).is_some() {
return Err(RuntimeAllocationError::InvariantViolation);
}
}
match (state, matched) {
(RuntimeFrameState::Free, None) => Ok(RuntimeFrameOwnership::Free),
(RuntimeFrameState::Reserved, None) => Ok(RuntimeFrameOwnership::Reserved),
(RuntimeFrameState::Allocated { pin_count }, Some(record)) => {
let frame_offset = usize::try_from(
(address.as_u64() - record.start.as_u64()) / RUNTIME_FRAME_SIZE,
)
.map_err(|_| RuntimeAllocationError::CounterOverflow)?;
let (_, domain) = self
.domain_record(record.owner.id)
.ok_or(RuntimeAllocationError::InvariantViolation)?;
Ok(RuntimeFrameOwnership::Owned {
owner: record.owner,
allocation_generation: record.generation,
class: record.class,
frame_offset,
pin_count,
retired: record.owner.generation < domain.generation,
})
}
_ => Err(RuntimeAllocationError::InvariantViolation),
}
}
/// Preflight an exact, empty shutdown without consuming the state.
pub fn shutdown_readiness(&self) -> Result<(), RuntimeAllocationError> {
let snapshot = self.audited_snapshot()?;
let mapping_references = snapshot
.prepared_mappings
.checked_add(snapshot.active_mappings)
.and_then(|value| value.checked_add(snapshot.pending_tlb_invalidations))
.ok_or(RuntimeAllocationError::CounterOverflow)?;
let access_references = snapshot
.kernel_access_references
.checked_add(snapshot.scrub_access_references)
.ok_or(RuntimeAllocationError::CounterOverflow)?;
if snapshot.active_allocations != 0
|| snapshot.pmm.allocated_frames != 0
|| snapshot.pin_references != 0
|| mapping_references != 0
|| access_references != 0
|| snapshot.scrubs_in_progress != 0
{
return Err(RuntimeAllocationError::ShutdownBusy {
active_allocations: snapshot.active_allocations,
pin_references: snapshot.pin_references,
mapping_references,
access_references,
scrubs_in_progress: snapshot.scrubs_in_progress,
});
}
Ok(())
}
/// Return the inventory only after an exact, empty audit.
///
/// Call [`Self::shutdown_readiness`] first if an outstanding lifecycle must
/// be recoverable. A failure here consumes the state and loses its inventory
/// fail-closed, avoiding a heap allocation or a 60-KiB error value.
pub fn try_shutdown(self) -> Result<RuntimeMemoryInventory, RuntimeAllocationError> {
self.shutdown_readiness()?;
let Self {
inventory,
pmm: _,
ledger: _,
instance_epoch: _,
} = self;
Ok(inventory)
}
/// Compatibility registration with a hard limit equal to the complete
/// allocatable inventory. Production domains can select a smaller limit
/// through [`Self::register_domain_with_quota`].
pub fn register_domain(&mut self, id: u32) -> Result<AllocationDomain, RuntimeAllocationError> {
let allocatable_frames = self.allocatable_frame_capacity()?;
self.register_domain_with_quota(id, allocatable_frames)
}
/// Register one quota domain. The limit is immutable across generation
/// rotation and cannot exceed the physical inventory governed by this
/// runtime authority.
pub fn register_domain_with_quota(
&mut self,
id: u32,
hard_limit_frames: u64,
) -> Result<AllocationDomain, RuntimeAllocationError> {
if hard_limit_frames == 0 {
return Err(RuntimeAllocationError::EmptyDomainQuota);
}
let allocatable_frames = self.allocatable_frame_capacity()?;
if hard_limit_frames > allocatable_frames {
return Err(RuntimeAllocationError::DomainQuotaExceedsInventory {
hard_limit_frames,
allocatable_frames,
});
}
if self.domain_record(id).is_some() {
return Err(RuntimeAllocationError::DomainAlreadyRegistered);
}
let index = self
.ledger
.domains
.iter()
.position(|record| !record.occupied)
.ok_or(RuntimeAllocationError::DomainCapacity)?;
let registered_domains = self
.ledger
.registered_domains
.checked_add(1)
.ok_or(RuntimeAllocationError::CounterOverflow)?;
let authority = AllocationDomain {
instance_epoch: self.instance_epoch,
id,
generation: 1,
};
self.ledger.domains[index] = DomainRecord {
id,
generation: authority.generation,
hard_limit_frames,
occupied: true,
};
self.ledger.registered_domains = registered_domains;
Ok(authority)
}
/// Validate that a copied domain handle is current for this exact state.
/// This exposes no allocator or ledger mutation authority.
pub fn validate_domain_authority(
&self,
current: AllocationDomain,
) -> Result<(), RuntimeAllocationError> {
self.validate_current_domain(current).map(|_| ())
}
/// Retire only allocations already unreferenced and release-scrubbed.
pub fn rotate_domain(
&mut self,
current: AllocationDomain,
) -> Result<AllocationDomain, RuntimeAllocationError> {
let domain_index = self.validate_current_domain(current)?;
let next_generation = current
.generation
.checked_add(1)
.ok_or(RuntimeAllocationError::DomainGenerationOverflow)?;
let mut pins = 0u64;
let mut mapping_references = 0u64;
let mut access_references = 0u64;
let mut scrubs = 0usize;
let mut dirty = 0usize;
let mut newly_retired = 0usize;
for record in self.ledger.allocations.iter().copied().filter(|record| {
record.active
&& record.owner.instance_epoch == self.instance_epoch
&& record.owner.id == current.id
}) {
let (observed_pins, _) = self.observed_record_pins(record)?;
if observed_pins != record.pin_references {
return Err(RuntimeAllocationError::InvariantViolation);
}
pins = pins
.checked_add(observed_pins)
.ok_or(RuntimeAllocationError::CounterOverflow)?;
mapping_references = mapping_references
.checked_add(record.mapping_references()?)
.ok_or(RuntimeAllocationError::CounterOverflow)?;
access_references = access_references
.checked_add(record.access_references()?)
.ok_or(RuntimeAllocationError::CounterOverflow)?;
if record.scrub_in_progress {
scrubs = scrubs
.checked_add(1)
.ok_or(RuntimeAllocationError::CounterOverflow)?;
}
if !record.release_scrubbed {
dirty = dirty
.checked_add(1)
.ok_or(RuntimeAllocationError::CounterOverflow)?;
}
if record.owner.generation == current.generation {
newly_retired = newly_retired
.checked_add(1)
.ok_or(RuntimeAllocationError::CounterOverflow)?;
} else if record.owner.generation > current.generation {
return Err(RuntimeAllocationError::InvariantViolation);
}
}
if pins != 0 {
return Err(RuntimeAllocationError::DomainPinned {
domain_id: current.id,
pin_references: pins,
});
}
if mapping_references != 0 || access_references != 0 || scrubs != 0 || dirty != 0 {
return Err(RuntimeAllocationError::DomainLifecycleIncomplete {
domain_id: current.id,
mapping_references,
access_references,
scrubs_in_progress: scrubs,
dirty_allocations: dirty,
});
}
let retired = self
.ledger
.retired_allocations
.checked_add(newly_retired)
.ok_or(RuntimeAllocationError::CounterOverflow)?;
self.ledger.domains[domain_index].generation = next_generation;
self.ledger.retired_allocations = retired;
Ok(AllocationDomain {
instance_epoch: self.instance_epoch,
id: current.id,
generation: next_generation,
})
}
pub fn allocate(
&mut self,
current: AllocationDomain,
frame_count: usize,
) -> Result<AllocationToken, RuntimeAllocationError> {
self.allocate_classified(current, RuntimeMemoryClass::Unclassified, frame_count)
}
/// Allocate one exact run and bind its complete frame range to both the
/// quota domain and a closed MEM0 resource class before publication.
pub fn allocate_classified(
&mut self,
current: AllocationDomain,
class: RuntimeMemoryClass,
frame_count: usize,
) -> Result<AllocationToken, RuntimeAllocationError> {
let domain_index = self.validate_current_domain(current)?;
if frame_count == 0 {
return Err(RuntimeAllocationError::Pmm(RuntimePmmError::ZeroFrameCount));
}
let requested_frames =
u64::try_from(frame_count).map_err(|_| RuntimeAllocationError::CounterOverflow)?;
// Preserve the physical allocator boundary when both global exhaustion
// and a domain limit would reject the same request. No PMM mutation is
// needed to prove that a request larger than the total free count
// cannot be satisfied contiguously.
if requested_frames > self.pmm.snapshot().free_frames {
return Err(RuntimeAllocationError::Pmm(RuntimePmmError::OutOfMemory));
}
let allocated_frames = self.domain_allocated_frames(current.id)?;
let hard_limit_frames = self.ledger.domains[domain_index].hard_limit_frames;
let charged_frames = allocated_frames
.checked_add(requested_frames)
.ok_or(RuntimeAllocationError::CounterOverflow)?;
if charged_frames > hard_limit_frames {
return Err(RuntimeAllocationError::DomainQuotaExceeded {
domain_id: current.id,
hard_limit_frames,
allocated_frames,
requested_frames,
});
}
let record_index = self
.ledger
.allocations
.iter()
.position(|record| !record.active)
.ok_or(RuntimeAllocationError::AllocationCapacity)?;
let generation = self
.ledger
.last_allocation_generation
.checked_add(1)
.ok_or(RuntimeAllocationError::AllocationGenerationOverflow)?;
let active = self
.ledger
.active_allocations
.checked_add(1)
.ok_or(RuntimeAllocationError::CounterOverflow)?;
let run = self
.pmm
.allocate_contiguous(frame_count)
.map_err(RuntimeAllocationError::Pmm)?;
self.ledger.allocations[record_index] = AllocationRecord {
generation,
owner: current,
class,
start: run.start_address(),
frame_count: run.frame_count(),
pin_references: 0,
prepared_mappings: 0,
active_mappings: 0,
pending_tlb_invalidations: 0,
kernel_access_references: 0,
scrub_access_references: 0,
scrub_generation: 0,
scrub_in_progress: false,
scrub_access_completed: false,
release_scrubbed: false,
active: true,
};
self.ledger.active_allocations = active;
self.ledger.last_allocation_generation = generation;
Ok(AllocationToken {
run,
owner: current,
allocation_generation: generation,
class,
state: AuthorityState::Live,
})
}
pub fn free(
&mut self,
current: AllocationDomain,
token: &mut AllocationToken,
) -> Result<(), RuntimeAllocationError> {
self.validate_live_token(current, token)?;
let index = self.validate_allocation_record(token)?;
let record = self.ledger.allocations[index];
self.ensure_release_ready(record)?;
let active = self
.ledger
.active_allocations
.checked_sub(1)
.ok_or(RuntimeAllocationError::InvariantViolation)?;
let scrubbed = self
.ledger
.release_scrubbed_allocations
.checked_sub(1)
.ok_or(RuntimeAllocationError::InvariantViolation)?;
self.pmm
.free_contiguous(record.start, record.frame_count)
.map_err(RuntimeAllocationError::Pmm)?;
self.ledger.allocations[index] = AllocationRecord::EMPTY;
self.ledger.active_allocations = active;
self.ledger.release_scrubbed_allocations = scrubbed;
token.state = AuthorityState::Consumed;
Ok(())
}
/// Create exact ownership of one pin reference.
pub fn pin(
&mut self,
current: AllocationDomain,
token: &AllocationToken,
frame_offset: usize,
) -> Result<PinToken, RuntimeAllocationError> {
self.validate_live_token(current, token)?;
let allocation_index = self.validate_allocation_record(token)?;
let allocation = self.ledger.allocations[allocation_index];
if allocation.scrub_in_progress {
return Err(lifecycle_busy(allocation));
}
let address = token.frame_address(frame_offset)?;
let pin_index = self
.ledger
.pins
.iter()
.position(|record| !record.active)
.ok_or(RuntimeAllocationError::PinCapacity)?;
let generation = self
.ledger
.last_pin_generation
.checked_add(1)
.ok_or(RuntimeAllocationError::PinGenerationOverflow)?;
let allocation_pins = allocation
.pin_references
.checked_add(1)
.ok_or(RuntimeAllocationError::CounterOverflow)?;
let ledger_pins = self
.ledger
.pin_references
.checked_add(1)
.ok_or(RuntimeAllocationError::CounterOverflow)?;
let scrubbed = if allocation.release_scrubbed {
self.ledger
.release_scrubbed_allocations
.checked_sub(1)
.ok_or(RuntimeAllocationError::InvariantViolation)?
} else {
self.ledger.release_scrubbed_allocations
};
self.pmm
.pin_frame(address)
.map_err(RuntimeAllocationError::Pmm)?;
self.ledger.pins[pin_index] = PinRecord {
generation,
owner: current,
allocation_generation: token.allocation_generation,
frame_offset,
active: true,
};
self.ledger.allocations[allocation_index].pin_references = allocation_pins;
self.ledger.allocations[allocation_index].release_scrubbed = false;
self.ledger.pin_references = ledger_pins;
self.ledger.release_scrubbed_allocations = scrubbed;
self.ledger.last_pin_generation = generation;
Ok(PinToken {
owner: current,
allocation_generation: token.allocation_generation,
pin_generation: generation,
frame_offset,
state: AuthorityState::Live,
})
}
/// # Safety
/// The external user represented by this exact pin must no longer access
/// the frame. The allocation remains dirty until a final scrub.
pub unsafe fn unpin(
&mut self,
current: AllocationDomain,
token: &AllocationToken,
pin: &mut PinToken,
) -> Result<(), RuntimeAllocationError> {
self.validate_live_token(current, token)?;
let allocation_index = self.validate_allocation_record(token)?;
let pin_index = self.validate_pin_record(token, pin)?;
let allocation = self.ledger.allocations[allocation_index];
if allocation.access_references()? != 0 {
return Err(lifecycle_busy(allocation));
}
let allocation_pins = self.ledger.allocations[allocation_index]
.pin_references
.checked_sub(1)
.ok_or(RuntimeAllocationError::InvariantViolation)?;
let ledger_pins = self
.ledger
.pin_references
.checked_sub(1)
.ok_or(RuntimeAllocationError::InvariantViolation)?;
let address = token.frame_address(pin.frame_offset)?;
self.pmm
.unpin_frame(address)
.map_err(RuntimeAllocationError::Pmm)?;
self.ledger.pins[pin_index] = PinRecord::EMPTY;
self.ledger.allocations[allocation_index].pin_references = allocation_pins;
self.ledger.pin_references = ledger_pins;
pin.state = AuthorityState::Consumed;
Ok(())
}
/// Reserve ledger space before page-table mutation.
pub fn prepare_mapping(
&mut self,
current: AllocationDomain,
token: &AllocationToken,
descriptor: MappingDescriptor,
) -> Result<MappingToken, RuntimeAllocationError> {
self.validate_live_token(current, token)?;
let allocation_index = self.validate_allocation_record(token)?;
let allocation = self.ledger.allocations[allocation_index];
if !mapping_descriptor_is_valid(descriptor) {
return Err(RuntimeAllocationError::InvalidMappingDescriptor);
}
if descriptor.page_count != allocation.frame_count {
return Err(RuntimeAllocationError::MappingPageCountMismatch {
allocation_frames: allocation.frame_count,
mapping_pages: descriptor.page_count,
});
}
if allocation.scrub_in_progress || allocation.pending_tlb_invalidations != 0 {
return Err(lifecycle_busy(allocation));
}
if allocation.prepared_mappings == 0
&& allocation.active_mappings == 0
&& !allocation.release_scrubbed
{
return Err(RuntimeAllocationError::AllocationNeedsScrub {
allocation_generation: allocation.generation,
});
}
if self
.ledger
.mappings
.iter()
.any(|mapping| mapping.active && mapping.descriptor == descriptor)
{
return Err(RuntimeAllocationError::MappingAlreadyExists);
}
let mapping_index = self
.ledger
.mappings
.iter()
.position(|record| !record.active)
.ok_or(RuntimeAllocationError::MappingCapacity)?;
let generation = self
.ledger
.last_mapping_generation
.checked_add(1)
.ok_or(RuntimeAllocationError::MappingGenerationOverflow)?;
let allocation_prepared = allocation
.prepared_mappings
.checked_add(1)
.ok_or(RuntimeAllocationError::CounterOverflow)?;
let ledger_prepared = self
.ledger
.prepared_mappings
.checked_add(1)
.ok_or(RuntimeAllocationError::CounterOverflow)?;
let scrubbed = if allocation.release_scrubbed {
self.ledger
.release_scrubbed_allocations
.checked_sub(1)
.ok_or(RuntimeAllocationError::InvariantViolation)?
} else {
self.ledger.release_scrubbed_allocations
};
self.ledger.mappings[mapping_index] = MappingRecord {
generation,
owner: current,
allocation_generation: token.allocation_generation,
descriptor,
phase: MappingPhase::Prepared,
active: true,
};
self.ledger.allocations[allocation_index].prepared_mappings = allocation_prepared;
self.ledger.allocations[allocation_index].release_scrubbed = false;
self.ledger.prepared_mappings = ledger_prepared;
self.ledger.release_scrubbed_allocations = scrubbed;
self.ledger.last_mapping_generation = generation;
Ok(MappingToken {
owner: current,
allocation_generation: token.allocation_generation,
mapping_generation: generation,
descriptor,
phase: MappingTokenPhase::Prepared,
})
}
/// # Safety
/// The complete mapping must be installed with the required permissions and
/// publication barriers, after its reservation was created.
pub unsafe fn confirm_mapping(
&mut self,
current: AllocationDomain,
token: &AllocationToken,
mapping: &mut MappingToken,
) -> Result<(), RuntimeAllocationError> {
self.validate_live_token(current, token)?;
let allocation_index = self.validate_allocation_record(token)?;
let mapping_index = self.validate_mapping_record(token, mapping, MappingPhase::Prepared)?;
let allocation_prepared = self.ledger.allocations[allocation_index]
.prepared_mappings
.checked_sub(1)
.ok_or(RuntimeAllocationError::InvariantViolation)?;
let allocation_mapped = self.ledger.allocations[allocation_index]
.active_mappings
.checked_add(1)
.ok_or(RuntimeAllocationError::CounterOverflow)?;
let ledger_prepared = self
.ledger
.prepared_mappings
.checked_sub(1)
.ok_or(RuntimeAllocationError::InvariantViolation)?;
let ledger_mapped = self
.ledger
.active_mappings
.checked_add(1)
.ok_or(RuntimeAllocationError::CounterOverflow)?;
self.ledger.mappings[mapping_index].phase = MappingPhase::Mapped;
self.ledger.allocations[allocation_index].prepared_mappings = allocation_prepared;
self.ledger.allocations[allocation_index].active_mappings = allocation_mapped;
self.ledger.prepared_mappings = ledger_prepared;
self.ledger.active_mappings = ledger_mapped;
mapping.phase = MappingTokenPhase::Mapped;
Ok(())
}
pub fn cancel_prepared_mapping(
&mut self,
current: AllocationDomain,
token: &AllocationToken,
mapping: &mut MappingToken,
) -> Result<(), RuntimeAllocationError> {
self.validate_live_token(current, token)?;
let allocation_index = self.validate_allocation_record(token)?;
let mapping_index = self.validate_mapping_record(token, mapping, MappingPhase::Prepared)?;
let allocation_prepared = self.ledger.allocations[allocation_index]
.prepared_mappings
.checked_sub(1)
.ok_or(RuntimeAllocationError::InvariantViolation)?;
let ledger_prepared = self
.ledger
.prepared_mappings
.checked_sub(1)
.ok_or(RuntimeAllocationError::InvariantViolation)?;
self.ledger.mappings[mapping_index] = MappingRecord::EMPTY;
self.ledger.allocations[allocation_index].prepared_mappings = allocation_prepared;
self.ledger.prepared_mappings = ledger_prepared;
mapping.phase = MappingTokenPhase::Consumed;
Ok(())
}
/// # Safety
/// Every PTE represented by `mapping` must already be invalid with the
/// required page-table update barriers.
pub unsafe fn begin_unmap(
&mut self,
current: AllocationDomain,
token: &AllocationToken,
mapping: &mut MappingToken,
) -> Result<TlbInvalidationToken, RuntimeAllocationError> {
self.validate_live_token(current, token)?;
let allocation_index = self.validate_allocation_record(token)?;
let mapping_index = self.validate_mapping_record(token, mapping, MappingPhase::Mapped)?;
let allocation_mapped = self.ledger.allocations[allocation_index]
.active_mappings
.checked_sub(1)
.ok_or(RuntimeAllocationError::InvariantViolation)?;
let allocation_pending = self.ledger.allocations[allocation_index]
.pending_tlb_invalidations
.checked_add(1)
.ok_or(RuntimeAllocationError::CounterOverflow)?;
let ledger_mapped = self
.ledger
.active_mappings
.checked_sub(1)
.ok_or(RuntimeAllocationError::InvariantViolation)?;
let ledger_pending = self
.ledger
.pending_tlb_invalidations
.checked_add(1)
.ok_or(RuntimeAllocationError::CounterOverflow)?;
self.ledger.mappings[mapping_index].phase = MappingPhase::PendingTlb;
self.ledger.allocations[allocation_index].active_mappings = allocation_mapped;
self.ledger.allocations[allocation_index].pending_tlb_invalidations = allocation_pending;
self.ledger.active_mappings = ledger_mapped;
self.ledger.pending_tlb_invalidations = ledger_pending;
mapping.phase = MappingTokenPhase::Consumed;
Ok(TlbInvalidationToken {
owner: mapping.owner,
allocation_generation: mapping.allocation_generation,
mapping_generation: mapping.mapping_generation,
descriptor: mapping.descriptor,
state: AuthorityState::Live,
})
}
/// # Safety
/// All required local/remote TLBI and ordering barriers for the descriptor
/// must be durably complete.
pub unsafe fn complete_tlb_invalidation(
&mut self,
current: AllocationDomain,
token: &AllocationToken,
tlb: &mut TlbInvalidationToken,
) -> Result<(), RuntimeAllocationError> {
self.validate_live_token(current, token)?;
let allocation_index = self.validate_allocation_record(token)?;
let mapping_index = self.validate_tlb_record(token, tlb)?;
let allocation_pending = self.ledger.allocations[allocation_index]
.pending_tlb_invalidations
.checked_sub(1)
.ok_or(RuntimeAllocationError::InvariantViolation)?;
let ledger_pending = self
.ledger
.pending_tlb_invalidations
.checked_sub(1)
.ok_or(RuntimeAllocationError::InvariantViolation)?;
self.ledger.mappings[mapping_index] = MappingRecord::EMPTY;
self.ledger.allocations[allocation_index].pending_tlb_invalidations = allocation_pending;
self.ledger.pending_tlb_invalidations = ledger_pending;
tlb.state = AuthorityState::Consumed;
Ok(())
}
/// Reserve a bounded temporary kernel mapping before mutating page tables.
/// Dirty and pinned allocations are accepted; the exact linear reference
/// still prevents unpin, scrub, release, and domain rotation until closed.
pub fn prepare_kernel_access(
&mut self,
current: AllocationDomain,
token: &AllocationToken,
descriptor: KernelAccessDescriptor,
) -> Result<KernelAccessToken, RuntimeAllocationError> {
self.validate_live_token(current, token)?;
let allocation_index = self.validate_allocation_record(token)?;
let allocation = self.ledger.allocations[allocation_index];
if !kernel_access_descriptor_is_valid(descriptor) {
return Err(RuntimeAllocationError::InvalidKernelAccessDescriptor);
}
if descriptor.purpose == KernelAccessPurpose::Scrub {
return Err(RuntimeAllocationError::InvalidKernelAccessPurpose);
}
validate_kernel_access_range(descriptor, allocation.frame_count)?;
if allocation.scrub_in_progress {
return Err(lifecycle_busy(allocation));
}
if self
.ledger
.accesses
.iter()
.any(|access| access.active && access.descriptor == descriptor)
{
return Err(RuntimeAllocationError::KernelAccessAlreadyExists);
}
let access_index = self
.ledger
.accesses
.iter()
.position(|record| !record.active)
.ok_or(RuntimeAllocationError::AccessCapacity)?;
let generation = self
.ledger
.last_access_generation
.checked_add(1)
.ok_or(RuntimeAllocationError::AccessGenerationOverflow)?;
let allocation_accesses = allocation
.kernel_access_references
.checked_add(1)
.ok_or(RuntimeAllocationError::CounterOverflow)?;
let ledger_accesses = self
.ledger
.kernel_access_references
.checked_add(1)
.ok_or(RuntimeAllocationError::CounterOverflow)?;
let scrubbed = if descriptor.permissions == KernelAccessPermissions::ReadWrite
&& allocation.release_scrubbed
{
self.ledger
.release_scrubbed_allocations
.checked_sub(1)
.ok_or(RuntimeAllocationError::InvariantViolation)?
} else {
self.ledger.release_scrubbed_allocations
};
let physical_start = token.frame_address(descriptor.frame_offset)?;
self.ledger.accesses[access_index] = AccessRecord {
generation,
owner: current,
allocation_generation: token.allocation_generation,
descriptor,
kind: AccessKind::Kernel,
phase: AccessPhase::Prepared,
active: true,
};
self.ledger.allocations[allocation_index].kernel_access_references = allocation_accesses;
if descriptor.permissions == KernelAccessPermissions::ReadWrite {
self.ledger.allocations[allocation_index].release_scrubbed = false;
}
self.ledger.kernel_access_references = ledger_accesses;
self.ledger.release_scrubbed_allocations = scrubbed;
self.ledger.last_access_generation = generation;
Ok(KernelAccessToken {
owner: current,
allocation_generation: token.allocation_generation,
access_generation: generation,
physical_start,
descriptor,
phase: KernelAccessTokenPhase::Prepared,
})
}
/// # Safety
/// The exact physical subrange and virtual range in `access.descriptor()`
/// must now be mapped with its read/write permission, PXN+UXN, nG, and all
/// required page-table publication barriers. No undeclared alias may have
/// been installed.
pub unsafe fn confirm_kernel_access(
&mut self,
current: AllocationDomain,
token: &AllocationToken,
access: &mut KernelAccessToken,
) -> Result<(), RuntimeAllocationError> {
self.validate_live_token(current, token)?;
self.validate_allocation_record(token)?;
let access_index =
self.validate_kernel_access_record(token, access, AccessPhase::Prepared)?;
self.ledger.accesses[access_index].phase = AccessPhase::Mapped;
access.phase = KernelAccessTokenPhase::Mapped;
Ok(())
}
/// Cancel a reservation which was never installed. Writable reservations
/// remain conservatively dirty and require a scrub before reuse.
pub fn cancel_prepared_kernel_access(
&mut self,
current: AllocationDomain,
token: &AllocationToken,
access: &mut KernelAccessToken,
) -> Result<(), RuntimeAllocationError> {
self.validate_live_token(current, token)?;
let allocation_index = self.validate_allocation_record(token)?;
let access_index =
self.validate_kernel_access_record(token, access, AccessPhase::Prepared)?;
self.retire_kernel_access_record(allocation_index, access_index)?;
access.phase = KernelAccessTokenPhase::Consumed;
Ok(())
}
/// # Safety
/// Every PTE in this exact temporary mapping must already be invalid, and
/// all local/remote TLB invalidations plus ordering barriers must be durably
/// complete. This single-use close is the unmap/TLBI witness.
pub unsafe fn close_kernel_access(
&mut self,
current: AllocationDomain,
token: &AllocationToken,
access: &mut KernelAccessToken,
) -> Result<(), RuntimeAllocationError> {
self.validate_live_token(current, token)?;
let allocation_index = self.validate_allocation_record(token)?;
let access_index =
self.validate_kernel_access_record(token, access, AccessPhase::Mapped)?;
self.retire_kernel_access_record(allocation_index, access_index)?;
access.phase = KernelAccessTokenPhase::Consumed;
Ok(())
}
/// Reserve the exact full-run RW/NX/nG mapping for one live scrub.
pub fn prepare_scrub_access(
&mut self,
current: AllocationDomain,
token: &AllocationToken,
scrub: &ScrubToken,
address_space_generation: u64,
virtual_start: u64,
) -> Result<ScrubAccessToken, RuntimeAllocationError> {
self.validate_live_token(current, token)?;
let allocation_index = self.validate_allocation_record(token)?;
self.validate_scrub_record(token, scrub)?;
let allocation = self.ledger.allocations[allocation_index];
if allocation.scrub_access_completed {
return Err(RuntimeAllocationError::ScrubAccessAlreadyCompleted {
allocation_generation: allocation.generation,
scrub_generation: allocation.scrub_generation,
});
}
if allocation.access_references()? != 0 {
return Err(lifecycle_busy(allocation));
}
let descriptor = KernelAccessDescriptor::try_new(
address_space_generation,
virtual_start,
0,
allocation.frame_count,
KernelAccessPermissions::ReadWrite,
KernelAccessPurpose::Scrub,
true,
)?;
if self
.ledger
.accesses
.iter()
.any(|access| access.active && access.descriptor == descriptor)
{
return Err(RuntimeAllocationError::KernelAccessAlreadyExists);
}
let access_index = self
.ledger
.accesses
.iter()
.position(|record| !record.active)
.ok_or(RuntimeAllocationError::AccessCapacity)?;
let generation = self
.ledger
.last_access_generation
.checked_add(1)
.ok_or(RuntimeAllocationError::AccessGenerationOverflow)?;
let allocation_accesses = allocation
.scrub_access_references
.checked_add(1)
.ok_or(RuntimeAllocationError::CounterOverflow)?;
let ledger_accesses = self
.ledger
.scrub_access_references
.checked_add(1)
.ok_or(RuntimeAllocationError::CounterOverflow)?;
self.ledger.accesses[access_index] = AccessRecord {
generation,
owner: current,
allocation_generation: token.allocation_generation,
descriptor,
kind: AccessKind::Scrub {
scrub_generation: scrub.scrub_generation,
},
phase: AccessPhase::Prepared,
active: true,
};
self.ledger.allocations[allocation_index].scrub_access_references = allocation_accesses;
self.ledger.scrub_access_references = ledger_accesses;
self.ledger.last_access_generation = generation;
Ok(ScrubAccessToken {
owner: current,
allocation_generation: token.allocation_generation,
scrub_generation: scrub.scrub_generation,
access_generation: generation,
physical_start: token.start_address(),
descriptor,
phase: KernelAccessTokenPhase::Prepared,
})
}
/// # Safety
/// The exact full allocation must now be mapped RW, PXN+UXN, nG at the
/// descriptor virtual range with all page-table publication barriers.
pub unsafe fn confirm_scrub_access(
&mut self,
current: AllocationDomain,
token: &AllocationToken,
scrub: &ScrubToken,
access: &mut ScrubAccessToken,
) -> Result<(), RuntimeAllocationError> {
self.validate_live_token(current, token)?;
self.validate_allocation_record(token)?;
self.validate_scrub_record(token, scrub)?;
let access_index =
self.validate_scrub_access_record(token, scrub, access, AccessPhase::Prepared)?;
self.ledger.accesses[access_index].phase = AccessPhase::Mapped;
access.phase = KernelAccessTokenPhase::Mapped;
Ok(())
}
pub fn cancel_prepared_scrub_access(
&mut self,
current: AllocationDomain,
token: &AllocationToken,
scrub: &ScrubToken,
access: &mut ScrubAccessToken,
) -> Result<(), RuntimeAllocationError> {
self.validate_live_token(current, token)?;
let allocation_index = self.validate_allocation_record(token)?;
self.validate_scrub_record(token, scrub)?;
let access_index =
self.validate_scrub_access_record(token, scrub, access, AccessPhase::Prepared)?;
self.retire_scrub_access_record(allocation_index, access_index)?;
access.phase = KernelAccessTokenPhase::Consumed;
Ok(())
}
/// # Safety
/// Every byte in the exact full run must have been overwritten, every PTE
/// must be invalid, and all cache maintenance, local/remote TLBI, and
/// ordering barriers must be durably complete. This consumes the only
/// evidence accepted by `complete_scrub`.
pub unsafe fn close_scrub_access(
&mut self,
current: AllocationDomain,
token: &AllocationToken,
scrub: &ScrubToken,
access: &mut ScrubAccessToken,
) -> Result<(), RuntimeAllocationError> {
self.validate_live_token(current, token)?;
let allocation_index = self.validate_allocation_record(token)?;
self.validate_scrub_record(token, scrub)?;
let access_index =
self.validate_scrub_access_record(token, scrub, access, AccessPhase::Mapped)?;
self.retire_scrub_access_record(allocation_index, access_index)?;
self.ledger.allocations[allocation_index].scrub_access_completed = true;
access.phase = KernelAccessTokenPhase::Consumed;
Ok(())
}
pub fn begin_scrub(
&mut self,
current: AllocationDomain,
token: &AllocationToken,
) -> Result<ScrubToken, RuntimeAllocationError> {
self.validate_live_token(current, token)?;
let index = self.validate_allocation_record(token)?;
let allocation = self.ledger.allocations[index];
if allocation.pin_references != 0
|| allocation.mapping_references()? != 0
|| allocation.access_references()? != 0
|| allocation.scrub_in_progress
{
return Err(lifecycle_busy(allocation));
}
if allocation.release_scrubbed {
return Err(RuntimeAllocationError::AllocationAlreadyScrubbed {
allocation_generation: allocation.generation,
});
}
let generation = self
.ledger
.last_scrub_generation
.checked_add(1)
.ok_or(RuntimeAllocationError::ScrubGenerationOverflow)?;
let scrubs = self
.ledger
.scrubs_in_progress
.checked_add(1)
.ok_or(RuntimeAllocationError::CounterOverflow)?;
self.ledger.allocations[index].scrub_generation = generation;
self.ledger.allocations[index].scrub_in_progress = true;
self.ledger.allocations[index].scrub_access_completed = false;
self.ledger.scrubs_in_progress = scrubs;
self.ledger.last_scrub_generation = generation;
Ok(ScrubToken {
owner: current,
allocation_generation: token.allocation_generation,
scrub_generation: generation,
start: token.start_address(),
frame_count: token.frame_count(),
state: AuthorityState::Live,
})
}
/// # Safety
/// Every byte in the exact run must have been overwritten, with all cache
/// maintenance and barriers required before reuse.
pub unsafe fn complete_scrub(
&mut self,
current: AllocationDomain,
token: &AllocationToken,
scrub: &mut ScrubToken,
) -> Result<(), RuntimeAllocationError> {
self.validate_live_token(current, token)?;
let index = self.validate_allocation_record(token)?;
self.validate_scrub_record(token, scrub)?;
let allocation = self.ledger.allocations[index];
if allocation.access_references()? != 0 {
return Err(lifecycle_busy(allocation));
}
if !allocation.scrub_access_completed {
return Err(RuntimeAllocationError::ScrubAccessRequired {
allocation_generation: allocation.generation,
scrub_generation: allocation.scrub_generation,
});
}
let scrubs = self
.ledger
.scrubs_in_progress
.checked_sub(1)
.ok_or(RuntimeAllocationError::InvariantViolation)?;
let scrubbed = self
.ledger
.release_scrubbed_allocations
.checked_add(1)
.ok_or(RuntimeAllocationError::CounterOverflow)?;
self.ledger.allocations[index].scrub_generation = 0;
self.ledger.allocations[index].scrub_in_progress = false;
self.ledger.allocations[index].scrub_access_completed = false;
self.ledger.allocations[index].release_scrubbed = true;
self.ledger.scrubs_in_progress = scrubs;
self.ledger.release_scrubbed_allocations = scrubbed;
scrub.state = AuthorityState::Consumed;
Ok(())
}
pub fn reap_one_retired(
&mut self,
current: AllocationDomain,
) -> Result<Option<ReapedAllocation>, RuntimeAllocationError> {
self.validate_current_domain(current)?;
let Some((index, record)) =
self.ledger
.allocations
.iter()
.copied()
.enumerate()
.find(|(_, record)| {
record.active
&& record.owner.instance_epoch == self.instance_epoch
&& record.owner.id == current.id
&& record.owner.generation < current.generation
})
else {
return Ok(None);
};
self.ensure_release_ready(record)?;
let active = self
.ledger
.active_allocations
.checked_sub(1)
.ok_or(RuntimeAllocationError::InvariantViolation)?;
let retired = self
.ledger
.retired_allocations
.checked_sub(1)
.ok_or(RuntimeAllocationError::InvariantViolation)?;
let scrubbed = self
.ledger
.release_scrubbed_allocations
.checked_sub(1)
.ok_or(RuntimeAllocationError::InvariantViolation)?;
let reaped = ReapedAllocation {
owner: record.owner,
allocation_generation: record.generation,
class: record.class,
start: record.start,
frame_count: record.frame_count,
};
self.pmm
.free_contiguous(record.start, record.frame_count)
.map_err(RuntimeAllocationError::Pmm)?;
self.ledger.allocations[index] = AllocationRecord::EMPTY;
self.ledger.active_allocations = active;
self.ledger.retired_allocations = retired;
self.ledger.release_scrubbed_allocations = scrubbed;
Ok(Some(reaped))
}
fn domain_record(&self, id: u32) -> Option<(usize, DomainRecord)> {
self.ledger
.domains
.iter()
.copied()
.enumerate()
.find(|(_, record)| record.occupied && record.id == id)
}
fn allocatable_frame_capacity(&self) -> Result<u64, RuntimeAllocationError> {
let snapshot = self.pmm.snapshot();
snapshot
.total_frames
.checked_sub(snapshot.reserved_frames)
.ok_or(RuntimeAllocationError::InvariantViolation)
}
fn domain_allocated_frames(&self, id: u32) -> Result<u64, RuntimeAllocationError> {
let mut frames = 0u64;
for record in self
.ledger
.allocations
.iter()
.copied()
.filter(|record| record.active && record.owner.id == id)
{
if record.owner.instance_epoch != self.instance_epoch {
return Err(RuntimeAllocationError::InvariantViolation);
}
frames = frames
.checked_add(
u64::try_from(record.frame_count)
.map_err(|_| RuntimeAllocationError::CounterOverflow)?,
)
.ok_or(RuntimeAllocationError::CounterOverflow)?;
}
Ok(frames)
}
fn allocation_record_by_generation(
&self,
generation: u64,
) -> Option<(usize, AllocationRecord)> {
self.ledger
.allocations
.iter()
.copied()
.enumerate()
.find(|(_, record)| record.active && record.generation == generation)
}
fn validate_current_domain(
&self,
current: AllocationDomain,
) -> Result<usize, RuntimeAllocationError> {
if current.instance_epoch != self.instance_epoch {
return Err(RuntimeAllocationError::ForeignDomainInstance {
expected: self.instance_epoch,
provided: current.instance_epoch,
});
}
let (index, record) = self
.domain_record(current.id)
.ok_or(RuntimeAllocationError::UnknownDomain)?;
if current.generation != record.generation {
return Err(RuntimeAllocationError::StaleGeneration {
domain_id: current.id,
expected: record.generation,
provided: current.generation,
});
}
Ok(index)
}
fn validate_live_token(
&self,
current: AllocationDomain,
token: &AllocationToken,
) -> Result<(), RuntimeAllocationError> {
if token.is_consumed() {
return Err(RuntimeAllocationError::TokenConsumed);
}
self.validate_current_domain(current)?;
if token.owner.instance_epoch != self.instance_epoch {
return Err(RuntimeAllocationError::ForeignTokenInstance {
expected: self.instance_epoch,
provided: token.owner.instance_epoch,
});
}
if current.id != token.owner.id {
return Err(RuntimeAllocationError::CrossDomain {
expected: token.owner.id,
provided: current.id,
});
}
if token.owner.generation != current.generation {
return Err(RuntimeAllocationError::TokenFromRetiredGeneration {
domain_id: token.owner.id,
current: current.generation,
token: token.owner.generation,
});
}
Ok(())
}
fn validate_allocation_record(
&self,
token: &AllocationToken,
) -> Result<usize, RuntimeAllocationError> {
let Some((index, record)) =
self.allocation_record_by_generation(token.allocation_generation)
else {
return Err(RuntimeAllocationError::StaleAllocation {
allocation_generation: token.allocation_generation,
});
};
if record.owner != token.owner
|| record.class != token.class
|| record.start != token.run.start_address()
|| record.frame_count != token.run.frame_count()
{
return Err(RuntimeAllocationError::AllocationRecordMismatch);
}
Ok(index)
}
fn validate_pin_record(
&self,
allocation: &AllocationToken,
pin: &PinToken,
) -> Result<usize, RuntimeAllocationError> {
if pin.is_consumed() {
return Err(RuntimeAllocationError::PinTokenConsumed);
}
let Some((index, record)) = self
.ledger
.pins
.iter()
.copied()
.enumerate()
.find(|(_, record)| record.active && record.generation == pin.pin_generation)
else {
return Err(RuntimeAllocationError::PinRecordMismatch);
};
if pin.owner != allocation.owner
|| pin.allocation_generation != allocation.allocation_generation
|| record.owner != pin.owner
|| record.allocation_generation != pin.allocation_generation
|| record.frame_offset != pin.frame_offset
{
return Err(RuntimeAllocationError::PinRecordMismatch);
}
Ok(index)
}
fn validate_mapping_record(
&self,
allocation: &AllocationToken,
mapping: &MappingToken,
expected: MappingPhase,
) -> Result<usize, RuntimeAllocationError> {
let token_phase = match mapping.phase {
MappingTokenPhase::Prepared => MappingPhase::Prepared,
MappingTokenPhase::Mapped => MappingPhase::Mapped,
MappingTokenPhase::Consumed => {
return Err(RuntimeAllocationError::MappingTokenConsumed)
}
};
if token_phase != expected {
return Err(RuntimeAllocationError::InvalidMappingPhase);
}
let Some((index, record)) = self
.ledger
.mappings
.iter()
.copied()
.enumerate()
.find(|(_, record)| record.active && record.generation == mapping.mapping_generation)
else {
return Err(RuntimeAllocationError::MappingRecordMismatch);
};
if record.phase != expected
|| mapping.owner != allocation.owner
|| mapping.allocation_generation != allocation.allocation_generation
|| record.owner != mapping.owner
|| record.allocation_generation != mapping.allocation_generation
|| record.descriptor != mapping.descriptor
{
return Err(RuntimeAllocationError::MappingRecordMismatch);
}
Ok(index)
}
fn validate_tlb_record(
&self,
allocation: &AllocationToken,
tlb: &TlbInvalidationToken,
) -> Result<usize, RuntimeAllocationError> {
if tlb.is_consumed() {
return Err(RuntimeAllocationError::TlbTokenConsumed);
}
let Some((index, record)) = self
.ledger
.mappings
.iter()
.copied()
.enumerate()
.find(|(_, record)| record.active && record.generation == tlb.mapping_generation)
else {
return Err(RuntimeAllocationError::MappingRecordMismatch);
};
if record.phase != MappingPhase::PendingTlb
|| tlb.owner != allocation.owner
|| tlb.allocation_generation != allocation.allocation_generation
|| record.owner != tlb.owner
|| record.allocation_generation != tlb.allocation_generation
|| record.descriptor != tlb.descriptor
{
return Err(RuntimeAllocationError::MappingRecordMismatch);
}
Ok(index)
}
fn validate_kernel_access_record(
&self,
allocation: &AllocationToken,
access: &KernelAccessToken,
expected: AccessPhase,
) -> Result<usize, RuntimeAllocationError> {
let token_phase = access_token_phase(access.phase, false)?;
if token_phase != expected {
return Err(RuntimeAllocationError::InvalidKernelAccessPhase);
}
let Some((index, record)) = self
.ledger
.accesses
.iter()
.copied()
.enumerate()
.find(|(_, record)| record.active && record.generation == access.access_generation)
else {
return Err(RuntimeAllocationError::AccessRecordMismatch);
};
let expected_start = allocation.frame_address(access.descriptor.frame_offset)?;
if record.phase != expected
|| record.kind != AccessKind::Kernel
|| access.owner != allocation.owner
|| access.allocation_generation != allocation.allocation_generation
|| access.physical_start != expected_start
|| record.owner != access.owner
|| record.allocation_generation != access.allocation_generation
|| record.descriptor != access.descriptor
{
return Err(RuntimeAllocationError::AccessRecordMismatch);
}
Ok(index)
}
fn validate_scrub_access_record(
&self,
allocation: &AllocationToken,
scrub: &ScrubToken,
access: &ScrubAccessToken,
expected: AccessPhase,
) -> Result<usize, RuntimeAllocationError> {
let token_phase = access_token_phase(access.phase, true)?;
if token_phase != expected {
return Err(RuntimeAllocationError::InvalidKernelAccessPhase);
}
let Some((index, record)) = self
.ledger
.accesses
.iter()
.copied()
.enumerate()
.find(|(_, record)| record.active && record.generation == access.access_generation)
else {
return Err(RuntimeAllocationError::AccessRecordMismatch);
};
if record.phase != expected
|| record.kind
!= (AccessKind::Scrub {
scrub_generation: scrub.scrub_generation,
})
|| access.owner != allocation.owner
|| access.allocation_generation != allocation.allocation_generation
|| access.scrub_generation != scrub.scrub_generation
|| access.physical_start != allocation.start_address()
|| record.owner != access.owner
|| record.allocation_generation != access.allocation_generation
|| record.descriptor != access.descriptor
{
return Err(RuntimeAllocationError::AccessRecordMismatch);
}
Ok(index)
}
fn retire_kernel_access_record(
&mut self,
allocation_index: usize,
access_index: usize,
) -> Result<(), RuntimeAllocationError> {
let allocation_accesses = self.ledger.allocations[allocation_index]
.kernel_access_references
.checked_sub(1)
.ok_or(RuntimeAllocationError::InvariantViolation)?;
let ledger_accesses = self
.ledger
.kernel_access_references
.checked_sub(1)
.ok_or(RuntimeAllocationError::InvariantViolation)?;
self.ledger.accesses[access_index] = AccessRecord::EMPTY;
self.ledger.allocations[allocation_index].kernel_access_references = allocation_accesses;
self.ledger.kernel_access_references = ledger_accesses;
Ok(())
}
fn retire_scrub_access_record(
&mut self,
allocation_index: usize,
access_index: usize,
) -> Result<(), RuntimeAllocationError> {
let allocation_accesses = self.ledger.allocations[allocation_index]
.scrub_access_references
.checked_sub(1)
.ok_or(RuntimeAllocationError::InvariantViolation)?;
let ledger_accesses = self
.ledger
.scrub_access_references
.checked_sub(1)
.ok_or(RuntimeAllocationError::InvariantViolation)?;
self.ledger.accesses[access_index] = AccessRecord::EMPTY;
self.ledger.allocations[allocation_index].scrub_access_references = allocation_accesses;
self.ledger.scrub_access_references = ledger_accesses;
Ok(())
}
fn validate_scrub_record(
&self,
allocation: &AllocationToken,
scrub: &ScrubToken,
) -> Result<(), RuntimeAllocationError> {
if scrub.is_consumed() {
return Err(RuntimeAllocationError::ScrubTokenConsumed);
}
let (_, record) = self
.allocation_record_by_generation(allocation.allocation_generation)
.ok_or(RuntimeAllocationError::ScrubRecordMismatch)?;
if scrub.owner != allocation.owner
|| scrub.allocation_generation != allocation.allocation_generation
|| scrub.start != allocation.start_address()
|| scrub.frame_count != allocation.frame_count()
|| !record.scrub_in_progress
|| record.scrub_generation != scrub.scrub_generation
{
return Err(RuntimeAllocationError::ScrubRecordMismatch);
}
Ok(())
}
fn ensure_release_ready(&self, record: AllocationRecord) -> Result<(), RuntimeAllocationError> {
let (observed_pins, _) = self.observed_record_pins(record)?;
if observed_pins != record.pin_references {
return Err(RuntimeAllocationError::InvariantViolation);
}
if observed_pins != 0 {
return Err(RuntimeAllocationError::AllocationPinned {
allocation_generation: record.generation,
pin_references: observed_pins,
});
}
if record.mapping_references()? != 0
|| record.access_references()? != 0
|| record.scrub_in_progress
{
return Err(lifecycle_busy(record));
}
if !record.release_scrubbed {
return Err(RuntimeAllocationError::AllocationNeedsScrub {
allocation_generation: record.generation,
});
}
Ok(())
}
fn observed_record_pins(
&self,
record: AllocationRecord,
) -> Result<(u64, u64), RuntimeAllocationError> {
let mut pins = 0u64;
let mut pinned_frames = 0u64;
for frame_offset in 0..record.frame_count {
let address = record_frame_address(record, frame_offset)?;
let token_pin_count = u64::try_from(
self.ledger
.pins
.iter()
.filter(|pin| {
pin.active
&& pin.allocation_generation == record.generation
&& pin.frame_offset == frame_offset
})
.count(),
)
.map_err(|_| RuntimeAllocationError::CounterOverflow)?;
match self
.pmm
.frame_state(address)
.map_err(RuntimeAllocationError::Pmm)?
{
RuntimeFrameState::Allocated { pin_count } => {
if token_pin_count != pin_count as u64 {
return Err(RuntimeAllocationError::InvariantViolation);
}
if pin_count != 0 {
pinned_frames = pinned_frames
.checked_add(1)
.ok_or(RuntimeAllocationError::CounterOverflow)?;
}
pins = pins
.checked_add(pin_count as u64)
.ok_or(RuntimeAllocationError::CounterOverflow)?;
}
RuntimeFrameState::Free | RuntimeFrameState::Reserved => {
return Err(RuntimeAllocationError::InvariantViolation);
}
}
}
Ok((pins, pinned_frames))
}
}snippet sha256: 55bfb6853c4c…file sha256: f0f53099668f…
02 · Doğrulayan test kodu
Operations komutuna bağlı focused test
tam Rust öğesiL197–L242
simulation/tests/runtime_memory_reconciliation.rs::retired_frame_ownership_keeps_its_class_until_bounded_reap
#[test]
fn retired_frame_ownership_keeps_its_class_until_bounded_reap() {
let mut metadata = [0; 10];
let mut memory = state(&mut metadata);
let old = memory.register_domain(10).unwrap();
let allocation = memory
.allocate_classified(old, RuntimeMemoryClass::KernelObject, 1)
.unwrap();
scrub(&mut memory, old, &allocation);
let current = memory.rotate_domain(old).unwrap();
assert_eq!(
memory
.audited_domain_memory(current)
.unwrap()
.class(RuntimeMemoryClass::KernelObject)
.retired_allocations,
1
);
assert_eq!(
memory.audited_frame_ownership(allocation.start_address()),
Ok(RuntimeFrameOwnership::Owned {
owner: old,
allocation_generation: allocation.allocation_generation(),
class: RuntimeMemoryClass::KernelObject,
frame_offset: 0,
pin_count: 0,
retired: true,
})
);
assert_eq!(
memory.reap_one_retired(current),
Ok(Some(ReapedAllocation {
owner: old,
allocation_generation: allocation.allocation_generation(),
class: RuntimeMemoryClass::KernelObject,
start: allocation.start_address(),
frame_count: 1,
}))
);
assert_eq!(
memory.audited_frame_ownership(allocation.start_address()),
Ok(RuntimeFrameOwnership::Free)
);
}snippet sha256: fad15ab77b13…file sha256: d48b55f5604f…
03 · Kapı kimlik kaydı
Operations sıra, kimlik ve başlık bağı
tam Operations kaydıL26715–L26803
website/src/lib/operations.ts::k1-mem0-per-frame-ownership-reconciliation-partial
{
id: "k1-mem0-per-frame-ownership-reconciliation-partial",
date: "2026-08-23",
sequence: 127,
status: "passed",
umbrella_status: "partial",
title:
"K1/MEM0: per-frame domain sınıfı, hard quota ve fiziksel reconciliation",
summary:
"S126 production RuntimePmm dönüş tabanı üzerinde S127, her runtime tahsisini domain + allocation generation + kapalı MEM0 sınıfına bağladı. Allocation-free audit, sınıf toplamlarını PMM allocated/pinned/pin-reference envanteriyle exact uzlaştırır; tek frame Free/Reserved veya exact owner/class/offset olarak sorgulanır. Unclassified compatibility bucket strict MEM0 kapısını fail-closed kapatır. Domain hard quota retired generation frame'lerini bounded reap'e kadar ücretli tutar ve aşımı başka domain'i etkilemeden mutasyonsuz reddeder. Strict QEMU ELF yolu text=1/data=1/stack=3 frame'i sınıflı aldı ve 5/5 frame'i reclaim sonunda RuntimePmm baseline'ına döndürdü. Bu K1/MEM0 COMPLETE değildir.",
evidence: [
"Focused serialized host 35/35 PASS: memory_accounting 9/9, runtime_allocation_token 18/18, runtime_domain_quota 3/3 ve runtime_memory_reconciliation 5/5.",
"MEM0 reconciliation kapısı PMM allocated/pinned/pin-reference toplamlarını 10 sınıflı fixed-capacity snapshot ile exact eşler; Unclassified tahsis typed UnclassifiedAllocations hatasıdır.",
"Per-frame audit Reserved, Free ve Owned { domain, generation, class, offset, pin_count, retired } durumlarını yalnız tam ledger/PMM auditi sonrasında yayınlar.",
"Hard quota host kanıtı: aşım atomik ve mutasyonsuzdur, unrelated domain tahsis yapabilir; rotated domain'in retired frame'leri reap'e kadar kotada kalır.",
"QEMU smoke PASS: `[K1-MEM0] ... text=1 data=1 stack=3 total=5 UNCLASSIFIED=0 RECONCILED=YES`, ardından `[K1-RUNTIME-ELF-RECLAIM] ... frames=5 free=6144->6144 active_allocations=0->0 BASELINE=PASS`; strict ELF W^X 2/2, EL0 return x4096, IPC reply 3/3 ve SEC5 korunur.",
"RPi5 `aarch64-unknown-none` cargo check PASS; bu yalnız compile applicability'dir, fiziksel board kanıtı değildir.",
"Kalıcı kapsam ve açık sınırlar: `docs/K1-MEM0-Per-Frame-Ownership-Reconciliation-Proof.md`.",
],
commands: [
"cargo test -p aselsan_microkernel_simulation --test runtime_memory_reconciliation --test runtime_domain_quota --test runtime_allocation_token --test memory_accounting -- --test-threads=1",
"make verify-qemu",
"cargo check -p aselsan_kernel --target aarch64-unknown-none --no-default-features --features board-rpi5",
"cargo test --workspace -- --test-threads=1",
],
terminalSessions: [
{
id: "s127-mem0-focused-host",
title: "MEM0 sahiplik, reconciliation ve quota host kapıları",
commandLines: [
"cargo test -p aselsan_microkernel_simulation --test runtime_memory_reconciliation --test runtime_domain_quota --test runtime_allocation_token --test memory_accounting -- --test-threads=1",
],
outputLines: [
"memory_accounting: 9 passed",
"runtime_allocation_token: 18 passed",
"runtime_domain_quota: 3 passed",
"runtime_memory_reconciliation: 5 passed",
"focused total: 35/35 PASS",
],
exitCode: 0,
outputMode: "selected",
},
{
id: "s127-runtime-and-rpi5-compile",
title:
"Strict QEMU runtime ledger/reclaim ve RPi5 compile applicability",
commandLines: [
"make verify-qemu",
"cargo check -p aselsan_kernel --target aarch64-unknown-none --no-default-features --features board-rpi5",
],
outputLines: [
"K1-MEM0 ELF_FRAME_LEDGER: text=1 data=1 stack=3 total=5 UNCLASSIFIED=0 RECONCILED=YES",
"K1-RUNTIME-ELF-RECLAIM: frames=5 free=6144->6144 active_allocations=0->0 BASELINE=PASS",
"QEMU smoke PASS: strict ELF W^X 2/2 + runtime MEM0 ledger/reclaim baseline + EL0 return x4096 + IPC reply 3/3 + scheduler SEC 5",
"board-rpi5 aarch64-unknown-none check: PASS",
],
exitCode: 0,
outputMode: "selected",
},
{
id: "s127-workspace-independent-history-red",
title: "Tam workspace: S127 dışı iki tarihsel identity kırmızısı",
commandLines: [
"cargo test --workspace -- --test-threads=1",
"cargo test --workspace -- --test-threads=1 --skip wiring_does_not_mutate_timer_gic_boot_or_expand_runtime_scope",
],
outputLines: [
"rpi5_g8h_integration_source::wiring_does_not_mutate_timer_gic_boot_or_expand_runtime_scope: FAILED",
"S96 mutated exceptions.S: observed f7b47672...04fd, frozen expected c0eed3e2...cb89",
"diagnostic continuation: rpi5_g8h_staged_flash_source::historical_s90_and_s100_inputs_remain_exact: FAILED",
"reconstructed S100 package-source bytes: observed 52911, frozen expected 52745",
"S127 focused tests remain 35/35 PASS; full-workspace GREEN is not claimed",
],
exitCode: 101,
outputMode: "selected",
outputNote:
"İki kırmızı da S127'nin değiştirmediği tarihsel yüzeylerdedir: önceden modified exceptions.S identity sınırı ve reconstructed S100 package-source uzunluğu. Frozen hash, uzunluk veya testler düzeltilmedi ya da gevşetilmedi.",
},
],
terminalSessionsNote:
"S127 host + QEMU runtime + RPi5 compile kaydıdır. Tam workspace'teki iki bağımsız tarihsel identity kırmızısı açıkça korunur; fiziksel veya device işlemi yapılmadı.",
limitations: [
"K1/MEM0 COMPLETE değildir. Production sınıflandırma strict QEMU hello LOAD/stack frame'lerini kapsar; IPC demo ve diğer legacy BumpAllocator üreticileri kapsam dışıdır.",
"PageTable/KernelObject/Surface/IpcLoan/Dma sınıfları typed audit yüzeyinde vardır; bütün gerçek kernel üreticileri henüz bağlanmamıştır. Capability, endpoint ve ASID aynı global reconciliation snapshot'ında değildir.",
"Repeated spawn/fault/exit soak, injected malformed-ELF/page-fault/OOM runtime matrisi, supervisor event kanalı ve SMP-grade reaper açık kalır.",
"S124 archive/promotion STOP kalır. Son fiziksel boot/runtime PASS S92 BOOT8G / CPU1_PER_CPU_TIMER_ONLY; S123 PHYSICAL_BOOT8H=REJECTED_NO_PASS.",
"CARD_WRITE=0, PHYSICAL_CARD_READBACK=0, SYNC=0, EJECT=0, UART=STOP, POWER=STOP ve PHYSICAL_BOOT8H=STOP.",
],
},snippet sha256: 797ddbf4e2b6…file sha256: 9726dbf00f84…
Focused test komutu
cargo test -p aselsan_microkernel_simulation --test runtime_memory_reconciliation --test runtime_domain_quota --test runtime_allocation_token --test memory_accounting -- --test-threads=1Registry schema v5 · generator
website/scripts/generate-code-gates.mjs · Tam SHA-256: 3050638b71a684d8f8f947a8a6faa237a17fa8db5dc0db04fb207b668b462af9