tpt_archon_kernel/
memory.rs1use tpt_archon_bridge::capability::Capability;
17use tpt_archon_bridge::page_cache::{CacheError, UnifiedPageCache};
18use tpt_archon_core::page::Page;
19
20pub struct UnifiedMemory<C> {
28 cache: C,
29}
30
31impl<C> UnifiedMemory<C> {
32 pub fn new(cache: C) -> Self {
34 Self { cache }
35 }
36
37 pub fn into_cache(self) -> C {
39 self.cache
40 }
41}
42
43impl<C: UnifiedPageCache> UnifiedMemory<C> {
44 pub fn map_read(&mut self, cap: &Capability, block_id: u64) -> Result<&Page, CacheError> {
47 self.cache.map_read(cap, block_id)
48 }
49
50 pub fn map_write(&mut self, cap: &Capability, block_id: u64) -> Result<&mut Page, CacheError> {
52 self.cache.map_write(cap, block_id)
53 }
54
55 pub fn unmap(&mut self, block_id: u64) {
57 self.cache.unmap(block_id);
58 }
59}
60
61#[cfg(all(feature = "std", feature = "mmap"))]
62impl<C: tpt_archon_bridge::page_cache::MmapPageSource> UnifiedMemory<C> {
63 pub fn map_read_zero_copy(
68 &self,
69 cap: &Capability,
70 block_id: u64,
71 ) -> Result<&[u8; tpt_archon_core::page::PAGE_SIZE], CacheError> {
72 self.cache.map_read_zero_copy(cap, block_id)
73 }
74}
75
76#[cfg(test)]
77mod tests {
78 use super::*;
79 use alloc::rc::Rc;
80 use core::cell::RefCell;
81 use tpt_archon_bridge::capability::{CapabilityIssuer, Resource, Right};
82 use tpt_archon_bridge::page_cache::{CacheError, CorePageCache};
83 use tpt_archon_core::block::InMemoryBlockDevice;
84 use tpt_archon_core::page::BufferPool;
85
86 #[test]
87 fn unified_memory_shares_storage_pages() {
88 let issuer = Rc::new(RefCell::new(CapabilityIssuer::new()));
89 let rw = issuer
90 .borrow_mut()
91 .mint(Resource::Page(1), Right::ReadWrite);
92
93 let cache = CorePageCache::new(BufferPool::new(InMemoryBlockDevice::new(4), 2), issuer);
94 let mut mem = UnifiedMemory::new(cache);
95
96 {
97 let page = mem.map_write(&rw, 1).unwrap();
98 page.as_bytes_mut()[0] = 0x5A;
99 }
100 mem.unmap(1);
101
102 let page = mem.map_read(&rw, 1).unwrap();
103 assert_eq!(page.as_bytes()[0], 0x5A);
104 mem.unmap(1);
105 }
106
107 #[test]
108 fn unified_memory_denies_revoked_capability() {
109 let issuer = Rc::new(RefCell::new(CapabilityIssuer::new()));
114 let rw = issuer
115 .borrow_mut()
116 .mint(Resource::Page(1), Right::ReadWrite);
117
118 let cache = CorePageCache::new(
119 BufferPool::new(InMemoryBlockDevice::new(4), 2),
120 issuer.clone(),
121 );
122 let mut mem = UnifiedMemory::new(cache);
123
124 mem.map_write(&rw, 1).unwrap();
125 issuer.borrow_mut().revoke(&rw);
126 assert_eq!(mem.map_read(&rw, 1).err(), Some(CacheError::Denied));
127 assert_eq!(mem.map_write(&rw, 1).err(), Some(CacheError::Denied));
128 }
129}
130
131#[cfg(all(test, feature = "std", feature = "mmap"))]
132mod mmap_tests {
133 use super::*;
134 use alloc::rc::Rc;
135 use core::cell::RefCell;
136 use tpt_archon_bridge::capability::{CapabilityIssuer, Resource, Right};
137 use tpt_archon_bridge::page_cache::{CacheError, MmapPageCache};
138 use tpt_archon_core::block::MmapBlockDevice;
139 use tpt_archon_core::page::PAGE_SIZE;
140 use tpt_archon_core::storage::Database;
141
142 fn temp_db(name: &str) -> std::path::PathBuf {
143 let mut p = std::env::temp_dir();
144 p.push(format!(
145 "tpt-archon-kernel-mmap-{}-{}.bin",
146 name,
147 std::process::id()
148 ));
149 let _ = std::fs::remove_file(&p);
150 p
151 }
152
153 #[test]
154 fn unified_memory_zero_copy_read_over_mmap() {
155 let path = temp_db("shared");
156 let mut db = Database::create(&path, 4).unwrap();
157 db.put(1, &[0x5Au8; PAGE_SIZE]).unwrap();
158
159 let issuer = Rc::new(RefCell::new(CapabilityIssuer::new()));
160 let ro = issuer.borrow_mut().mint(Resource::Page(1), Right::Read);
161 let cache = MmapPageCache::new(MmapBlockDevice::open(&path).unwrap(), issuer);
162 let mem = UnifiedMemory::new(cache);
163
164 assert_eq!(mem.map_read_zero_copy(&ro, 1).unwrap()[0], 0x5A);
165 let _ = std::fs::remove_file(&path);
166 }
167
168 #[test]
169 fn unified_memory_mmap_denies_revoked_capability() {
170 let path = temp_db("revoked");
171 let _ = Database::create(&path, 4).unwrap();
172
173 let issuer = Rc::new(RefCell::new(CapabilityIssuer::new()));
174 let ro = issuer.borrow_mut().mint(Resource::Page(0), Right::Read);
175 let cache = MmapPageCache::new(MmapBlockDevice::open(&path).unwrap(), issuer.clone());
176 let mem = UnifiedMemory::new(cache);
177
178 mem.map_read_zero_copy(&ro, 0).unwrap();
179 issuer.borrow_mut().revoke(&ro);
180 assert_eq!(
181 mem.map_read_zero_copy(&ro, 0).err(),
182 Some(CacheError::Denied)
183 );
184 let _ = std::fs::remove_file(&path);
185 }
186}