corevm_engine/
page_mapper.rs1use corevm_host::{Range, RangeSet, PAGE_SIZE};
2use log::{debug, trace};
3
4#[derive(Debug)]
6pub struct PageMapper {
7 pub heap_page_range: Range,
9 pub pages: RangeSet,
11}
12
13impl PageMapper {
14 pub fn new(pages: RangeSet, heap_page_range: Range) -> Self {
15 if let Some(range) = pages.enclosing_range() {
17 let next_page_index = range.end;
18 assert!(
19 (heap_page_range.start..=heap_page_range.end).contains(&next_page_index),
20 "Heap page range {:?} doesn't contain the next page index {}",
21 heap_page_range,
22 next_page_index
23 );
24 }
25 Self { heap_page_range, pages }
26 }
27
28 pub fn map(&mut self, num_pages: u64) -> Option<Range> {
29 if num_pages == 0 {
30 return None;
31 }
32 let Some(page_range) = self.find_unmapped_page_range(num_pages) else {
33 debug!("Failed to map {num_pages} guest memory page(s): no next address");
34 return None;
35 };
36 self.pages.insert(page_range.clone());
37 trace!(
38 "Mapped guest memory pages {:#x}..{:#x}",
39 page_range.start * PAGE_SIZE,
40 page_range.end * PAGE_SIZE,
41 );
42 Some(page_range)
43 }
44
45 pub fn unmap(&mut self, start_page: u64, end_page: u64) {
46 self.pages.remove(&Range::new(start_page, end_page));
47 }
48
49 pub fn is_mapped(&self, page: u64) -> bool {
50 self.pages.as_ref().iter().any(|range| range.contains(page))
51 }
52
53 fn find_unmapped_page_range(&mut self, num_pages: u64) -> Option<Range> {
54 let start_page = match self.pages.enclosing_range() {
55 Some(range) => range.end,
56 None => self.heap_page_range.start,
57 };
58 let end_page = start_page.checked_add(num_pages)?;
59 if end_page > self.heap_page_range.end {
60 return None;
61 }
62 Some(Range::new(start_page, end_page))
63 }
64}
65
66#[cfg(test)]
67mod tests {
68 use super::*;
69
70 #[test]
71 fn map_works() {
72 let mut mapper = PageMapper::new(Default::default(), Range::new(1, 10));
73 assert_eq!(None, mapper.map(0));
74 assert_eq!(None, mapper.map(10));
75 assert_eq!(None, mapper.map(u64::MAX));
76 assert_eq!(Some(Range::new(1, 2)), mapper.map(1));
77 mapper.unmap(0, u64::MAX);
78 assert_eq!(0, mapper.pages.as_ref().len(), "{:?}", mapper);
79 assert_eq!(Some(Range::new(1, 10)), mapper.map(9));
80 mapper.unmap(0, u64::MAX);
81 assert_eq!(0, mapper.pages.as_ref().len(), "{:?}", mapper);
82 assert_eq!(Some(Range::new(1, 2)), mapper.map(1));
83 }
84}