diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f4dc006..b10a539 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -21,7 +21,7 @@ jobs: - nightly - beta - stable - - 1.56.0 + - 1.57.0 profile: - name: debug - name: release diff --git a/Cargo.toml b/Cargo.toml index ad09017..a92343d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ homepage = "https://github.com/jarkkojs/mmledger" repository = "https://github.com/jarkkojs/mmledger" description = "A ledger for confidential computing (CC) shims for tracking memory management system calls" edition = "2021" +rust-version = "1.57" include = [ "**/*.rs", "Cargo.toml", diff --git a/src/lib.rs b/src/lib.rs index 171e00c..ae8948b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,585 +1,357 @@ //! A ledger for memory mappings. -#![no_std] +#![cfg_attr(not(test), no_std)] #![deny(clippy::all)] #![deny(missing_docs)] #![forbid(unsafe_code)] use core::cmp::Ordering; -use lset::{Empty, Line, Span}; +use lset::{Contains, Empty, Line, Span}; use primordial::{Address, Offset, Page}; -bitflags::bitflags! { - /// Memory access permissions. - #[derive(Default)] - #[repr(transparent)] - pub struct Access: usize { - /// Read access - const READ = 1 << 0; - - /// Write access - const WRITE = 1 << 0; - - /// Execute access - const EXECUTE = 1 << 0; - } -} - -/// A ledger record. +/// A range of tagged address space in a ledger. #[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] -pub struct Record { - /// The covered region of memory. - pub region: Line>, - - /// The access permissions. - pub access: Access, - - length: usize, +#[repr(C, align(32))] +pub struct Region { + /// Address range + pub addresses: Line>, + /// Access token + pub token: u64, + reserved: u64, } -impl Record { - const EMPTY: Record = Record { - region: Line::new(Address::NULL, Address::NULL), - access: Access::empty(), - length: 0, - }; - - fn new(region: Line>, access: Access) -> Self { - Record { - region, - access, - length: 0, +impl Region { + #[inline] + /// Create a new instance. + pub const fn new(addresses: Line>, token: u64) -> Self { + Self { + addresses, + token, + reserved: 0, } } + + #[inline] + /// Create an empty instance. + pub const fn empty() -> Self { + Self::new(Line::new(Address::NULL, Address::NULL), 0) + } } /// Ledger error conditions. #[derive(Debug)] pub enum Error { /// Out of storage capacity - OutOfCapacity, + NoCapacity, /// No space for the region - OutOfSpace, - - /// Not inside the address space - Overflow, + NoSpace, - /// Overlap with the existing regions - Overlap, - - /// Invalid region + /// Invalid region given as input InvalidRegion, } -/// A virtual memory map ledger. -// -// Developer Note: the first record is reserved for the ledger bounds. We -// structure it this way so that the user of the `Ledger` type has -// fine-grained controls over allocation. For example, to allocate a 4k page, -// the user can instantiate as `Ledger::<128>::new(..)`. +/// Maintains a log of reserved address regions. The header of the ledger and +/// each region are 32 bytes, and they are also aligned to 32 bytes. To get a +/// ledger of which total size is a power of two, pick N = M - 1, where M is a +/// power of two. #[derive(Clone, Debug)] +#[repr(C, align(32))] pub struct Ledger { - records: [Record; N], + addresses: Line>, + len: usize, + reserved: u64, + regions: [Region; N], } impl Ledger { - /// Sort the records. - fn sort(&mut self) { - self.records_mut().sort_unstable_by(|l, r| { - if l.region == r.region { - Ordering::Equal - } else if l.region.is_empty() { - Ordering::Greater - } else if r.region.is_empty() { - Ordering::Less - } else { - l.region.start.cmp(&r.region.start) - } - }) - } - /// Create a new instance. - pub const fn new(region: Line>) -> Self { - let mut records = [Record::EMPTY; N]; - records[0].region = region; - Self { records } + pub const fn new(addresses: Line>) -> Self { + Self { + addresses, + len: 0, + reserved: 0, + regions: [Region::empty(); N], + } } - /// Get an immutable view of the records. - pub fn records(&self) -> &[Record] { - let used = self.records[0].length; - &self.records[1..][..used] + /// Get an immutable view of the regions. + pub fn regions(&self) -> &[Region] { + &self.regions[..self.len] } - /// Get a mutable view of the records. - /// - /// This function MUST NOT be public. - fn records_mut(&mut self) -> &mut [Record] { - let used = self.records[0].length; - &mut self.records[1..][..used] + /// Delete a range of addresses from the regions. + pub fn delete(&mut self, addresses: Line>) -> Result<(), Error> { + if addresses.start >= addresses.end { + return Err(Error::InvalidRegion); + } + + if addresses.start < self.addresses.start || addresses.end > self.addresses.end { + return Err(Error::InvalidRegion); + } + + for i in 0..self.len { + // No contact: skip. + let shared = addresses.intersection(self.regions[i].addresses); + if shared.is_none() { + continue; + } + + let region_addresses = self.regions[i].addresses; + let value = self.regions[i].token; + + // Region fully covered: remove. + if addresses.contains(®ion_addresses) { + self.remove(i); + continue; + } + + // Piece fully covered: split the region and return. + if region_addresses.contains(&addresses) { + self.regions[i].addresses = Line::new(addresses.start, region_addresses.start); + return self.insert(Region::new( + Line::new(addresses.end, region_addresses.end), + value, + )); + } + + // Partially covered: adjust. + let shared = shared.unwrap(); + if shared.start > addresses.start { + self.regions[i].addresses = Line::new(addresses.start, shared.start); + } else { + self.regions[i].addresses = Line::new(shared.end, addresses.end); + } + } + + Ok(()) } - /// Insert a new record into the ledger. - pub fn insert( - &mut self, - region: impl Into>>, - access: impl Into>, - commit: bool, - ) -> Result<(), Error> { - // Make sure the record is valid. - let record = Record::new(region.into(), access.into().unwrap_or_default()); - if record.region.start >= record.region.end { + /// Merge a new region to the ledger. + pub fn merge(&mut self, region: Region) -> Result<(), Error> { + if region.addresses.start >= region.addresses.end { + return Err(Error::InvalidRegion); + } + + // Make sure the region fits in our adress space. + if region.addresses.start < self.addresses.start + || region.addresses.end > self.addresses.end + { return Err(Error::InvalidRegion); } - // Make sure the record fits in our adress space. - let region = self.records[0].region; - if record.region.start < region.start || record.region.end > region.end { - return Err(Error::Overflow); + if let Err(e) = self.delete(region.addresses) { + return Err(e); } - // Loop over the records looking for merges. - let mut iter = self.records_mut().iter_mut().peekable(); + // Loop over the regions looking for merges. + let mut iter = self.regions_mut().iter_mut().peekable(); while let Some(prev) = iter.next() { - if prev.region.intersection(record.region).is_some() { - return Err(Error::Overlap); - } + assert!(prev.addresses.intersection(region.addresses).is_none()); if let Some(next) = iter.peek() { - if next.region.intersection(record.region).is_some() { - return Err(Error::Overlap); - } + assert!(next.addresses.intersection(region.addresses).is_none()); } - // Potentially merge with the `prev` slot. - if prev.access == record.access && prev.region.end == record.region.start { - if commit { - prev.region.end = record.region.end; - } - + // Merge previous. + if prev.token == region.token && prev.addresses.end == region.addresses.start { + prev.addresses.end = region.addresses.end; return Ok(()); } - // Potentially merge with the `prev` slot + // Merge next. if let Some(next) = iter.peek_mut() { - if next.access == record.access && next.region.start == record.region.end { - if commit { - next.region.start = record.region.start; - } - + if next.token == region.token && next.addresses.start == region.addresses.end { + next.addresses.start = region.addresses.start; return Ok(()); } } } - // If there is room to append a new record. - if self.records[0].length + 2 <= self.records.len() { - self.records[0].length += 1; - self.records[self.records[0].length] = record; - self.sort(); - return Ok(()); - } - - Err(Error::OutOfCapacity) + self.insert(region) } - /// Find space for a free region. - pub fn find_free( + /// Find free space from front. + pub fn find_free_front( &self, len: Offset, - front: bool, ) -> Result>, Error> { - let region = self.records[0].region; - - let start = Record { - region: Line::new(region.start, region.start), - ..Default::default() - }; - - let end = Record { - region: Line::new(region.end, region.end), - ..Default::default() - }; - - // Synthesize a starting window. - let first = [start, *self.records().first().unwrap_or(&end)]; - - // Synthesize an ending window. - let last = [*self.records().last().unwrap_or(&start), end]; - - // Chain everything together. - let mut iter = first - .windows(2) - .chain(self.records().windows(2)) - .chain(last.windows(2)); - - // Iterate through the windows. - if front { - while let Some([l, r]) = iter.next() { - if r.region.end - l.region.start > len { - return Ok(Span::new(l.region.end, len).into()); - } - } - } else { - let mut iter = iter.rev(); - while let Some([l, r]) = iter.next() { - if r.region.end - l.region.start > len { - return Ok(Span::new(r.region.start - len, len).into()); - } - } + if len.bytes() == 0 || len > self.addresses.end - self.addresses.start { + return Err(Error::InvalidRegion); } - Err(Error::OutOfSpace) - } -} + if self.len == 0 { + return Ok(Span::new(self.addresses.start, len).into()); + } -#[cfg(test)] -mod tests { - use super::*; + let mut prev: Address = self.addresses.start; + for i in 0..self.len { + let next = self.regions[i].addresses.start; + if len <= next - prev { + return Ok(Span::new(prev, len).into()); + } + prev = self.regions[i].addresses.end; + } - use core::mem::{align_of, size_of}; - - const PREV: Record = Record { - region: Line { - start: Address::new(0x4000usize), - end: Address::new(0x5000usize), - }, - access: Access::empty(), - length: 0, - }; - - const NEXT: Record = Record { - region: Line { - start: Address::new(0x8000), - end: Address::new(0x9000), - }, - access: Access::empty(), - length: 0, - }; - - const INDX: Record = Record { - region: Line { - start: Address::new(0x1000), - end: Address::new(0x10000), - }, - access: Access::empty(), - length: 2, - }; - - const LEDGER: Ledger<3> = Ledger { - records: [INDX, PREV, NEXT], - }; + if len <= self.addresses.end - prev { + return Ok(Span::new(prev, len).into()); + } - #[test] - fn record_size_align() { - assert_eq!(size_of::(), size_of::() * 4); - assert_eq!(align_of::(), align_of::()); + Err(Error::NoSpace) } - #[test] - fn insert() { - let start = Address::from(0x1000usize).lower(); - let end = Address::from(0x10000usize).lower(); - let mut ledger = Ledger::<8>::new(Line::new(start, end)); - - let region = Line { - start: Address::from(0xe000usize).lower(), - end: Address::from(0x10000usize).lower(), - }; - - assert_eq!(ledger.records(), &[]); - ledger.insert(region, None, true).unwrap(); - assert_eq!(ledger.records(), &[Record::new(region, Access::empty())]); - } + /// Find free space from back. + pub fn find_free_back( + &self, + len: Offset, + ) -> Result>, Error> { + if len.bytes() == 0 || len > self.addresses.end - self.addresses.start { + return Err(Error::InvalidRegion); + } - #[test] - fn find_free_front() { - let start = Address::from(0x1000).lower(); - let end = Address::from(0x10000).lower(); - let mut ledger = Ledger::<8>::new(Line::new(start, end)); - - let region = ledger.find_free(Offset::from_items(2), true).unwrap(); - let answer = Line { - start: Address::from(0x1000).lower(), - end: Address::from(0x3000).lower(), - }; - assert_eq!(region, answer); - - ledger.insert(answer, None, true).unwrap(); - - let region = ledger.find_free(Offset::from_items(2), true).unwrap(); - let answer = Line { - start: Address::from(0x3000).lower(), - end: Address::from(0x5000).lower(), - }; - assert_eq!(region, answer); - } + if self.len == 0 { + return Ok(Span::new(self.addresses.end - len, len).into()); + } - #[test] - fn find_free_back() { - let start = Address::from(0x1000).lower(); - let end = Address::from(0x10000).lower(); - let mut ledger = Ledger::<8>::new(Line::new(start, end)); - - let region = ledger.find_free(Offset::from_items(2), false).unwrap(); - let answer = Line { - start: Address::from(0xe000).lower(), - end: Address::from(0x10000).lower(), - }; - assert_eq!(region, answer); - - ledger.insert(answer, None, true).unwrap(); - - let region = ledger.find_free(Offset::from_items(2), false).unwrap(); - let answer = Line { - start: Address::from(0xc000).lower(), - end: Address::from(0xe000).lower(), - }; - assert_eq!(region, answer); - } + let mut next: Address = self.addresses.end; + for i in (0..self.len).rev() { + let prev = self.regions[i].addresses.end; + if len <= next - prev { + return Ok(Span::new(next - len, len).into()); + } + next = self.regions[i].addresses.start; + } - #[test] - fn merge_after() { - const REGION: Line> = Line { - start: Address::new(0x5000), - end: Address::new(0x6000), - }; - - const MERGED: Record = Record { - region: Line { - start: Address::new(0x4000), - end: Address::new(0x6000), - }, - access: Access::empty(), - length: 0, - }; - - let mut ledger = LEDGER.clone(); - ledger.insert(REGION, Access::empty(), true).unwrap(); - - assert_eq!(ledger.records[0].length, 2); - assert_eq!(ledger.records[1], MERGED); - assert_eq!(ledger.records[2], NEXT); - } + if len <= next - self.addresses.start { + return Ok(Span::new(next - len, len).into()); + } - #[test] - fn merge_before() { - const REGION: Line> = Line { - start: Address::new(0x7000), - end: Address::new(0x8000), - }; - - const MERGED: Record = Record { - region: Line { - start: Address::new(0x7000), - end: Address::new(0x9000), - }, - access: Access::empty(), - length: 0, - }; - - let mut ledger = LEDGER.clone(); - ledger.insert(REGION, Access::empty(), true).unwrap(); - - assert_eq!(ledger.records[0].length, 2); - assert_eq!(ledger.records[1], PREV); - assert_eq!(ledger.records[2], MERGED); + Err(Error::NoSpace) } - /* - use std::mem::{align_of, size_of}; - - use super::*; + /// Get a mutable view of the regions. + fn regions_mut(&mut self) -> &mut [Region] { + &mut self.regions[..self.len] + } - const MEMORY_MAP_ADDRESS: Address = - unsafe { Address::new_unchecked((2 * Page::SIZE) as *mut c_void) }; - const MEMORY_MAP_SIZE: usize = 3 * Page::SIZE; + /// Insert a region. + fn insert(&mut self, region: Region) -> Result<(), Error> { + if self.len == self.regions.len() { + assert!(self.len <= self.regions.len()); + return Err(Error::NoCapacity); + } - #[test] - fn addr_region_equal() { - const A: Address = unsafe { Address::new_unchecked(Page::SIZE as *mut c_void) }; - const B: Address = unsafe { Address::new_unchecked(Page::SIZE as *mut c_void) }; + self.regions[self.len] = region; + self.len += 1; + self.sort(); - assert_eq!(Region::new(A, Page::SIZE), Region::new(B, Page::SIZE),); + Ok(()) } - #[test] - fn addr_region_not_equal() { - const A: Address = unsafe { Address::new_unchecked(Page::SIZE as *mut c_void) }; - const B: Address = unsafe { Address::new_unchecked(MEMORY_MAP_SIZE as *mut c_void) }; + /// Remove a region by index. + fn remove(&mut self, index: usize) { + assert!(self.len > 0); + assert!(index < self.len); - assert!(Region::new(A, Page::SIZE) != Region::new(B, Page::SIZE)); + self.regions[index] = self.regions[self.len - 1]; + self.regions[self.len - 1] = Region::empty(); // clear + self.len -= 1; + self.sort(); } - #[test] - fn alloc_region_success() { - const A: Address = unsafe { Address::new_unchecked((2 * Page::SIZE) as *mut c_void) }; - const B: Address = unsafe { Address::new_unchecked((4 * Page::SIZE) as *mut c_void) }; - - let mut m: AddressSpace<2> = AddressSpace::new(MEMORY_MAP_ADDRESS, MEMORY_MAP_SIZE); - let region_a = Region::new(A, Page::SIZE); - let region_b = Region::new(B, Page::SIZE); - - m.insert_region(region_a, AddressSpaceFlags::empty()) - .unwrap(); - m.insert_region(region_b, AddressSpaceFlags::empty()) - .unwrap(); + /// Sort the regions. + fn sort(&mut self) { + self.regions_mut().sort_unstable_by(|l, r| { + if l.addresses == r.addresses { + Ordering::Equal + } else if l.addresses.is_empty() { + Ordering::Greater + } else if r.addresses.is_empty() { + Ordering::Less + } else { + l.addresses.start.cmp(&r.addresses.start) + } + }) + } +} - let result = match m.allocate_region(Page::SIZE, AddressSpaceFlags::DRY_RUN) { - Ok(r) => r, - _ => panic!(), - }; +#[cfg(test)] +mod tests { + use super::*; - assert_eq!(result, Region::new(MEMORY_MAP_ADDRESS, 3 * Page::SIZE)); - } + const LIMITS: Line> = + Line::new(Address::new(0x1000), Address::new(0x10000)); #[test] - fn alloc_region_failure() { - const A: Address = unsafe { Address::new_unchecked((2 * Page::SIZE) as *mut c_void) }; - const B: Address = unsafe { Address::new_unchecked((4 * Page::SIZE) as *mut c_void) }; - const C: Address = unsafe { Address::new_unchecked((3 * Page::SIZE) as *mut c_void) }; - - let mut m: AddressSpace<2> = AddressSpace::new(MEMORY_MAP_ADDRESS, MEMORY_MAP_SIZE); - let region_a = Region::new(A, Page::SIZE); - let region_b = Region::new(B, Page::SIZE); - let region_c = Region::new(C, Page::SIZE); - - m.insert_region(region_a, AddressSpaceFlags::empty()) - .unwrap(); - m.insert_region(region_b, AddressSpaceFlags::empty()) - .unwrap(); - m.insert_region(region_c, AddressSpaceFlags::empty()) - .unwrap(); - - match m.allocate_region(Page::SIZE, AddressSpaceFlags::DRY_RUN) { - Err(AddressSpaceError::OutOfSpace) => (), - _ => panic!(), - } + fn merge() { + const X: Line> = + Line::new(Address::new(0xe000), Address::new(0x10000)); + + let mut ledger: Ledger<1> = Ledger::new(LIMITS); + assert_eq!(ledger.len, 0); + ledger.merge(Region::new(X, 0)).unwrap(); + assert_eq!(ledger.regions(), &[Region::new(X, 0)]); } #[test] - fn extend_region() { - const A: Address = unsafe { Address::new_unchecked((2 * Page::SIZE) as *mut c_void) }; - const B: Address = unsafe { Address::new_unchecked((4 * Page::SIZE) as *mut c_void) }; - const E: Address = unsafe { Address::new_unchecked((3 * Page::SIZE) as *mut c_void) }; - - let mut m: AddressSpace<1> = AddressSpace::new(MEMORY_MAP_ADDRESS, MEMORY_MAP_SIZE); - let region_a = Region::new(A, Page::SIZE); - let expected = Region::new(E, Page::SIZE); - - println!("{:?}", region_a); - - m.insert_region(region_a, AddressSpaceFlags::empty()) - .unwrap(); - let result = match m.extend_region(B) { - Ok(region) => region, - _ => panic!(), - }; - - assert_eq!(result, expected); + fn find_free_front() { + const D: Offset = Offset::from_items(2); + const A: Line> = Line::new(Address::new(0x1000), Address::new(0x3000)); + const B: Line> = Line::new(Address::new(0x3000), Address::new(0x5000)); + + let mut ledger: Ledger<8> = Ledger::new(LIMITS); + assert_eq!(ledger.find_free_front(D).unwrap(), A); + ledger.merge(Region::new(A, 0)).unwrap(); + assert_eq!(ledger.find_free_front(D).unwrap(), B); } #[test] - fn insert_region() { - const A: Address = unsafe { Address::new_unchecked((2 * Page::SIZE) as *mut c_void) }; - - let mut m: AddressSpace<1> = AddressSpace::new(MEMORY_MAP_ADDRESS, MEMORY_MAP_SIZE); - let region = Region::new(A, Page::SIZE); - - let region = match m.insert_region(region, AddressSpaceFlags::empty()) { - Ok(region) => region, - _ => panic!(), - }; - - assert_eq!(region, Region::new(A, Page::SIZE)); + fn find_free_back() { + const D: Offset = Offset::from_items(2); + const A: Line> = + Line::new(Address::new(0xe000), Address::new(0x10000)); + const B: Line> = Line::new(Address::new(0xc000), Address::new(0xe000)); + + let mut ledger: Ledger<8> = Ledger::new(LIMITS); + assert_eq!(ledger.find_free_back(D).unwrap(), A); + ledger.merge(Region::new(A, 0)).unwrap(); + assert_eq!(ledger.find_free_back(D).unwrap(), B); } #[test] - fn insert_adjacent() { - const A: Address = unsafe { Address::new_unchecked((2 * Page::SIZE) as *mut c_void) }; - const B: Address = unsafe { Address::new_unchecked((3 * Page::SIZE) as *mut c_void) }; - - let mut m: AddressSpace<2> = AddressSpace::new(MEMORY_MAP_ADDRESS, MEMORY_MAP_SIZE); - let region_a = Region::new(A, Page::SIZE); - let region_b = Region::new(B, Page::SIZE); + fn merge_after() { + const A: Line> = Line::new(Address::new(0x4000), Address::new(0x5000)); + const B: Line> = Line::new(Address::new(0x8000), Address::new(0x9000)); - m.insert_region(region_a, AddressSpaceFlags::empty()) - .unwrap(); + const X: Line> = Line::new(Address::new(0x5000), Address::new(0x6000)); + const Y: Line> = Line::new(Address::new(0x4000), Address::new(0x6000)); - let region = match m.insert_region(region_b, AddressSpaceFlags::DRY_RUN) { - Ok(region) => region, - _ => panic!(), - }; + let mut ledger: Ledger<8> = Ledger::new(LIMITS); + ledger.merge(Region::new(A, 0)).unwrap(); + ledger.merge(Region::new(B, 0)).unwrap(); + ledger.merge(Region::new(X, 0)).unwrap(); - assert_eq!(region, Region::new(A, 2 * Page::SIZE)); + assert_eq!(ledger.len, 2); + assert_eq!(ledger.regions[0], Region::new(Y, 0)); + assert_eq!(ledger.regions[1].addresses, B); } #[test] - fn insert_after_memory_map() { - const A: Address = unsafe { Address::new_unchecked((5 * Page::SIZE) as *mut c_void) }; - - let mut m: AddressSpace<2> = AddressSpace::new(MEMORY_MAP_ADDRESS, MEMORY_MAP_SIZE); - let region_a = Region::new(A, Page::SIZE); - - match m.insert_region(region_a, AddressSpaceFlags::DRY_RUN) { - Err(AddressSpaceError::Overflow) => (), - _ => panic!(), - } - } + fn merge_before() { + const A: Line> = Line::new(Address::new(0x4000), Address::new(0x5000)); + const B: Line> = Line::new(Address::new(0x8000), Address::new(0x9000)); - #[test] - fn insert_intersects() { - const A: Address = unsafe { Address::new_unchecked((2 * Page::SIZE) as *mut c_void) }; - const B: Address = unsafe { Address::new_unchecked((2 * Page::SIZE) as *mut c_void) }; - - let mut m: AddressSpace<2> = AddressSpace::new(MEMORY_MAP_ADDRESS, MEMORY_MAP_SIZE); - let region_a = Region::new(A, Page::SIZE); - let region_b = Region::new(B, Page::SIZE); - - m.insert_region(region_a, AddressSpaceFlags::empty()) - .unwrap(); - match m.insert_region(region_b, AddressSpaceFlags::DRY_RUN) { - Err(AddressSpaceError::Overlap) => (), - _ => panic!(), - } - } + const X: Line> = Line::new(Address::new(0x7000), Address::new(0x8000)); + const Y: Line> = Line::new(Address::new(0x7000), Address::new(0x9000)); - #[test] - fn insert_not_intersects() { - const A: Address = unsafe { Address::new_unchecked((2 * Page::SIZE) as *mut c_void) }; - const B: Address = unsafe { Address::new_unchecked((4 * Page::SIZE) as *mut c_void) }; - - let mut m: AddressSpace<2> = AddressSpace::new(MEMORY_MAP_ADDRESS, MEMORY_MAP_SIZE); - let region_a = Region::new(A, Page::SIZE); - let region_b = Region::new(B, Page::SIZE); - - m.insert_region(region_a, AddressSpaceFlags::empty()) - .unwrap(); - let region_c = match m.insert_region(region_b, AddressSpaceFlags::DRY_RUN) { - Ok(region) => region, - _ => panic!(), - }; - - assert_eq!(region_c, region_b); - } + let mut ledger: Ledger<8> = Ledger::new(LIMITS); + ledger.merge(Region::new(A, 0)).unwrap(); + ledger.merge(Region::new(B, 0)).unwrap(); + ledger.merge(Region::new(X, 0)).unwrap(); - #[test] - fn insert_overflow() { - const A: Address = unsafe { Address::new_unchecked((2 * Page::SIZE) as *mut c_void) }; - const B: Address = unsafe { Address::new_unchecked((4 * Page::SIZE) as *mut c_void) }; - - let mut m: AddressSpace<1> = AddressSpace::new(MEMORY_MAP_ADDRESS, MEMORY_MAP_SIZE); - let region_a = Region::new(A, Page::SIZE); - let region_b = Region::new(B, Page::SIZE); - - m.insert_region(region_a, AddressSpaceFlags::empty()) - .unwrap(); - match m.insert_region(region_b, AddressSpaceFlags::DRY_RUN) { - Err(AddressSpaceError::OutOfCapacity) => (), - _ => panic!(), - } + assert_eq!(ledger.len, 2); + assert_eq!(ledger.regions[0].addresses, A); + assert_eq!(ledger.regions[1], Region::new(Y, 0)); } - */ }