Skip to main content

rvm_memory/
lib.rs

1//! # RVM Memory Manager
2//!
3//! Guest physical address space management for the RVM microhypervisor,
4//! as specified in ADR-136 and ADR-138. Provides a safe abstraction over
5//! four-tier coherence-driven memory with reconstruction capability.
6//!
7//! ## Four-Tier Memory Model (ADR-136)
8//!
9//! | Tier | Name | Description |
10//! |------|------|-------------|
11//! | 0 | Hot | Per-core SRAM / L1-adjacent; always resident during execution |
12//! | 1 | Warm | Shared DRAM; resident if residency rule is met |
13//! | 2 | Dormant | Compressed checkpoint + delta; reconstructed on demand |
14//! | 3 | Cold | Persistent archival; accessed only during recovery |
15//!
16//! ## Key Components
17//!
18//! - [`tier::TierManager`] -- Coherence-driven tier placement and transitions
19//! - [`allocator::BuddyAllocator`] -- Power-of-two physical page allocator
20//! - [`region::RegionManager`] -- Owned region lifecycle and address translation
21//! - [`reconstruction::ReconstructionPipeline`] -- Dormant state restoration
22//!
23//! ## Design Constraints
24//!
25//! - `#![no_std]` with zero heap allocation
26//! - `#![forbid(unsafe_code)]`
27//! - Works without the coherence engine (DC-1 static fallback thresholds)
28//! - All tier transitions are explicit, not demand-paged
29
30#![no_std]
31#![forbid(unsafe_code)]
32#![deny(missing_docs)]
33#![deny(clippy::all)]
34#![warn(clippy::pedantic)]
35
36#[cfg(feature = "alloc")]
37extern crate alloc;
38
39#[cfg(feature = "std")]
40extern crate std;
41
42use rvm_types::{GuestPhysAddr, PartitionId, PhysAddr, RvmError, RvmResult};
43
44pub mod allocator;
45pub mod reconstruction;
46pub mod region;
47pub mod tier;
48
49// Re-export key types at crate root for convenience.
50pub use allocator::BuddyAllocator;
51pub use reconstruction::{
52    create_checkpoint, CheckpointId, CompressedCheckpoint, ReconstructionPipeline,
53    ReconstructionResult, WitnessDelta,
54};
55pub use region::{AddressMapping, OwnedRegion, RegionConfig, RegionManager};
56pub use tier::{RegionTierState, Tier, TierManager, TierThresholds};
57
58/// Page size in bytes (4 KiB).
59pub const PAGE_SIZE: usize = 4096;
60
61/// Access permissions for a memory mapping.
62#[derive(Debug, Clone, Copy, PartialEq, Eq)]
63pub struct MemoryPermissions {
64    /// Allow read access.
65    pub read: bool,
66    /// Allow write access.
67    pub write: bool,
68    /// Allow execute access.
69    pub execute: bool,
70}
71
72impl MemoryPermissions {
73    /// Read-only permissions.
74    pub const READ_ONLY: Self = Self {
75        read: true,
76        write: false,
77        execute: false,
78    };
79
80    /// Read-write permissions.
81    pub const READ_WRITE: Self = Self {
82        read: true,
83        write: true,
84        execute: false,
85    };
86
87    /// Read-execute permissions.
88    pub const READ_EXECUTE: Self = Self {
89        read: true,
90        write: false,
91        execute: true,
92    };
93}
94
95/// A legacy memory region descriptor (ADR-138 compatibility).
96///
97/// For new code, prefer [`region::OwnedRegion`] which includes tier metadata.
98#[derive(Debug, Clone, Copy)]
99pub struct MemoryRegion {
100    /// Guest physical base address (must be page-aligned).
101    pub guest_base: GuestPhysAddr,
102    /// Host physical base address (must be page-aligned).
103    pub host_base: PhysAddr,
104    /// Number of pages in this region.
105    pub page_count: usize,
106    /// Access permissions.
107    pub permissions: MemoryPermissions,
108    /// The partition that owns this region.
109    pub owner: PartitionId,
110}
111
112/// Validate that a memory region descriptor is well-formed.
113///
114/// # Errors
115///
116/// Returns [`RvmError::AlignmentError`] if addresses are not page-aligned.
117/// Returns [`RvmError::ResourceLimitExceeded`] if the page count is zero.
118/// Returns [`RvmError::Unsupported`] if no permission bits are set.
119pub fn validate_region(region: &MemoryRegion) -> RvmResult<()> {
120    if !region.guest_base.is_page_aligned() {
121        return Err(RvmError::AlignmentError);
122    }
123    if !region.host_base.is_page_aligned() {
124        return Err(RvmError::AlignmentError);
125    }
126    if region.page_count == 0 {
127        return Err(RvmError::ResourceLimitExceeded);
128    }
129    if !region.permissions.read && !region.permissions.write && !region.permissions.execute {
130        return Err(RvmError::Unsupported);
131    }
132    Ok(())
133}
134
135/// Check whether two memory regions overlap in guest physical space.
136///
137/// Guest-physical overlap is only meaningful within the same partition
138/// (each partition has its own stage-2 page table). However, host-physical
139/// overlap across partitions would break isolation, so callers should also
140/// check `regions_overlap_host` for cross-partition safety.
141#[must_use]
142pub fn regions_overlap(a: &MemoryRegion, b: &MemoryRegion) -> bool {
143    if a.owner != b.owner {
144        return false; // Different partitions have separate guest address spaces.
145    }
146    let a_start = a.guest_base.as_u64();
147    let a_end = a_start + (a.page_count as u64 * PAGE_SIZE as u64);
148    let b_start = b.guest_base.as_u64();
149    let b_end = b_start + (b.page_count as u64 * PAGE_SIZE as u64);
150
151    a_start < b_end && b_start < a_end
152}
153
154/// Check whether two memory regions overlap in host physical space.
155///
156/// This is a critical isolation check: two partitions must NEVER map
157/// the same host physical pages unless explicitly sharing via a
158/// controlled mechanism (e.g., `RegionShare` with read-only attenuation).
159#[must_use]
160pub fn regions_overlap_host(a: &MemoryRegion, b: &MemoryRegion) -> bool {
161    let a_start = a.host_base.as_u64();
162    let a_end = a_start + (a.page_count as u64 * PAGE_SIZE as u64);
163    let b_start = b.host_base.as_u64();
164    let b_end = b_start + (b.page_count as u64 * PAGE_SIZE as u64);
165
166    a_start < b_end && b_start < a_end
167}