From e8a51c4e08e6ce492f5e16bac844c836d751d30d Mon Sep 17 00:00:00 2001 From: aarkegz Date: Tue, 20 Aug 2024 22:05:44 +0800 Subject: [PATCH] demo: what if we add more bounds to `MemoryAddr` --- memory_addr/src/addr.rs | 32 +++++++++++++++++++++- memory_addr/src/range.rs | 49 +++++----------------------------- memory_set/src/area.rs | 23 +++++++--------- memory_set/src/set.rs | 57 +++++++++++++++++++--------------------- 4 files changed, 74 insertions(+), 87 deletions(-) diff --git a/memory_addr/src/addr.rs b/memory_addr/src/addr.rs index 9ca3861..268373f 100644 --- a/memory_addr/src/addr.rs +++ b/memory_addr/src/addr.rs @@ -8,12 +8,34 @@ pub trait MemoryAddr: // The address type should be convertible to and from `usize`. + From + Into + // The address type should be comparable. + + core::cmp::Ord + // The address type should support arithmetic operations with `usize`. + + core::ops::Add + + core::ops::AddAssign + + core::ops::Sub + + core::ops::SubAssign + + core::ops::Sub + // 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 MemoryAddr for T where T: Copy + From + Into {} +impl MemoryAddr for T where + T: Copy + + From + + Into + + core::cmp::Ord + + core::ops::Add + + core::ops::AddAssign + + core::ops::Sub + + core::ops::SubAssign + + core::ops::Sub + + Default +{ +} /// Creates a new address type by wrapping an `usize`. /// @@ -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)*); }; () => {}; diff --git a/memory_addr/src/range.rs b/memory_addr/src/range.rs index 29ee1f4..dcba825 100644 --- a/memory_addr/src/range.rs +++ b/memory_addr/src/range.rs @@ -2,12 +2,6 @@ use core::{fmt, ops::Range}; use crate::{MemoryAddr, PhysAddr, VirtAddr}; -macro_rules! usize { - ($addr:expr) => { - Into::::into($addr) - }; -} - /// A range of a given memory address type `A`. /// /// The range is inclusive on the start and exclusive on the end. @@ -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 { /// The lower bound of the range (inclusive). pub start: A, @@ -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, } } @@ -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. @@ -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. @@ -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. @@ -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. @@ -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 Default for AddrRange -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 PartialEq for AddrRange -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 Eq for AddrRange where A: MemoryAddr {} - /// Implementations of [`From`] for [`AddrRange`] and [`Range`]. /// /// Converts a range into an address range. diff --git a/memory_set/src/area.rs b/memory_set/src/area.rs index b439bee..e4b4e76 100644 --- a/memory_set/src/area.rs +++ b/memory_set/src/area.rs @@ -107,7 +107,7 @@ impl MemoryArea { 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(()) } @@ -121,14 +121,13 @@ impl MemoryArea { 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(()) } @@ -140,14 +139,10 @@ impl MemoryArea { /// 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 { - 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 diff --git a/memory_set/src/set.rs b/memory_set/src/set.rs index a6ae04a..ebd7db3 100644 --- a/memory_set/src/set.rs +++ b/memory_set/src/set.rs @@ -9,7 +9,7 @@ use crate::{MappingBackend, MappingError, MappingResult, MemoryArea}; /// A container that maintains memory mappings ([`MemoryArea`]). pub struct MemorySet { - areas: BTreeMap>, + areas: BTreeMap>, } impl MemorySet { @@ -37,12 +37,12 @@ impl MemorySet { /// Returns whether the given address range overlaps with any existing area. pub fn overlaps(&self, range: AddrRange) -> 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; } @@ -52,7 +52,7 @@ impl MemorySet { /// Finds the memory area that contains the given address. pub fn find(&self, addr: B::Addr) -> Option<&MemoryArea> { - 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)) } @@ -70,16 +70,15 @@ impl MemorySet { limit: AddrRange, ) -> Option { // 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 } @@ -112,7 +111,7 @@ impl MemorySet { } 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(()) } @@ -133,8 +132,7 @@ impl MemorySet { 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| { @@ -147,17 +145,17 @@ impl MemorySet { }); // 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::::into(end)); self.areas.insert(end, right_part); } } @@ -165,12 +163,12 @@ impl MemorySet { // 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::::into(end)); self.areas.insert(end, new_area); } } @@ -203,12 +201,11 @@ impl MemorySet { update_flags: impl Fn(B::Flags) -> Option, 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 { @@ -227,32 +224,32 @@ impl MemorySet { } 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)); } } }