Skip to content

Commit

Permalink
Add address range types to crate memory_addr
Browse files Browse the repository at this point in the history
  • Loading branch information
equation314 committed Jun 24, 2024
1 parent 0c3da40 commit 311b24c
Show file tree
Hide file tree
Showing 6 changed files with 515 additions and 318 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion crates/memory_addr/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "memory_addr"
version = "0.1.0"
version = "0.2.0"
edition = "2021"
authors = ["Yuekai Jia <[email protected]>"]
description = "Wrappers and helper functions for physical and virtual addresses"
Expand Down
9 changes: 8 additions & 1 deletion crates/memory_addr/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Wrappers and helper functions for physical and virtual memory addresses.
## Examples

```rust
use memory_addr::{PhysAddr, VirtAddr};
use memory_addr::{PhysAddr, VirtAddr, VirtAddrRange};

let phys_addr = PhysAddr::from(0x12345678);
let virt_addr = VirtAddr::from(0x87654321);
Expand All @@ -17,4 +17,11 @@ assert_eq!(phys_addr.align_offset_4k(), 0x678);
assert_eq!(virt_addr.align_up_4k(), VirtAddr::from(0x87655000));
assert!(!virt_addr.is_aligned_4k());
assert!(VirtAddr::from(0xabcedf0).is_aligned(16usize));

let va_range = VirtAddrRange::from(0x87654000..0x87655000);
assert_eq!(va_range.start(), VirtAddr::from(0x87654000));
assert_eq!(va_range.size(), 0x1000);
assert!(va_range.contains(virt_addr));
assert!(va_range.contains_range(virt_addr, 0x100));
assert!(!va_range.contains_range(virt_addr, 0x1000));
```
319 changes: 319 additions & 0 deletions crates/memory_addr/src/addr.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,319 @@
use core::fmt;
use core::ops::{Add, AddAssign, Sub, SubAssign};

use crate::{align_down, align_offset, align_up, is_aligned, PAGE_SIZE_4K};

/// A physical memory address.
///
/// It's a wrapper type around an `usize`.
#[repr(transparent)]
#[derive(Copy, Clone, Default, Ord, PartialOrd, Eq, PartialEq)]
pub struct PhysAddr(usize);

/// A virtual memory address.
///
/// It's a wrapper type around an `usize`.
#[repr(transparent)]
#[derive(Copy, Clone, Default, Ord, PartialOrd, Eq, PartialEq)]
pub struct VirtAddr(usize);

impl PhysAddr {
/// Converts an `usize` to a physical address.
#[inline]
pub const fn from(addr: usize) -> Self {
Self(addr)
}

/// Converts the address to an `usize`.
#[inline]
pub const fn as_usize(self) -> usize {
self.0
}

/// Aligns the address downwards to the given alignment.
///
/// See the [`align_down`] function for more information.
#[inline]
pub const fn align_down<U>(self, align: U) -> Self
where
U: Into<usize>,
{
Self(align_down(self.0, align.into()))
}

/// Aligns the address upwards to the given alignment.
///
/// See the [`align_up`] function for more information.
#[inline]
pub const fn align_up<U>(self, align: U) -> Self
where
U: Into<usize>,
{
Self(align_up(self.0, align.into()))
}

/// Returns the offset of the address within the given alignment.
///
/// See the [`align_offset`] function for more information.
#[inline]
pub const fn align_offset<U>(self, align: U) -> usize
where
U: Into<usize>,
{
align_offset(self.0, align.into())
}

/// Checks whether the address has the demanded alignment.
///
/// See the [`is_aligned`] function for more information.
#[inline]
pub const fn is_aligned<U>(self, align: U) -> bool
where
U: Into<usize>,
{
is_aligned(self.0, align.into())
}

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

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

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

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

impl VirtAddr {
/// Converts an `usize` to a virtual address.
#[inline]
pub const fn from(addr: usize) -> Self {
Self(addr)
}

/// Converts the address to an `usize`.
#[inline]
pub const fn as_usize(self) -> usize {
self.0
}

/// Converts the virtual address to a raw pointer.
#[inline]
pub const fn as_ptr(self) -> *const u8 {
self.0 as *const u8
}

/// Converts the virtual address to a mutable raw pointer.
#[inline]
pub const fn as_mut_ptr(self) -> *mut u8 {
self.0 as *mut u8
}

/// Aligns the address downwards to the given alignment.
///
/// See the [`align_down`] function for more information.
#[inline]
pub const fn align_down<U>(self, align: U) -> Self
where
U: Into<usize>,
{
Self(align_down(self.0, align.into()))
}

/// Aligns the address upwards to the given alignment.
///
/// See the [`align_up`] function for more information.
#[inline]
pub const fn align_up<U>(self, align: U) -> Self
where
U: Into<usize>,
{
Self(align_up(self.0, align.into()))
}

/// Returns the offset of the address within the given alignment.
///
/// See the [`align_offset`] function for more information.
#[inline]
pub const fn align_offset<U>(self, align: U) -> usize
where
U: Into<usize>,
{
align_offset(self.0, align.into())
}

/// Checks whether the address has the demanded alignment.
///
/// See the [`is_aligned`] function for more information.
#[inline]
pub const fn is_aligned<U>(self, align: U) -> bool
where
U: Into<usize>,
{
is_aligned(self.0, align.into())
}

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

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

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

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

impl From<usize> for PhysAddr {
#[inline]
fn from(addr: usize) -> Self {
Self(addr)
}
}

impl From<usize> for VirtAddr {
#[inline]
fn from(addr: usize) -> Self {
Self(addr)
}
}

impl From<PhysAddr> for usize {
#[inline]
fn from(addr: PhysAddr) -> usize {
addr.0
}
}

impl From<VirtAddr> for usize {
#[inline]
fn from(addr: VirtAddr) -> usize {
addr.0
}
}

impl Add<usize> for PhysAddr {
type Output = Self;
#[inline]
fn add(self, rhs: usize) -> Self {
Self(self.0 + rhs)
}
}

impl AddAssign<usize> for PhysAddr {
#[inline]
fn add_assign(&mut self, rhs: usize) {
*self = *self + rhs;
}
}

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

impl SubAssign<usize> for PhysAddr {
#[inline]
fn sub_assign(&mut self, rhs: usize) {
*self = *self - rhs;
}
}

impl Add<usize> for VirtAddr {
type Output = Self;
#[inline]
fn add(self, rhs: usize) -> Self {
Self(self.0 + rhs)
}
}

impl AddAssign<usize> for VirtAddr {
#[inline]
fn add_assign(&mut self, rhs: usize) {
*self = *self + rhs;
}
}

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

impl SubAssign<usize> for VirtAddr {
#[inline]
fn sub_assign(&mut self, rhs: usize) {
*self = *self - rhs;
}
}

impl fmt::Debug for PhysAddr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_fmt(format_args!("PA:{:#x}", self.0))
}
}

impl fmt::Debug for VirtAddr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_fmt(format_args!("VA:{:#x}", self.0))
}
}

impl fmt::LowerHex for PhysAddr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_fmt(format_args!("PA:{:#x}", self.0))
}
}

impl fmt::UpperHex for PhysAddr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_fmt(format_args!("PA:{:#X}", self.0))
}
}

impl fmt::LowerHex for VirtAddr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_fmt(format_args!("VA:{:#x}", self.0))
}
}

impl fmt::UpperHex for VirtAddr {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_fmt(format_args!("VA:{:#X}", self.0))
}
}
Loading

0 comments on commit 311b24c

Please sign in to comment.