swage_core/memory/
memblock.rs1use std::{cell::RefCell, ops::Range, ptr::null_mut};
2
3use super::{BytePointer, PfnOffset, PhysAddr, pfn_offset::CachedPfnOffset};
4use crate::memory::virt_to_phys::LinuxPageMapError;
5use crate::memory::{LinuxPageMap, VirtToPhysResolver};
6use crate::util::PAGE_SIZE;
7use libc::{MAP_ANONYMOUS, MAP_POPULATE, MAP_SHARED};
8use log::{log, trace, warn};
9use pagemap2::VirtualMemoryArea;
10
11#[derive(Clone, Debug)]
16pub struct Memory {
17 pub ptr: *mut u8,
19 pub len: usize,
21 pfn_offset: PfnOffset,
22}
23
24unsafe impl Send for Memory {}
25
26impl Memory {
27 pub fn new(ptr: *mut u8, len: usize) -> Self {
29 Memory {
30 ptr,
31 len,
32 pfn_offset: PfnOffset::Dynamic(Box::new(RefCell::new(None))),
33 }
34 }
35
36 pub fn new_with_parts(ptr: *mut u8, len: usize, pfn_offset: PfnOffset) -> Self {
44 Memory {
45 ptr,
46 len,
47 pfn_offset,
48 }
49 }
50
51 pub fn mmap(size: usize) -> std::result::Result<Self, std::io::Error> {
60 let p = unsafe {
61 libc::mmap(
62 null_mut(),
63 size,
64 libc::PROT_READ | libc::PROT_WRITE,
65 MAP_SHARED | MAP_ANONYMOUS | MAP_POPULATE,
66 -1,
67 0,
68 )
69 };
70 if p == libc::MAP_FAILED {
71 return Err(std::io::Error::last_os_error());
72 }
73 unsafe { libc::memset(p, 0x00, size) };
74 Ok(Memory::new(p as *mut u8, size))
75 }
76
77 pub fn dealloc(self) {
81 unsafe { libc::munmap(self.ptr as *mut libc::c_void, self.len) };
82 }
83}
84
85impl BytePointer for Memory {
86 fn addr(&self, offset: usize) -> *mut u8 {
87 assert!(
88 offset < self.len,
89 "Memory::byte_add failed. Offset {} >= {}",
90 offset,
91 self.len
92 );
93 unsafe { self.ptr.byte_add(offset) }
94 }
95 fn ptr(&self) -> *mut u8 {
96 self.ptr
97 }
98 fn len(&self) -> usize {
99 self.len
100 }
101}
102
103impl CachedPfnOffset for Memory {
104 fn cached_offset(&self) -> &PfnOffset {
105 &self.pfn_offset
106 }
107}
108
109#[derive(Debug, thiserror::Error)]
111pub enum Error {
112 #[error(transparent)]
114 LinuxPageMapError(#[from] LinuxPageMapError),
115 #[error("Empty PFN range")]
117 EmptyPfnRange,
118}
119
120pub type Result<T> = std::result::Result<T, Error>;
122
123pub trait GetConsecPfns {
127 fn consec_pfns(&self) -> Result<ConsecPfns>;
133
134 fn log_pfns(&self, level: log::Level) {
136 let pfns = match self.consec_pfns() {
137 Ok(pfns) => pfns,
138 Err(e) => {
139 warn!("Failed to get PFNs: {:?}", e);
140 return;
141 }
142 };
143 let pfns = pfns.format_pfns();
144 log!(level, "PFNs:\n{}", pfns);
145 }
146}
147
148impl GetConsecPfns for Memory {
149 fn consec_pfns(&self) -> Result<ConsecPfns> {
150 (self.ptr, self.len).consec_pfns()
151 }
152}
153
154impl<T> GetConsecPfns for (*mut T, usize) {
155 fn consec_pfns(&self) -> Result<ConsecPfns> {
156 trace!("Get consecutive PFNs for vaddr 0x{:x}", self.0 as u64);
157 let mut consecs = vec![];
158 let mut resolver = LinuxPageMap::new()?;
160 let pfns = resolver.get_phys_range(VirtualMemoryArea::from((self.0 as u64, unsafe {
161 self.0.byte_add(self.1) as u64
162 })))?;
163 if pfns.is_empty() {
164 return Err(Error::EmptyPfnRange);
165 }
166 let mut phys_prev = pfns[0];
167 let mut range_start = phys_prev;
168 for phys in pfns.into_iter().skip(1) {
169 if phys != phys_prev + PAGE_SIZE {
170 consecs.push(range_start..phys_prev + PAGE_SIZE);
171 range_start = phys;
172 }
173 phys_prev = phys;
174 }
175 consecs.push(range_start..phys_prev + PAGE_SIZE);
176 trace!("PFN check done");
177 Ok(consecs)
178 }
179}
180
181pub trait FormatPfns {
183 fn format_pfns(&self) -> String;
185}
186
187type ConsecPfns = Vec<Range<PhysAddr>>;
189
190impl FormatPfns for ConsecPfns {
191 fn format_pfns(&self) -> String {
192 let mut pfns = String::from("");
193 for range in self {
194 pfns += &format!(
195 "{:p}..[{:04} KB]..{:p}\n",
196 range.start,
197 (range.end - range.start).as_usize() / 1024,
198 range.end
199 );
200 }
201 pfns
202 }
203}
204
205impl Memory {
207 #[cfg(false)]
208 pub fn pfn_align(mut self) -> Result<Vec<Memory>> {
209 let mut blocks = vec![];
210 let offset = match self.pfn_offset {
211 PfnOffset::Fixed(offset) => offset,
212 PfnOffset::Dynamic(ref offset) => {
213 let offset = offset.borrow();
214 match offset.into() {
215 Some(offset) => offset
216 .expect("PFN offset not determined yet. Call MemBlock::pfn_offset() before MemBlock::pfn_align()")
217 .0
218 .expect("Block is not consecutive"),
219 None => bail!("PFN offset not determined yet. Call MemBlock::pfn_offset() before MemBlock::pfn_align()"),
220 }
221 }
222 };
223 if offset == 0 {
224 return Ok(vec![self]);
225 }
226 assert_eq!(self.len, MB(4).bytes());
227 let offset = self.len - offset * ROW_SIZE;
228 assert!(offset < MB(4).bytes(), "Offset {} >= 4MB", offset);
229 let ptr = self.addr(offset);
230 let len = self.len - offset;
231 let block = Memory::new(ptr, len); blocks.push(block);
233 self.len = offset;
234 blocks.push(self);
235
236 Ok(blocks)
237 }
238}