Skip to content

Commit

Permalink
remove arithmetic bounds for MemoryAddr, add some provided methods
Browse files Browse the repository at this point in the history
  • Loading branch information
aarkegz committed Aug 20, 2024
1 parent e8a51c4 commit 77972d9
Show file tree
Hide file tree
Showing 6 changed files with 131 additions and 117 deletions.
184 changes: 88 additions & 96 deletions memory_addr/src/addr.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use core::cmp::Ord;

/// A trait for memory address types.
///
/// Memory address types here include both physical and virtual addresses, as well as any other
Expand All @@ -9,34 +11,90 @@ pub trait MemoryAddr:
+ 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
+ Ord
{
// Empty for now.
}
// No required methods for now. Following are some utility methods.

/// Implement the `MemoryAddr` trait for any type that satisfies the required bounds.
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
{
// About alignment:

/// Aligns the address downwards to the given alignment.
#[inline]
fn align_down<U>(self, align: U) -> Self
where
U: Into<usize>,
{
Self::from(crate::align_down(self.into(), align.into()))
}

/// Aligns the address upwards to the given alignment.
#[inline]
fn align_up<U>(self, align: U) -> Self
where
U: Into<usize>,
{
Self::from(crate::align_up(self.into(), align.into()))
}

/// Returns the offset of the address within the given alignment.
#[inline]
fn align_offset<U>(self, align: U) -> usize
where
U: Into<usize>,
{
crate::align_offset(self.into(), align.into())
}

/// Checks whether the address has the demanded alignment.
#[inline]
fn is_aligned<U>(self, align: U) -> bool
where
U: Into<usize>,
{
crate::is_aligned(self.into(), align.into())
}

/// Aligns the address downwards to 4096 (bytes).
#[inline]
fn align_down_4k(self) -> Self {
Self::from(crate::align_down(self.into(), crate::PAGE_SIZE_4K))
}

/// Aligns the address upwards to 4096 (bytes).
#[inline]
fn align_up_4k(self) -> Self {
Self::from(crate::align_up(self.into(), crate::PAGE_SIZE_4K))
}

/// Returns the offset of the address within a 4K-sized page.
#[inline]
fn align_offset_4k(self) -> usize {
crate::align_offset(self.into(), crate::PAGE_SIZE_4K)
}

/// Checks whether the address is 4K-aligned.
#[inline]
fn is_aligned_4k(self) -> bool {
crate::is_aligned(self.into(), crate::PAGE_SIZE_4K)
}

// About address modification:

/// Adds the given signed offset to the address.
#[inline]
fn offset(self, offset: isize) -> Self {
Self::from(usize::wrapping_add_signed(self.into(), offset))
}

/// Gets the distance between two addresses.
#[inline]
fn sub_addr(self, base: Self) -> usize {
usize::wrapping_sub(self.into(), base.into())
}
}

// Implement the `MemoryAddr` trait for any type that is `Copy`, `From<usize>`, `Into<usize>`, and `Ord`.
impl<T> MemoryAddr for T where T: Copy + From<usize> + Into<usize> + Ord {}

/// Creates a new address type by wrapping an `usize`.
///
/// For each `$vis type $name;`, this macro generates the following items:
Expand All @@ -52,15 +110,11 @@ impl<T> MemoryAddr for T where
/// - Two `const` methods to convert between the address type and `usize`:
/// - `from_usize`, which converts an `usize` to the address type, and
/// - `as_usize`, which converts the address type to an `usize`.
/// - Methods to align the address, namely:
/// - `align_down`, `align_up`, `align_offset`, `is_aligned`, `align_down_4k`, `align_up_4k`,
/// `align_offset_4k`, and `is_aligned_4k`, which correspond to the functions with the same
/// names in the crate root.
///
/// # Example
///
/// ```
/// use memory_addr::def_usize_addr;
/// use memory_addr::{def_usize_addr, MemoryAddr};
///
/// def_usize_addr! {
/// /// A example address type.
Expand Down Expand Up @@ -103,68 +157,6 @@ macro_rules! def_usize_addr {
}
}

impl $name {
/// Aligns the address downwards to the given alignment.
#[inline]
pub fn align_down<U>(self, align: U) -> Self
where
U: Into<usize>,
{
Self::from_usize($crate::align_down(self.0, align.into()))
}

/// Aligns the address upwards to the given alignment.
#[inline]
pub fn align_up<U>(self, align: U) -> Self
where
U: Into<usize>,
{
Self::from_usize($crate::align_up(self.0, align.into()))
}

/// Returns the offset of the address within the given alignment.
#[inline]
pub fn align_offset<U>(self, align: U) -> usize
where
U: Into<usize>,
{
$crate::align_offset(self.0, align.into())
}

/// Checks whether the address has the demanded alignment.
#[inline]
pub fn is_aligned<U>(self, align: U) -> bool
where
U: Into<usize>,
{
$crate::is_aligned(self.0, align.into())
}

/// Aligns the address downwards to 4096 (bytes).
#[inline]
pub const fn align_down_4k(self) -> Self {
Self::from_usize($crate::align_down(self.0, $crate::PAGE_SIZE_4K))
}

/// Aligns the address upwards to 4096 (bytes).
#[inline]
pub const fn align_up_4k(self) -> Self {
Self::from_usize($crate::align_up(self.0, $crate::PAGE_SIZE_4K))
}

/// Returns the offset of the address within a 4K-sized page.
#[inline]
pub const fn align_offset_4k(self) -> usize {
$crate::align_offset(self.0, $crate::PAGE_SIZE_4K)
}

/// Checks whether the address is 4K-aligned.
#[inline]
pub const fn is_aligned_4k(self) -> bool {
$crate::is_aligned(self.0, $crate::PAGE_SIZE_4K)
}
}

impl From<usize> for $name {
#[inline]
fn from(addr: usize) -> Self {
Expand Down Expand Up @@ -247,11 +239,11 @@ macro_rules! def_usize_addr {
/// ExampleAddr = "EA:{}";
/// }
///
/// fn main() {
/// assert_eq!(format!("{:?}", PhysAddr::from(0x1abc)), "PA:0x1abc");
/// assert_eq!(format!("{:x}", VirtAddr::from(0x1abc)), "VA:0x1abc");
/// assert_eq!(format!("{:X}", ExampleAddr::from(0x1abc)), "EA:0x1ABC");
/// }
/// # fn main() {
/// assert_eq!(format!("{:?}", PhysAddr::from(0x1abc)), "PA:0x1abc");
/// assert_eq!(format!("{:x}", VirtAddr::from(0x1abc)), "VA:0x1abc");
/// assert_eq!(format!("{:X}", ExampleAddr::from(0x1abc)), "EA:0x1ABC");
/// # }
/// ```
#[macro_export]
macro_rules! def_usize_addr_formatter {
Expand Down
2 changes: 1 addition & 1 deletion memory_addr/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ pub const fn is_aligned_4k(addr: usize) -> bool {

#[cfg(test)]
mod tests {
use crate::{va, va_range, VirtAddrRange};
use crate::{va, va_range, MemoryAddr, VirtAddrRange};

#[test]
fn test_addr() {
Expand Down
22 changes: 19 additions & 3 deletions memory_addr/src/range.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use crate::{MemoryAddr, PhysAddr, VirtAddr};
/// assert_eq!(range.start, 0x1000);
/// assert_eq!(range.end, 0x2000);
/// ```
#[derive(Clone, Copy, Default, PartialEq, Eq)]
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct AddrRange<A: MemoryAddr> {
/// The lower bound of the range (inclusive).
pub start: A,
Expand Down Expand Up @@ -60,7 +60,7 @@ where
pub fn from_start_size(start: A, size: usize) -> Self {
Self {
start,
end: start + size,
end: start.offset(size as isize),
}
}

Expand Down Expand Up @@ -92,7 +92,7 @@ where
/// ```
#[inline]
pub fn size(self) -> usize {
self.end - self.start
self.end.sub_addr(self.start)
}

/// Checks if the range contains the given address.
Expand Down Expand Up @@ -185,6 +185,22 @@ where
}
}

/// 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 {
start: 0.into(),
end: 0.into(),
}
}
}

/// Implementations of [`fmt::Debug`] for [`AddrRange`].
impl<A> fmt::Debug for AddrRange<A>
where
Expand Down
22 changes: 14 additions & 8 deletions memory_set/src/area.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use core::fmt;

use memory_addr::AddrRange;
use memory_addr::{AddrRange, MemoryAddr};

use crate::{MappingBackend, MappingError, MappingResult};

Expand Down 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 += unmap_size;
self.va_range.start = self.va_range.start.offset(unmap_size as isize);
Ok(())
}

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

Expand All @@ -141,7 +142,12 @@ impl<B: MappingBackend> MemoryArea<B> {
pub(crate) fn split(&mut self, pos: B::Addr) -> Option<Self> {
// todo: is it a bug when `pos == end - 1`?
if self.start() < pos && pos < self.end() {
let new_area = Self::new(pos, self.end() - pos, self.flags, self.backend.clone());
let new_area = Self::new(
pos,
self.end().sub_addr(pos),
self.flags,
self.backend.clone(),
);
self.va_range.end = pos;
Some(new_area)
} else {
Expand Down
16 changes: 8 additions & 8 deletions memory_set/src/set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use alloc::collections::BTreeMap;
use alloc::vec::Vec;
use core::fmt;

use memory_addr::AddrRange;
use memory_addr::{AddrRange, MemoryAddr};

use crate::{MappingBackend, MappingError, MappingResult, MemoryArea};

Expand Down Expand Up @@ -71,13 +71,13 @@ impl<B: MappingBackend> MemorySet<B> {
) -> Option<B::Addr> {
// brute force: try each area's end address as the start.
let mut last_end = hint.max(limit.start);
for (addr, area) in self.areas.iter() {
if last_end + size <= *addr {
for (&addr, area) in self.areas.iter() {
if last_end.offset(size as isize) <= addr {
return Some(last_end);
}
last_end = area.end();
}
if last_end + size <= limit.end {
if last_end.offset(size as isize) <= limit.end {
Some(last_end)
} else {
None
Expand Down Expand Up @@ -150,11 +150,11 @@ impl<B: MappingBackend> MemorySet<B> {
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)?;
before.shrink_right(start.sub_addr(before_start), page_table)?;
} else {
// the unmapped area is in the middle `before`, need to split.
let right_part = before.split(end).unwrap();
before.shrink_right(start - before_start, page_table)?;
before.shrink_right(start.sub_addr(before_start), page_table)?;
assert_eq!(right_part.start().into(), Into::<usize>::into(end));
self.areas.insert(end, right_part);
}
Expand All @@ -167,7 +167,7 @@ impl<B: MappingBackend> MemorySet<B> {
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)?;
new_area.shrink_left(after_end.sub_addr(end), page_table)?;
assert_eq!(new_area.start().into(), Into::<usize>::into(end));
self.areas.insert(end, new_area);
}
Expand Down Expand Up @@ -201,7 +201,7 @@ impl<B: MappingBackend> MemorySet<B> {
update_flags: impl Fn(B::Flags) -> Option<B::Flags>,
page_table: &mut B::PageTable,
) -> MappingResult {
let end = start + size;
let end = start.offset(size as isize);
let mut to_insert = Vec::new();
for (area_start, area) in self.areas.iter_mut() {
let area_start = *area_start;
Expand Down
2 changes: 1 addition & 1 deletion memory_set/src/tests.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use memory_addr::VirtAddr;
use memory_addr::{MemoryAddr, VirtAddr};

use crate::{MappingBackend, MappingError, MemoryArea, MemorySet};

Expand Down

0 comments on commit 77972d9

Please sign in to comment.