Skip to content

Commit

Permalink
demo: what if we add more bounds to MemoryAddr
Browse files Browse the repository at this point in the history
  • Loading branch information
aarkegz committed Aug 20, 2024
1 parent 4e58d27 commit e8a51c4
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 87 deletions.
32 changes: 31 additions & 1 deletion memory_addr/src/addr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,34 @@ pub trait MemoryAddr:
// The address type should be convertible to and from `usize`.
+ From<usize>
+ Into<usize>
// The address type should be comparable.
+ core::cmp::Ord
// The address type should support arithmetic operations with `usize`.
+ core::ops::Add<usize, Output = Self>
+ core::ops::AddAssign<usize>
+ core::ops::Sub<usize, Output = Self>
+ core::ops::SubAssign<usize>
+ core::ops::Sub<Self, Output = usize>
// The address type should have a default value.
+ Default
{
// Empty for now.
}

/// Implement the `MemoryAddr` trait for any type that satisfies the required bounds.
impl<T> MemoryAddr for T where T: Copy + From<usize> + Into<usize> {}
impl<T> MemoryAddr for T where
T: Copy
+ From<usize>
+ Into<usize>
+ core::cmp::Ord
+ core::ops::Add<usize, Output = Self>
+ core::ops::AddAssign<usize>
+ core::ops::Sub<usize, Output = Self>
+ core::ops::SubAssign<usize>
+ core::ops::Sub<Self, Output = usize>
+ Default
{
}

/// Creates a new address type by wrapping an `usize`.
///
Expand Down Expand Up @@ -187,6 +209,14 @@ macro_rules! def_usize_addr {
}
}

impl core::ops::Sub<$name> for $name {
type Output = usize;
#[inline]
fn sub(self, rhs: $name) -> usize {
self.0 - rhs.0
}
}

$crate::def_usize_addr!($($tt)*);
};
() => {};
Expand Down
49 changes: 7 additions & 42 deletions memory_addr/src/range.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,6 @@ use core::{fmt, ops::Range};

use crate::{MemoryAddr, PhysAddr, VirtAddr};

macro_rules! usize {
($addr:expr) => {
Into::<usize>::into($addr)
};
}

/// A range of a given memory address type `A`.
///
/// The range is inclusive on the start and exclusive on the end.
Expand All @@ -22,7 +16,7 @@ macro_rules! usize {
/// assert_eq!(range.start, 0x1000);
/// assert_eq!(range.end, 0x2000);
/// ```
#[derive(Clone, Copy)]
#[derive(Clone, Copy, Default, PartialEq, Eq)]
pub struct AddrRange<A: MemoryAddr> {
/// The lower bound of the range (inclusive).
pub start: A,
Expand Down Expand Up @@ -66,7 +60,7 @@ where
pub fn from_start_size(start: A, size: usize) -> Self {
Self {
start,
end: A::from(usize!(start) + size),
end: start + size,
}
}

Expand All @@ -83,7 +77,7 @@ where
/// ```
#[inline]
pub fn is_empty(self) -> bool {
usize!(self.start) >= usize!(self.end)
self.start >= self.end
}

/// Returns the size of the range.
Expand All @@ -98,7 +92,7 @@ where
/// ```
#[inline]
pub fn size(self) -> usize {
usize!(self.end) - usize!(self.start)
self.end - self.start
}

/// Checks if the range contains the given address.
Expand All @@ -116,7 +110,7 @@ where
/// ```
#[inline]
pub fn contains(self, addr: A) -> bool {
usize!(self.start) <= usize!(addr) && usize!(addr) < usize!(self.end)
self.start <= addr && addr < self.end
}

/// Checks if the range contains the given address range.
Expand All @@ -136,7 +130,7 @@ where
/// ```
#[inline]
pub fn contains_range(self, other: Self) -> bool {
usize!(self.start) <= usize!(other.start) && usize!(other.end) <= usize!(self.end)
self.start <= other.start && other.end <= self.end
}

/// Checks if the range is contained in the given address range.
Expand Down Expand Up @@ -174,39 +168,10 @@ where
/// ```
#[inline]
pub fn overlaps(self, other: Self) -> bool {
usize!(self.start) < usize!(other.end) && usize!(other.start) < usize!(self.end)
}
}

/// Implementations of [`Default`] for [`AddrRange`].
///
/// The default value is an empty range `0..0`.
impl<A> Default for AddrRange<A>
where
A: MemoryAddr,
{
#[inline]
fn default() -> Self {
Self::new(0.into(), 0.into())
}
}

/// Implementations of [`PartialEq`] for [`AddrRange`].
///
/// Two ranges are equal iff their start and end addresses are equal.
impl<A> PartialEq for AddrRange<A>
where
A: MemoryAddr,
{
#[inline]
fn eq(&self, other: &Self) -> bool {
usize!(self.start) == usize!(other.start) && usize!(self.end) == usize!(other.end)
self.start < other.end && other.start < self.end
}
}

/// Implementations of [`Eq`] for [`AddrRange`].
impl<A> Eq for AddrRange<A> where A: MemoryAddr {}

/// Implementations of [`From`] for [`AddrRange`] and [`Range`].
///
/// Converts a range into an address range.
Expand Down
23 changes: 9 additions & 14 deletions memory_set/src/area.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ impl<B: MappingBackend> MemoryArea<B> {
if !self.backend.unmap(self.start(), unmap_size, page_table) {
return Err(MappingError::BadState);
}
self.va_range.start = (self.va_range.start.into() + unmap_size).into();
self.va_range.start += unmap_size;
Ok(())
}

Expand All @@ -121,14 +121,13 @@ impl<B: MappingBackend> MemoryArea<B> {
page_table: &mut B::PageTable,
) -> MappingResult {
let unmap_size = self.size() - new_size;
if !self.backend.unmap(
(self.start().into() + new_size).into(),
unmap_size,
page_table,
) {
if !self
.backend
.unmap(self.start() + new_size, unmap_size, page_table)
{
return Err(MappingError::BadState);
}
self.va_range.end = (self.va_range.end.into() - unmap_size).into();
self.va_range.end -= unmap_size;
Ok(())
}

Expand All @@ -140,14 +139,10 @@ impl<B: MappingBackend> MemoryArea<B> {
/// Returns `None` if the given position is not in the memory area, or one
/// of the parts is empty after splitting.
pub(crate) fn split(&mut self, pos: B::Addr) -> Option<Self> {
let pos: usize = pos.into();

let start: usize = self.start().into();
let end: usize = self.end().into();
// todo: is it a bug when `pos == end - 1`?
if start < pos && pos < end {
let new_area = Self::new(pos.into(), end - pos, self.flags, self.backend.clone());
self.va_range.end = pos.into();
if self.start() < pos && pos < self.end() {
let new_area = Self::new(pos, self.end() - pos, self.flags, self.backend.clone());
self.va_range.end = pos;
Some(new_area)
} else {
None
Expand Down
57 changes: 27 additions & 30 deletions memory_set/src/set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::{MappingBackend, MappingError, MappingResult, MemoryArea};

/// A container that maintains memory mappings ([`MemoryArea`]).
pub struct MemorySet<B: MappingBackend> {
areas: BTreeMap<usize, MemoryArea<B>>,
areas: BTreeMap<B::Addr, MemoryArea<B>>,
}

impl<B: MappingBackend> MemorySet<B> {
Expand Down Expand Up @@ -37,12 +37,12 @@ impl<B: MappingBackend> MemorySet<B> {

/// Returns whether the given address range overlaps with any existing area.
pub fn overlaps(&self, range: AddrRange<B::Addr>) -> bool {
if let Some((_, before)) = self.areas.range(..range.start.into()).last() {
if let Some((_, before)) = self.areas.range(..range.start).last() {
if before.va_range().overlaps(range) {
return true;
}
}
if let Some((_, after)) = self.areas.range(range.start.into()..).next() {
if let Some((_, after)) = self.areas.range(range.start..).next() {
if after.va_range().overlaps(range) {
return true;
}
Expand All @@ -52,7 +52,7 @@ impl<B: MappingBackend> MemorySet<B> {

/// Finds the memory area that contains the given address.
pub fn find(&self, addr: B::Addr) -> Option<&MemoryArea<B>> {
let candidate = self.areas.range(..=addr.into()).last().map(|(_, a)| a);
let candidate = self.areas.range(..=addr).last().map(|(_, a)| a);
candidate.filter(|a| a.va_range().contains(addr))
}

Expand All @@ -70,16 +70,15 @@ impl<B: MappingBackend> MemorySet<B> {
limit: AddrRange<B::Addr>,
) -> Option<B::Addr> {
// brute force: try each area's end address as the start.
let hint: usize = hint.into();
let mut last_end = hint.max(limit.start.into());
let mut last_end = hint.max(limit.start);
for (addr, area) in self.areas.iter() {
if last_end + size <= *addr {
return Some(last_end.into());
return Some(last_end);
}
last_end = area.end().into();
last_end = area.end();
}
if last_end + size <= limit.end.into() {
Some(last_end.into())
if last_end + size <= limit.end {
Some(last_end)
} else {
None
}
Expand Down Expand Up @@ -112,7 +111,7 @@ impl<B: MappingBackend> MemorySet<B> {
}

area.map_area(page_table)?;
assert!(self.areas.insert(area.start().into(), area).is_none());
assert!(self.areas.insert(area.start(), area).is_none());
Ok(())
}

Expand All @@ -133,8 +132,7 @@ impl<B: MappingBackend> MemorySet<B> {
return Ok(());
}

let start: usize = start.into();
let end = range.end.into();
let end = range.end;

// Unmap entire areas that are contained by the range.
self.areas.retain(|_, area| {
Expand All @@ -147,30 +145,30 @@ impl<B: MappingBackend> MemorySet<B> {
});

// Shrink right if the area intersects with the left boundary.
if let Some((before_start, before)) = self.areas.range_mut(..start).last() {
let before_end = before.end().into();
if let Some((&before_start, before)) = self.areas.range_mut(..start).last() {
let before_end = before.end();
if before_end > start {
if before_end <= end {
// the unmapped area is at the end of `before`.
before.shrink_right(start - before_start, page_table)?;
} else {
// the unmapped area is in the middle `before`, need to split.
let right_part = before.split(end.into()).unwrap();
let right_part = before.split(end).unwrap();
before.shrink_right(start - before_start, page_table)?;
assert_eq!(right_part.start().into(), end);
assert_eq!(right_part.start().into(), Into::<usize>::into(end));
self.areas.insert(end, right_part);
}
}
}

// Shrink left if the area intersects with the right boundary.
if let Some((&after_start, after)) = self.areas.range_mut(start..).next() {
let after_end = after.end().into();
let after_end = after.end();
if after_start < end {
// the unmapped area is at the start of `after`.
let mut new_area = self.areas.remove(&after_start).unwrap();
new_area.shrink_left(after_end - end, page_table)?;
assert_eq!(new_area.start().into(), end);
assert_eq!(new_area.start().into(), Into::<usize>::into(end));
self.areas.insert(end, new_area);
}
}
Expand Down Expand Up @@ -203,12 +201,11 @@ impl<B: MappingBackend> MemorySet<B> {
update_flags: impl Fn(B::Flags) -> Option<B::Flags>,
page_table: &mut B::PageTable,
) -> MappingResult {
let start = start.into();
let end = start + size;
let mut to_insert = Vec::new();
for (area_start, area) in self.areas.iter_mut() {
let area_start = *area_start;
let area_end = area.end().into();
let area_end = area.end();

if let Some(new_flags) = update_flags(area.flags()) {
if area_start >= end {
Expand All @@ -227,32 +224,32 @@ impl<B: MappingBackend> MemorySet<B> {
} else if area_start < start && area_end > end {
// [ prot ]
// [ left | area | right ]
let right_part = area.split(end.into()).unwrap();
area.set_end(start.into());
let right_part = area.split(end).unwrap();
area.set_end(start);

let mut middle_part =
MemoryArea::new(start.into(), size, area.flags(), area.backend().clone());
MemoryArea::new(start, size, area.flags(), area.backend().clone());
middle_part.protect_area(new_flags, page_table)?;
middle_part.set_flags(new_flags);

to_insert.push((right_part.start().into(), right_part));
to_insert.push((middle_part.start().into(), middle_part));
to_insert.push((right_part.start(), right_part));
to_insert.push((middle_part.start(), middle_part));
} else if area_end > end {
// [ prot ]
// [ area | right ]
let right_part = area.split(end.into()).unwrap();
let right_part = area.split(end).unwrap();
area.protect_area(new_flags, page_table)?;
area.set_flags(new_flags);

to_insert.push((right_part.start().into(), right_part));
to_insert.push((right_part.start(), right_part));
} else {
// [ prot ]
// [ left | area ]
let mut right_part = area.split(start.into()).unwrap();
let mut right_part = area.split(start).unwrap();
right_part.protect_area(new_flags, page_table)?;
right_part.set_flags(new_flags);

to_insert.push((right_part.start().into(), right_part));
to_insert.push((right_part.start(), right_part));
}
}
}
Expand Down

0 comments on commit e8a51c4

Please sign in to comment.