Skip to main content

osiris/mem/
vmm.rs

1use crate::error::Result;
2use crate::hal::mem::{PhysAddr, VirtAddr};
3
4mod nommu;
5
6pub type AddressSpace = nommu::AddressSpace;
7
8bitflags::bitflags! {
9    #[derive(Clone, Copy)]
10    pub struct Perms: u8 {
11        const Read = 0b0001;
12        const Write = 0b0010;
13        const Exec = 0b0100;
14    }
15}
16
17#[derive(Clone)]
18#[allow(dead_code)]
19pub enum Backing {
20    Zeroed,
21    Uninit,
22    Anon(PhysAddr),
23}
24
25#[derive(Clone)]
26#[allow(dead_code)]
27pub struct Region {
28    start: Option<VirtAddr>,
29    len: usize,
30    backing: Backing,
31    perms: Perms,
32}
33
34impl Region {
35    /// Creates a new region.
36    ///
37    /// - `start` is the starting virtual address of the region. If `None`, the system will choose a suitable address.
38    /// - `len` is the length of the region in bytes.
39    /// - `backing` is the backing type of the region, which determines how the region is initialized and where its contents come from.
40    /// - `perms` is the permissions of the region, which determines how the region can be accessed.
41    ///
42    pub fn new(start: Option<VirtAddr>, len: usize, backing: Backing, perms: Perms) -> Self {
43        Self {
44            start,
45            len,
46            backing,
47            perms,
48        }
49    }
50
51    #[allow(dead_code)]
52    pub fn start(&self) -> VirtAddr {
53        self.start.unwrap_or_else(|| VirtAddr::new(0))
54    }
55
56    pub fn len(&self) -> usize {
57        self.len
58    }
59
60    #[allow(dead_code)]
61    pub fn contains(&self, addr: VirtAddr) -> bool {
62        let Some(start) = self.start else {
63            return false;
64        };
65        start.saturating_add(self.len()) > addr && addr >= start
66    }
67}
68
69#[cfg(test)]
70mod tests {
71    use super::*;
72
73    #[test]
74    fn unplaced_region_contains_nothing() {
75        let r = Region::new(None, 100, Backing::Uninit, Perms::Read);
76        assert!(!r.contains(VirtAddr::new(0)));
77        assert!(!r.contains(VirtAddr::new(50)));
78        assert!(!r.contains(VirtAddr::new(100)));
79    }
80
81    #[test]
82    fn placed_region_contains_within_bounds() {
83        let r = Region::new(Some(VirtAddr::new(100)), 50, Backing::Uninit, Perms::Read);
84        assert!(!r.contains(VirtAddr::new(99)));
85        assert!(r.contains(VirtAddr::new(100)));
86        assert!(r.contains(VirtAddr::new(149)));
87        assert!(!r.contains(VirtAddr::new(150)));
88    }
89
90    #[test]
91    fn placed_region_saturates_at_usize_max() {
92        let r = Region::new(
93            Some(VirtAddr::new(usize::MAX - 10)),
94            100,
95            Backing::Uninit,
96            Perms::Read,
97        );
98        assert!(r.contains(VirtAddr::new(usize::MAX - 10)));
99        assert!(r.contains(VirtAddr::new(usize::MAX - 1)));
100        assert!(!r.contains(VirtAddr::new(usize::MAX)));
101    }
102}
103
104#[allow(dead_code)]
105pub trait AddressSpacelike {
106    // Size is the amount of pages in the address space. On nommu systems this will be reserved.
107    fn new(pages: usize) -> Result<Self>
108    where
109        Self: Sized;
110    fn map(&mut self, region: Region) -> Result<PhysAddr>;
111    fn unmap(&mut self, region: &Region) -> Result<()>;
112    fn protect(&mut self, region: &Region, perms: Perms) -> Result<()>;
113    fn virt_to_phys(&self, addr: VirtAddr) -> Option<PhysAddr>;
114    fn phys_to_virt(&self, addr: PhysAddr) -> Option<VirtAddr>;
115    fn end(&self) -> VirtAddr;
116    fn activate(&self) -> Result<()>;
117}