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}