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));
}
- */
}