From 4cb9cd6c9fb0f27015835d584cc336d59a9242ca Mon Sep 17 00:00:00 2001 From: ZIYAN137 Date: Fri, 17 Oct 2025 16:38:34 +0000 Subject: [PATCH 01/10] =?UTF-8?q?feat(mm):=20=E5=AE=9A=E4=B9=89=E6=93=8D?= =?UTF-8?q?=E4=BD=9C=E7=9B=B8=E5=85=B3trait=E5=B9=B6=E5=AE=9E=E7=8E=B0impl?= =?UTF-8?q?=E5=AE=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- os/src/main.rs | 1 + os/src/mm/address/.gitkeep | 0 os/src/mm/address/mod.rs | 1 + os/src/mm/address/operations.rs | 242 ++++++++++++++++++++++++++++++++ os/src/mm/mod.rs | 1 + 5 files changed, 245 insertions(+) delete mode 100644 os/src/mm/address/.gitkeep create mode 100644 os/src/mm/address/mod.rs create mode 100644 os/src/mm/address/operations.rs create mode 100644 os/src/mm/mod.rs diff --git a/os/src/main.rs b/os/src/main.rs index e4bcce04..d0568ac8 100644 --- a/os/src/main.rs +++ b/os/src/main.rs @@ -8,6 +8,7 @@ mod console; mod sbi; mod config; +mod mm; use core::arch::global_asm; use core::panic::PanicInfo; diff --git a/os/src/mm/address/.gitkeep b/os/src/mm/address/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/os/src/mm/address/mod.rs b/os/src/mm/address/mod.rs new file mode 100644 index 00000000..059ed62b --- /dev/null +++ b/os/src/mm/address/mod.rs @@ -0,0 +1 @@ +mod operations; \ No newline at end of file diff --git a/os/src/mm/address/operations.rs b/os/src/mm/address/operations.rs new file mode 100644 index 00000000..4580d80b --- /dev/null +++ b/os/src/mm/address/operations.rs @@ -0,0 +1,242 @@ +use core::ops::{ + Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Shl, ShlAssign, + Shr, ShrAssign, Sub, SubAssign, +}; +use crate::config::PAGE_SIZE; + +// convert between usize and the type +pub trait UsizeConvert: Copy + Clone + PartialEq + PartialOrd + Eq + Ord { + fn as_usize(&self) -> usize; + fn from_usize(value: usize) -> Self; +} + +// arithmetic and bitwise operations +pub trait CalcOps: + UsizeConvert + + Add + + Add + + AddAssign + + AddAssign + + Sub + + Sub + + SubAssign + + SubAssign + + BitAnd + + BitAnd + + BitAndAssign + + BitAndAssign + + BitOr + + BitOr + + BitOrAssign + + BitOrAssign + + BitXor + + BitXor + + BitXorAssign + + BitXorAssign + + Shl + + ShlAssign + + Shr + + ShrAssign +{ +} + +// macro to implement arithmetic and bitwise operations +#[macro_export] +macro_rules! impl_calc_ops { + ($type:ty) => { + impl core::ops::Add for $type { + type Output = Self; + fn add(self, rhs: usize) -> Self::Output { + $crate::mm::address::operations::UsizeConvert::from_usize(self.as_usize() + rhs) + } + } + impl core::ops::Add for $type { + type Output = Self; + fn add(self, rhs: Self) -> Self::Output { + $crate::mm::address::operations::UsizeConvert::from_usize( + self.as_usize() + rhs.as_usize(), + ) + } + } + impl core::ops::AddAssign for $type { + fn add_assign(&mut self, rhs: usize) { + *self = + $crate::mm::address::operations::UsizeConvert::from_usize(self.as_usize() + rhs) + } + } + impl core::ops::AddAssign for $type { + fn add_assign(&mut self, rhs: Self) { + *self = $crate::mm::address::operations::UsizeConvert::from_usize( + self.as_usize() + rhs.as_usize(), + ) + } + } + impl core::ops::Sub for $type { + type Output = Self; + fn sub(self, rhs: usize) -> Self::Output { + $crate::mm::address::operations::UsizeConvert::from_usize(self.as_usize() - rhs) + } + } + impl core::ops::Sub for $type { + type Output = Self; + fn sub(self, rhs: Self) -> Self::Output { + $crate::mm::address::operations::UsizeConvert::from_usize( + self.as_usize() - rhs.as_usize(), + ) + } + } + impl core::ops::SubAssign for $type { + fn sub_assign(&mut self, rhs: usize) { + *self = + $crate::mm::address::operations::UsizeConvert::from_usize(self.as_usize() - rhs) + } + } + impl core::ops::SubAssign for $type { + fn sub_assign(&mut self, rhs: Self) { + *self = $crate::mm::address::operations::UsizeConvert::from_usize( + self.as_usize() - rhs.as_usize(), + ) + } + } + impl core::ops::BitAnd for $type { + type Output = Self; + fn bitand(self, rhs: usize) -> Self::Output { + $crate::mm::address::operations::UsizeConvert::from_usize(self.as_usize() & rhs) + } + } + impl core::ops::BitAnd for $type { + type Output = Self; + fn bitand(self, rhs: Self) -> Self::Output { + $crate::mm::address::operations::UsizeConvert::from_usize( + self.as_usize() & rhs.as_usize(), + ) + } + } + impl core::ops::BitAndAssign for $type { + fn bitand_assign(&mut self, rhs: usize) { + *self = + $crate::mm::address::operations::UsizeConvert::from_usize(self.as_usize() & rhs) + } + } + impl core::ops::BitAndAssign for $type { + fn bitand_assign(&mut self, rhs: Self) { + *self = $crate::mm::address::operations::UsizeConvert::from_usize( + self.as_usize() & rhs.as_usize(), + ) + } + } + impl core::ops::BitOr for $type { + type Output = Self; + fn bitor(self, rhs: usize) -> Self::Output { + $crate::mm::address::operations::UsizeConvert::from_usize(self.as_usize() | rhs) + } + } + impl core::ops::BitOr for $type { + type Output = Self; + fn bitor(self, rhs: Self) -> Self::Output { + $crate::mm::address::operations::UsizeConvert::from_usize( + self.as_usize() | rhs.as_usize(), + ) + } + } + impl core::ops::BitOrAssign for $type { + fn bitor_assign(&mut self, rhs: usize) { + *self = + $crate::mm::address::operations::UsizeConvert::from_usize(self.as_usize() | rhs) + } + } + impl core::ops::BitOrAssign for $type { + fn bitor_assign(&mut self, rhs: Self) { + *self = $crate::mm::address::operations::UsizeConvert::from_usize( + self.as_usize() | rhs.as_usize(), + ) + } + } + impl core::ops::BitXor for $type { + type Output = Self; + fn bitxor(self, rhs: usize) -> Self::Output { + $crate::mm::address::operations::UsizeConvert::from_usize(self.as_usize() ^ rhs) + } + } + impl core::ops::BitXor for $type { + type Output = Self; + fn bitxor(self, rhs: Self) -> Self::Output { + $crate::mm::address::operations::UsizeConvert::from_usize( + self.as_usize() ^ rhs.as_usize(), + ) + } + } + impl core::ops::BitXorAssign for $type { + fn bitxor_assign(&mut self, rhs: usize) { + *self = + $crate::mm::address::operations::UsizeConvert::from_usize(self.as_usize() ^ rhs) + } + } + impl core::ops::BitXorAssign for $type { + fn bitxor_assign(&mut self, rhs: Self) { + *self = $crate::mm::address::operations::UsizeConvert::from_usize( + self.as_usize() ^ rhs.as_usize(), + ) + } + } + impl core::ops::Shl for $type { + type Output = Self; + fn shl(self, rhs: usize) -> Self::Output { + $crate::mm::address::operations::UsizeConvert::from_usize(self.as_usize() << rhs) + } + } + impl core::ops::ShlAssign for $type { + fn shl_assign(&mut self, rhs: usize) { + *self = $crate::mm::address::operations::UsizeConvert::from_usize( + self.as_usize() << rhs, + ) + } + } + impl core::ops::Shr for $type { + type Output = Self; + fn shr(self, rhs: usize) -> Self::Output { + $crate::mm::address::operations::UsizeConvert::from_usize(self.as_usize() >> rhs) + } + } + impl core::ops::ShrAssign for $type { + fn shr_assign(&mut self, rhs: usize) { + *self = $crate::mm::address::operations::UsizeConvert::from_usize( + self.as_usize() >> rhs, + ) + } + } + }; +} + +// alignment operations +pub trait AlignOps: UsizeConvert { + // check if the address is aligned to the given alignment + fn is_aligned(self, alignment: usize) -> bool { + debug_assert!(alignment.is_power_of_two(), "alignment must be a power of two"); + let mask = alignment - 1; + self.as_usize() & mask == 0 + } + fn is_page_aligned(self) -> bool { + self.is_aligned(PAGE_SIZE) + } + // align the address up to the given alignment + fn align_up(self, alignment: usize) -> Self { + debug_assert!(alignment.is_power_of_two(), "alignment must be a power of two"); + let mask = alignment - 1; + Self::from_usize((self.as_usize() + mask) & !mask) + } + // align the address down to the given alignment + fn align_down(self, alignment: usize) -> Self { + debug_assert!(alignment.is_power_of_two(), "alignment must be a power of two"); + let mask = alignment - 1; + Self::from_usize(self.as_usize() & !mask) + } + // align the address up to the page size + fn align_up_to_page(self) -> Self { + self.align_up(PAGE_SIZE) + } + // align the address down to the page size + fn align_down_to_page(self) -> Self { + self.align_down(PAGE_SIZE) + } +} diff --git a/os/src/mm/mod.rs b/os/src/mm/mod.rs new file mode 100644 index 00000000..0fda4d55 --- /dev/null +++ b/os/src/mm/mod.rs @@ -0,0 +1 @@ +mod address; \ No newline at end of file From 79a7e3f7cc765e13b878f2bd24e1f7e72990f81a Mon Sep 17 00:00:00 2001 From: ZIYAN137 Date: Fri, 17 Oct 2025 16:57:24 +0000 Subject: [PATCH 02/10] =?UTF-8?q?style(mm):=20=E5=AF=B9=20operations.rs=20?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E6=A0=BC=E5=BC=8F=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- os/src/mm/address/operations.rs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/os/src/mm/address/operations.rs b/os/src/mm/address/operations.rs index 4580d80b..d7fc3cfa 100644 --- a/os/src/mm/address/operations.rs +++ b/os/src/mm/address/operations.rs @@ -1,8 +1,8 @@ +use crate::config::PAGE_SIZE; use core::ops::{ Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Shl, ShlAssign, Shr, ShrAssign, Sub, SubAssign, }; -use crate::config::PAGE_SIZE; // convert between usize and the type pub trait UsizeConvert: Copy + Clone + PartialEq + PartialOrd + Eq + Ord { @@ -212,7 +212,10 @@ macro_rules! impl_calc_ops { pub trait AlignOps: UsizeConvert { // check if the address is aligned to the given alignment fn is_aligned(self, alignment: usize) -> bool { - debug_assert!(alignment.is_power_of_two(), "alignment must be a power of two"); + debug_assert!( + alignment.is_power_of_two(), + "alignment must be a power of two" + ); let mask = alignment - 1; self.as_usize() & mask == 0 } @@ -221,13 +224,19 @@ pub trait AlignOps: UsizeConvert { } // align the address up to the given alignment fn align_up(self, alignment: usize) -> Self { - debug_assert!(alignment.is_power_of_two(), "alignment must be a power of two"); + debug_assert!( + alignment.is_power_of_two(), + "alignment must be a power of two" + ); let mask = alignment - 1; Self::from_usize((self.as_usize() + mask) & !mask) } // align the address down to the given alignment fn align_down(self, alignment: usize) -> Self { - debug_assert!(alignment.is_power_of_two(), "alignment must be a power of two"); + debug_assert!( + alignment.is_power_of_two(), + "alignment must be a power of two" + ); let mask = alignment - 1; Self::from_usize(self.as_usize() & !mask) } From ce8ed33df8194e4da2de9ea2b36d9ead9640019c Mon Sep 17 00:00:00 2001 From: ZIYAN137 Date: Sat, 18 Oct 2025 01:22:44 +0000 Subject: [PATCH 03/10] =?UTF-8?q?fix(mm):=20=E4=BF=AE=E5=A4=8Dimpl=5Fcalc?= =?UTF-8?q?=5Fops=E5=AE=8F=E6=9C=AA=E5=AE=9E=E7=8E=B0=E8=87=AA=E8=BA=ABCal?= =?UTF-8?q?cOps=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- os/src/mm/address/operations.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/os/src/mm/address/operations.rs b/os/src/mm/address/operations.rs index d7fc3cfa..9dad05bb 100644 --- a/os/src/mm/address/operations.rs +++ b/os/src/mm/address/operations.rs @@ -205,6 +205,7 @@ macro_rules! impl_calc_ops { ) } } + impl $crate::mm::address::operations::CalcOps for $type {} }; } From 6fd0254eac0eb4e52ad9dd18b40890f23bf0dea8 Mon Sep 17 00:00:00 2001 From: ZIYAN137 Date: Sat, 18 Oct 2025 01:49:26 +0000 Subject: [PATCH 04/10] =?UTF-8?q?feat(mm):=20=E5=AE=9E=E7=8E=B0Vaddr?= =?UTF-8?q?=E5=92=8CPaddr?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- os/src/mm/address/address.rs | 141 +++++++++++++++++++++++++++++++++++ os/src/mm/address/mod.rs | 6 +- 2 files changed, 146 insertions(+), 1 deletion(-) create mode 100644 os/src/mm/address/address.rs diff --git a/os/src/mm/address/address.rs b/os/src/mm/address/address.rs new file mode 100644 index 00000000..957e0db2 --- /dev/null +++ b/os/src/mm/address/address.rs @@ -0,0 +1,141 @@ +use crate::mm::address::operations::{AlignOps, CalcOps, UsizeConvert}; +use core::mem::size_of; +use core::ops::Range; + +// trait to represent an address +pub trait Address: + CalcOps + AlignOps + UsizeConvert + Copy + Clone + PartialEq + PartialOrd + Eq + Ord +{ + fn is_null(self) -> bool { + self.as_usize() == 0 + } + + fn null() -> Self { + Self::from_usize(0) + } + + fn page_offset(self) -> usize { + self.as_usize() & (crate::config::PAGE_SIZE - 1) + } + + fn addr_diff(self, other: Self) -> isize { + self.as_usize() as isize - other.as_usize() as isize + } + + fn add(self) -> Self { + self.add_by(size_of::()) + } + + fn add_n(self, n: usize) -> Self { + self.add_by(size_of::() * n) + } + + fn add_by(self, offset: usize) -> Self { + Self::from_usize(self.as_usize() + offset) + } + + fn sub(self) -> Self { + self.sub_by(size_of::()) + } + + fn sub_n(self, n: usize) -> Self { + self.sub_by(size_of::() * n) + } + + fn sub_by(self, offset: usize) -> Self { + Self::from_usize(self.as_usize() - offset) + } + + fn step(&mut self) { + self.step_by(size_of::()) + } + + fn step_n(&mut self, n: usize) { + self.step_by(size_of::() * n) + } + + fn step_back(&mut self) { + self.step_back_by(size_of::()) + } + + fn step_back_n(&mut self, n: usize) { + self.step_back_by(size_of::() * n) + } + + fn step_by(&mut self, offset: usize) { + *self = self.add_by(offset); + } + + fn step_back_by(&mut self, offset: usize) { + *self = self.sub_by(offset); + } +} + +#[macro_export] +macro_rules! impl_address { + ($type:ty) => { + impl $crate::mm::address::operations::UsizeConvert for $type { + fn as_usize(&self) -> usize { + unsafe { core::mem::transmute::(*self) } + } + fn from_usize(value: usize) -> Self { + unsafe { core::mem::transmute::(value) } + } + } + + $crate::impl_calc_ops!($type); + impl $crate::mm::address::operations::AlignOps for $type {} + + impl $crate::mm::address::address::Address for $type {} + + unsafe impl Sync for $type {} + unsafe impl Send for $type {} + }; +} + +// physical address +#[repr(transparent)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct Paddr(*const ()); +impl_address!(Paddr); + +// virtual address +#[repr(transparent)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct Vaddr(*const ()); +impl_address!(Vaddr); + +impl Vaddr { + // from_ref + pub fn from_ref(r: &T) -> Self { + Self::from_ptr(r as *const T) + } + + // from_ptr + pub fn from_ptr(p: *const T) -> Self { + Self::from_usize(p as usize) + } + + // as_ref + // the caller must ensure that the address is valid for type T + pub unsafe fn as_ref(&self) -> &T { + &*(self.as_usize() as *const T) + } + + // as_mut + // the caller must ensure that the address is valid for type T + pub unsafe fn as_mut(&mut self) -> &mut T { + &mut *(self.as_usize() as *mut T) + } + + // as_ptr + pub fn as_ptr(&self) -> *const T { + self.as_usize() as *const T + } + + // as_mut_ptr + // the caller must ensure that the address is valid for type T + pub unsafe fn as_mut_ptr(&mut self) -> *mut T { + self.as_usize() as *mut T + } +} diff --git a/os/src/mm/address/mod.rs b/os/src/mm/address/mod.rs index 059ed62b..5792950e 100644 --- a/os/src/mm/address/mod.rs +++ b/os/src/mm/address/mod.rs @@ -1 +1,5 @@ -mod operations; \ No newline at end of file +mod operations; +mod address; + +pub use operations::{AlignOps, CalcOps, UsizeConvert}; +pub use address::{Vaddr, Paddr}; \ No newline at end of file From 3b930f93035d6a3552446a36133216c0e29599ac Mon Sep 17 00:00:00 2001 From: ZIYAN137 Date: Sat, 18 Oct 2025 14:03:26 +0000 Subject: [PATCH 05/10] =?UTF-8?q?feat(mm):=20=E5=AE=9E=E7=8E=B0Vpn?= =?UTF-8?q?=E5=92=8CPpn?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- os/src/mm/address/mod.rs | 4 +- os/src/mm/address/page_num.rs | 80 +++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 os/src/mm/address/page_num.rs diff --git a/os/src/mm/address/mod.rs b/os/src/mm/address/mod.rs index 5792950e..37ca974f 100644 --- a/os/src/mm/address/mod.rs +++ b/os/src/mm/address/mod.rs @@ -1,5 +1,7 @@ mod operations; mod address; +mod page_num; pub use operations::{AlignOps, CalcOps, UsizeConvert}; -pub use address::{Vaddr, Paddr}; \ No newline at end of file +pub use address::{Vaddr, Paddr, Address}; +pub use page_num::{Vpn, Ppn, PageNum}; \ No newline at end of file diff --git a/os/src/mm/address/page_num.rs b/os/src/mm/address/page_num.rs new file mode 100644 index 00000000..f0dc69dc --- /dev/null +++ b/os/src/mm/address/page_num.rs @@ -0,0 +1,80 @@ +use crate::config::PAGE_SIZE; +use crate::mm::address::address::{Address, Vaddr, Paddr}; +use crate::mm::address::operations::{AlignOps, CalcOps, UsizeConvert}; + +// TODO: implement the trait +// trait to represent an page number +pub trait PageNum: + CalcOps + UsizeConvert + Copy + Clone + PartialEq + PartialOrd + Eq + Ord +{ + type TAddress: Address; + + fn step(&mut self) { + self.step_by(1); + } + + fn step_by(&mut self, offset: usize) { + *self = Self::from_usize(self.as_usize() + offset); + } + + fn step_back(&mut self) { + self.step_back_by(1); + } + + fn step_back_by(&mut self, offset: usize) { + *self = Self::from_usize(self.as_usize() - offset); + } + + fn from_addr_floor(addr: Self::TAddress) -> Self { + Self::from_usize(addr.align_down_to_page().as_usize() / PAGE_SIZE) + } + + fn from_addr_ceil(addr: Self::TAddress) -> Self { + Self::from_usize(addr.align_up_to_page().as_usize() / PAGE_SIZE) + } + + fn start_addr(self) -> Self::TAddress { + Self::TAddress::from_usize(self.as_usize() * PAGE_SIZE) + } + + fn end_addr(self) -> Self::TAddress { + Self::TAddress::from_usize((self.as_usize() + 1) * PAGE_SIZE) + } + + fn diff(self, other: Self) -> isize { + self.as_usize() as isize - other.as_usize() as isize + } +} + +#[macro_export] +macro_rules! impl_page_num { + ($type:ty, $addr_type:ty) => { + impl $crate::mm::address::operations::UsizeConvert for $type { + fn as_usize(&self) -> usize { + self.0 + } + + fn from_usize(value: usize) -> Self { + Self(value) + } + } + + $crate::impl_calc_ops!($type); + + impl $crate::mm::address::page_num::PageNum for $type { + type TAddress = $addr_type; + } + }; +} + +// phyical page number +#[repr(transparent)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] +pub struct Ppn(pub usize); +impl_page_num!(Ppn, Paddr); + +// virtual page number +#[repr(transparent)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] +pub struct Vpn(pub usize); +impl_page_num!(Vpn, Vaddr); \ No newline at end of file From 1d42e4d996fd8a04d877308a001727728c24cbd5 Mon Sep 17 00:00:00 2001 From: ZIYAN137 Date: Sat, 18 Oct 2025 14:04:30 +0000 Subject: [PATCH 06/10] =?UTF-8?q?Docs(mm):=20=E7=A7=BB=E9=99=A4PageNum?= =?UTF-8?q?=E7=9A=84TODO=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- os/src/mm/address/page_num.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/os/src/mm/address/page_num.rs b/os/src/mm/address/page_num.rs index f0dc69dc..a693767b 100644 --- a/os/src/mm/address/page_num.rs +++ b/os/src/mm/address/page_num.rs @@ -2,7 +2,6 @@ use crate::config::PAGE_SIZE; use crate::mm::address::address::{Address, Vaddr, Paddr}; use crate::mm::address::operations::{AlignOps, CalcOps, UsizeConvert}; -// TODO: implement the trait // trait to represent an page number pub trait PageNum: CalcOps + UsizeConvert + Copy + Clone + PartialEq + PartialOrd + Eq + Ord From efca267c0ecc2a85f19fd216174d3a2d9fe89de7 Mon Sep 17 00:00:00 2001 From: ZIYAN137 Date: Sat, 18 Oct 2025 14:51:26 +0000 Subject: [PATCH 07/10] =?UTF-8?q?feat(mm):=20=E5=AE=9E=E7=8E=B0=20AddressR?= =?UTF-8?q?ange?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- os/src/mm/address/address.rs | 154 +++++++++++++++++++++++++++++++++++ os/src/mm/address/mod.rs | 6 +- 2 files changed, 157 insertions(+), 3 deletions(-) diff --git a/os/src/mm/address/address.rs b/os/src/mm/address/address.rs index 957e0db2..fe16fc1a 100644 --- a/os/src/mm/address/address.rs +++ b/os/src/mm/address/address.rs @@ -139,3 +139,157 @@ impl Vaddr { self.as_usize() as *mut T } } + +// trait to represent an address range +#[repr(C)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct AddressRange +where + T: Address, +{ + start: T, + end: T, +} + +// TODO: implement methods for AddressRange +impl AddressRange +where + T: Address, +{ + pub fn new(start: T, end: T) -> Self { + Self { + start, + end, + } + } + + pub fn from_range(range: Range) -> Self { + Self { + start: range.start, + end: range.end, + } + } + + pub fn from_start_len(start: T, len: usize) -> Self { + Self { + start, + end: T::from_usize(start.as_usize() + len), + } + } + + pub fn from_slices(slices: &[T]) -> Option { + if slices.len() < 2 { + return None; + } + Some(Self { + start: slices[0], + end: slices[slices.len() - 1], + }) + } + + pub fn start(&self) -> T { + self.start + } + + pub fn end(&self) -> T { + self.end + } + + pub fn len(&self) -> usize { + debug_assert!(self.end.as_usize() >= self.start.as_usize()); + self.end.as_usize() - self.start.as_usize() + } + + pub fn empty(&self) -> bool { + self.start == self.end + } + + pub fn contains(&self, addr: T) -> bool { + addr >= self.start && addr < self.end + } + + pub fn contains_range(&self, other: &Self) -> bool { + other.start >= self.start && other.end <= self.end + } + + pub fn contains_in(&self, other: &Self) -> bool { + self.start >= other.start && self.end <= other.end + } + + pub fn intersects(&self, other: &Self) -> bool { + self.start < other.end && other.start < self.end + } + + pub fn adjacent(&self, other: &Self) -> bool { + self.end == other.start || other.end == self.start + } + + pub fn intersection(&self, other: &Self) -> Option { + if !self.intersects(other) { + return None; + } + let start = core::cmp::max(self.start, other.start); + let end = core::cmp::min(self.end, other.end); + Some(Self { start, end }) + } + + pub fn union(&self, other: &Self) -> Option { + if !self.intersects(other) && !self.adjacent(other) { + return None; + } + let start = core::cmp::min(self.start, other.start); + let end = core::cmp::max(self.end, other.end); + Some(Self { start, end }) + } + + // comment out for now + pub fn iter(&self) -> AddressRangeIterator { + AddressRangeIterator { + range: *self, + current: self.start, + } + } +} + +impl IntoIterator for AddressRange +where + T: Address, +{ + type Item = T; + type IntoIter = AddressRangeIterator; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +// iterator for address range +pub struct AddressRangeIterator +where + T: Address, +{ + range: AddressRange, + current: T, +} + +impl Iterator for AddressRangeIterator +where + T: Address, +{ + type Item = T; + + fn next(&mut self) -> Option { + if self.current >= self.range.end { + return None; + } + let addr = self.current; + self.current.step(); + Some(addr) + } +} + +// physical address range +pub type PaddrRange = AddressRange; + +// virtual address range +pub type VaddrRange = AddressRange; diff --git a/os/src/mm/address/mod.rs b/os/src/mm/address/mod.rs index 37ca974f..8e9adbbd 100644 --- a/os/src/mm/address/mod.rs +++ b/os/src/mm/address/mod.rs @@ -1,7 +1,7 @@ -mod operations; mod address; +mod operations; mod page_num; +pub use address::{Address, AddressRange, Paddr, PaddrRange, Vaddr, VaddrRange}; pub use operations::{AlignOps, CalcOps, UsizeConvert}; -pub use address::{Vaddr, Paddr, Address}; -pub use page_num::{Vpn, Ppn, PageNum}; \ No newline at end of file +pub use page_num::{PageNum, Ppn, Vpn}; From 5385aed0a633f53c53c4b3ecb734a171f2598440 Mon Sep 17 00:00:00 2001 From: ZIYAN137 Date: Sat, 18 Oct 2025 14:58:34 +0000 Subject: [PATCH 08/10] =?UTF-8?q?feat(mm):=20=E5=AE=9E=E7=8E=B0=20PageNumR?= =?UTF-8?q?ange?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- os/src/mm/address/page_num.rs | 105 +++++++++++++++++++++++++++++++++- 1 file changed, 103 insertions(+), 2 deletions(-) diff --git a/os/src/mm/address/page_num.rs b/os/src/mm/address/page_num.rs index a693767b..7f5cdbaa 100644 --- a/os/src/mm/address/page_num.rs +++ b/os/src/mm/address/page_num.rs @@ -1,6 +1,7 @@ use crate::config::PAGE_SIZE; -use crate::mm::address::address::{Address, Vaddr, Paddr}; +use crate::mm::address::address::{Address, Paddr, Vaddr}; use crate::mm::address::operations::{AlignOps, CalcOps, UsizeConvert}; +use core::ops::Range; // trait to represent an page number pub trait PageNum: @@ -76,4 +77,104 @@ impl_page_num!(Ppn, Paddr); #[repr(transparent)] #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] pub struct Vpn(pub usize); -impl_page_num!(Vpn, Vaddr); \ No newline at end of file +impl_page_num!(Vpn, Vaddr); + +// trait to represent a range of page numbers +#[repr(C)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct PageNumRange +where + T: PageNum, +{ + pub start: T, + pub end: T, +} + +// TODO: implement methods for PageNumRange +impl PageNumRange +where + T: PageNum, +{ + pub fn new(start: T, end: T) -> Self { + Self { start, end } + } + + pub fn from_range(range: Range) -> Self { + Self { + start: range.start, + end: range.end, + } + } + + pub fn from_start_len(start: T, len: usize) -> Self { + Self { + start, + end: T::from_usize(start.as_usize() + len), + } + } + + pub fn len(&self) -> usize { + debug_assert!(self.end.as_usize() >= self.start.as_usize()); + self.end.as_usize() - self.start.as_usize() + } + + pub fn empty(&self) -> bool { + self.start == self.end + } + + pub fn contains(&self, addr: T) -> bool { + addr >= self.start && addr < self.end + } + + pub fn contains_range(&self, other: &Self) -> bool { + other.start >= self.start && other.end <= self.end + } + + pub fn contains_in(&self, other: &Self) -> bool { + self.start >= other.start && self.end <= other.end + } + + pub fn iter(&self) -> PageNumRangeIterator { + PageNumRangeIterator { + range: *self, + current: self.start, + } + } +} + +impl IntoIterator for PageNumRange +where + T: PageNum, +{ + type Item = T; + type IntoIter = PageNumRangeIterator; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +// iterator for PageNumRange +pub struct PageNumRangeIterator +where + T: PageNum, +{ + range: PageNumRange, + current: T, +} + +impl Iterator for PageNumRangeIterator +where + T: PageNum, +{ + type Item = T; + + fn next(&mut self) -> Option { + if self.current >= self.range.end { + return None; + } + let result = self.current; + self.current.step(); + Some(result) + } +} From 649719b67c677fdc39795f85c17e7493d124abdb Mon Sep 17 00:00:00 2001 From: ZIYAN137 Date: Sat, 18 Oct 2025 15:00:06 +0000 Subject: [PATCH 09/10] =?UTF-8?q?Docs(mm):=20=E7=A7=BB=E9=99=A4=E5=B7=B2?= =?UTF-8?q?=E5=AE=8C=E6=88=90=E7=9A=84=20TODO=20=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- os/src/mm/address/address.rs | 2 -- os/src/mm/address/page_num.rs | 1 - 2 files changed, 3 deletions(-) diff --git a/os/src/mm/address/address.rs b/os/src/mm/address/address.rs index fe16fc1a..762242a7 100644 --- a/os/src/mm/address/address.rs +++ b/os/src/mm/address/address.rs @@ -151,7 +151,6 @@ where end: T, } -// TODO: implement methods for AddressRange impl AddressRange where T: Address, @@ -242,7 +241,6 @@ where Some(Self { start, end }) } - // comment out for now pub fn iter(&self) -> AddressRangeIterator { AddressRangeIterator { range: *self, diff --git a/os/src/mm/address/page_num.rs b/os/src/mm/address/page_num.rs index 7f5cdbaa..90b95161 100644 --- a/os/src/mm/address/page_num.rs +++ b/os/src/mm/address/page_num.rs @@ -90,7 +90,6 @@ where pub end: T, } -// TODO: implement methods for PageNumRange impl PageNumRange where T: PageNum, From 258421c599b300b342ef8ba29bb500f3c06c6b43 Mon Sep 17 00:00:00 2001 From: ZIYAN137 Date: Sat, 18 Oct 2025 15:06:34 +0000 Subject: [PATCH 10/10] =?UTF-8?q?Docs(mm):=20=E8=A1=A5=E9=BD=90=20address?= =?UTF-8?q?=20=E6=A8=A1=E5=9D=97=E4=B8=8B=E7=9A=84=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- os/src/mm/address/address.rs | 68 +++++++++++++++++++++++++-------- os/src/mm/address/mod.rs | 24 ++++++++++++ os/src/mm/address/operations.rs | 21 +++++----- os/src/mm/address/page_num.rs | 29 +++++++++++--- 4 files changed, 112 insertions(+), 30 deletions(-) diff --git a/os/src/mm/address/address.rs b/os/src/mm/address/address.rs index 762242a7..f39cab15 100644 --- a/os/src/mm/address/address.rs +++ b/os/src/mm/address/address.rs @@ -2,75 +2,92 @@ use crate::mm::address::operations::{AlignOps, CalcOps, UsizeConvert}; use core::mem::size_of; use core::ops::Range; -// trait to represent an address +/// trait to represent an address pub trait Address: CalcOps + AlignOps + UsizeConvert + Copy + Clone + PartialEq + PartialOrd + Eq + Ord { + /// check if the address is null (zero) fn is_null(self) -> bool { self.as_usize() == 0 } + /// return a null address (zero) fn null() -> Self { Self::from_usize(0) } + /// get the offset within a page fn page_offset(self) -> usize { self.as_usize() & (crate::config::PAGE_SIZE - 1) } + /// calculate the difference between two addresses fn addr_diff(self, other: Self) -> isize { self.as_usize() as isize - other.as_usize() as isize } + /// add the size of type T to the address fn add(self) -> Self { self.add_by(size_of::()) } + /// add the size of n elements of type T to the address fn add_n(self, n: usize) -> Self { self.add_by(size_of::() * n) } + /// add an offset to the address fn add_by(self, offset: usize) -> Self { Self::from_usize(self.as_usize() + offset) } + /// subtract the size of Self from the address fn sub(self) -> Self { self.sub_by(size_of::()) } + /// subtract the size of n elements of Self from the address fn sub_n(self, n: usize) -> Self { self.sub_by(size_of::() * n) } + /// subtract an offset from the address fn sub_by(self, offset: usize) -> Self { Self::from_usize(self.as_usize() - offset) } + /// increment the address by the size of Self fn step(&mut self) { self.step_by(size_of::()) } + /// increment the address by the size of n elements of Self fn step_n(&mut self, n: usize) { self.step_by(size_of::() * n) } + /// decrement the address by the size of Self fn step_back(&mut self) { self.step_back_by(size_of::()) } + /// decrement the address by the size of n elements of Self fn step_back_n(&mut self, n: usize) { self.step_back_by(size_of::() * n) } + /// increment the address by the given offset fn step_by(&mut self, offset: usize) { *self = self.add_by(offset); } + /// decrement the address by the given offset fn step_back_by(&mut self, offset: usize) { *self = self.sub_by(offset); } } +/// macro to implement the Address trait for a type #[macro_export] macro_rules! impl_address { ($type:ty) => { @@ -93,54 +110,57 @@ macro_rules! impl_address { }; } -// physical address +/// physical address #[repr(transparent)] #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] pub struct Paddr(*const ()); impl_address!(Paddr); -// virtual address +/// virtual address #[repr(transparent)] #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] pub struct Vaddr(*const ()); impl_address!(Vaddr); impl Vaddr { - // from_ref + /// create a virtual address from a reference pub fn from_ref(r: &T) -> Self { Self::from_ptr(r as *const T) } - // from_ptr + /// create a virtual address from a pointer pub fn from_ptr(p: *const T) -> Self { Self::from_usize(p as usize) } - // as_ref - // the caller must ensure that the address is valid for type T + /// convert the address to a reference + /// # Safety + /// the caller must ensure that the address is valid for type T pub unsafe fn as_ref(&self) -> &T { &*(self.as_usize() as *const T) } - // as_mut - // the caller must ensure that the address is valid for type T + /// convert the address to a mutable reference + /// # Safety + /// the caller must ensure that the address is valid for type T pub unsafe fn as_mut(&mut self) -> &mut T { &mut *(self.as_usize() as *mut T) } - // as_ptr + /// convert the address to a const pointer pub fn as_ptr(&self) -> *const T { self.as_usize() as *const T } - // as_mut_ptr - // the caller must ensure that the address is valid for type T + /// convert the address to a mutable pointer + /// # Safety + /// the caller must ensure that the address is valid for type T pub unsafe fn as_mut_ptr(&mut self) -> *mut T { self.as_usize() as *mut T } } -// trait to represent an address range +/// address range #[repr(C)] #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct AddressRange @@ -155,6 +175,7 @@ impl AddressRange where T: Address, { + /// create a new address range pub fn new(start: T, end: T) -> Self { Self { start, @@ -162,6 +183,7 @@ where } } + /// create an address range from a Range pub fn from_range(range: Range) -> Self { Self { start: range.start, @@ -169,6 +191,7 @@ where } } + /// create an address range from start address and length pub fn from_start_len(start: T, len: usize) -> Self { Self { start, @@ -176,6 +199,7 @@ where } } + /// create an address range from a slice pub fn from_slices(slices: &[T]) -> Option { if slices.len() < 2 { return None; @@ -186,43 +210,53 @@ where }) } + /// get the start address pub fn start(&self) -> T { self.start } + /// get the end address pub fn end(&self) -> T { self.end } + /// get the length of the range pub fn len(&self) -> usize { debug_assert!(self.end.as_usize() >= self.start.as_usize()); self.end.as_usize() - self.start.as_usize() } + /// check if the range is empty pub fn empty(&self) -> bool { self.start == self.end } + /// check if the range contains an address pub fn contains(&self, addr: T) -> bool { addr >= self.start && addr < self.end } + /// check if the range contains another range pub fn contains_range(&self, other: &Self) -> bool { other.start >= self.start && other.end <= self.end } + /// check if the range is contained in another range pub fn contains_in(&self, other: &Self) -> bool { self.start >= other.start && self.end <= other.end } + /// check if the range intersects with another range pub fn intersects(&self, other: &Self) -> bool { self.start < other.end && other.start < self.end } + /// check if the range is adjacent to another range pub fn adjacent(&self, other: &Self) -> bool { self.end == other.start || other.end == self.start } + /// get the intersection of two ranges pub fn intersection(&self, other: &Self) -> Option { if !self.intersects(other) { return None; @@ -232,6 +266,7 @@ where Some(Self { start, end }) } + /// get the union of two ranges pub fn union(&self, other: &Self) -> Option { if !self.intersects(other) && !self.adjacent(other) { return None; @@ -241,6 +276,7 @@ where Some(Self { start, end }) } + /// get an iterator over the range pub fn iter(&self) -> AddressRangeIterator { AddressRangeIterator { range: *self, @@ -261,7 +297,7 @@ where } } -// iterator for address range +/// iterator for address range pub struct AddressRangeIterator where T: Address, @@ -286,8 +322,8 @@ where } } -// physical address range +/// physical address range pub type PaddrRange = AddressRange; -// virtual address range +/// virtual address range pub type VaddrRange = AddressRange; diff --git a/os/src/mm/address/mod.rs b/os/src/mm/address/mod.rs index 8e9adbbd..a22d77a9 100644 --- a/os/src/mm/address/mod.rs +++ b/os/src/mm/address/mod.rs @@ -1,3 +1,27 @@ +//! Address module +//! +//! This module provides abstractions for working with physical and virtual addresses, +//! as well as page numbers in a memory management system. +//! +//! # Components +//! +//! - [`Address`]: Trait for representing memory addresses (physical or virtual) +//! - [`Paddr`]: Physical address type +//! - [`Vaddr`]: Virtual address type +//! - [`AddressRange`]: Generic range of addresses +//! - [`PageNum`]: Trait for representing page numbers +//! - [`Ppn`]: Physical page number +//! - [`Vpn`]: Virtual page number +//! - [`PageNumRange`]: Generic range of page numbers +//! +//! # Operations +//! +//! The module provides three key trait categories: +//! +//! - [`UsizeConvert`]: Convert between types and usize +//! - [`CalcOps`]: Arithmetic and bitwise operations +//! - [`AlignOps`]: Address alignment operations + mod address; mod operations; mod page_num; diff --git a/os/src/mm/address/operations.rs b/os/src/mm/address/operations.rs index 9dad05bb..d1366623 100644 --- a/os/src/mm/address/operations.rs +++ b/os/src/mm/address/operations.rs @@ -4,13 +4,15 @@ use core::ops::{ Shr, ShrAssign, Sub, SubAssign, }; -// convert between usize and the type +/// convert between usize and the type pub trait UsizeConvert: Copy + Clone + PartialEq + PartialOrd + Eq + Ord { + /// convert the type to usize fn as_usize(&self) -> usize; + /// convert usize to the type fn from_usize(value: usize) -> Self; } -// arithmetic and bitwise operations +/// arithmetic and bitwise operations pub trait CalcOps: UsizeConvert + Add @@ -40,7 +42,7 @@ pub trait CalcOps: { } -// macro to implement arithmetic and bitwise operations +/// macro to implement arithmetic and bitwise operations #[macro_export] macro_rules! impl_calc_ops { ($type:ty) => { @@ -209,9 +211,9 @@ macro_rules! impl_calc_ops { }; } -// alignment operations +/// alignment operations pub trait AlignOps: UsizeConvert { - // check if the address is aligned to the given alignment + /// check if the address is aligned to the given alignment fn is_aligned(self, alignment: usize) -> bool { debug_assert!( alignment.is_power_of_two(), @@ -220,10 +222,11 @@ pub trait AlignOps: UsizeConvert { let mask = alignment - 1; self.as_usize() & mask == 0 } + /// check if the address is page aligned fn is_page_aligned(self) -> bool { self.is_aligned(PAGE_SIZE) } - // align the address up to the given alignment + /// align the address up to the given alignment fn align_up(self, alignment: usize) -> Self { debug_assert!( alignment.is_power_of_two(), @@ -232,7 +235,7 @@ pub trait AlignOps: UsizeConvert { let mask = alignment - 1; Self::from_usize((self.as_usize() + mask) & !mask) } - // align the address down to the given alignment + /// align the address down to the given alignment fn align_down(self, alignment: usize) -> Self { debug_assert!( alignment.is_power_of_two(), @@ -241,11 +244,11 @@ pub trait AlignOps: UsizeConvert { let mask = alignment - 1; Self::from_usize(self.as_usize() & !mask) } - // align the address up to the page size + /// align the address up to the page size fn align_up_to_page(self) -> Self { self.align_up(PAGE_SIZE) } - // align the address down to the page size + /// align the address down to the page size fn align_down_to_page(self) -> Self { self.align_down(PAGE_SIZE) } diff --git a/os/src/mm/address/page_num.rs b/os/src/mm/address/page_num.rs index 90b95161..ca30cc67 100644 --- a/os/src/mm/address/page_num.rs +++ b/os/src/mm/address/page_num.rs @@ -3,49 +3,59 @@ use crate::mm::address::address::{Address, Paddr, Vaddr}; use crate::mm::address::operations::{AlignOps, CalcOps, UsizeConvert}; use core::ops::Range; -// trait to represent an page number +/// trait to represent a page number pub trait PageNum: CalcOps + UsizeConvert + Copy + Clone + PartialEq + PartialOrd + Eq + Ord { type TAddress: Address; + /// increment the page number by 1 fn step(&mut self) { self.step_by(1); } + /// increment the page number by the given offset fn step_by(&mut self, offset: usize) { *self = Self::from_usize(self.as_usize() + offset); } + /// decrement the page number by 1 fn step_back(&mut self) { self.step_back_by(1); } + /// decrement the page number by the given offset fn step_back_by(&mut self, offset: usize) { *self = Self::from_usize(self.as_usize() - offset); } + /// convert an address to a page number (floor) fn from_addr_floor(addr: Self::TAddress) -> Self { Self::from_usize(addr.align_down_to_page().as_usize() / PAGE_SIZE) } + /// convert an address to a page number (ceil) fn from_addr_ceil(addr: Self::TAddress) -> Self { Self::from_usize(addr.align_up_to_page().as_usize() / PAGE_SIZE) } + /// get the start address of the page fn start_addr(self) -> Self::TAddress { Self::TAddress::from_usize(self.as_usize() * PAGE_SIZE) } + /// get the end address of the page fn end_addr(self) -> Self::TAddress { Self::TAddress::from_usize((self.as_usize() + 1) * PAGE_SIZE) } + /// calculate the difference between two page numbers fn diff(self, other: Self) -> isize { self.as_usize() as isize - other.as_usize() as isize } } +/// macro to implement the PageNum trait for a type #[macro_export] macro_rules! impl_page_num { ($type:ty, $addr_type:ty) => { @@ -67,19 +77,19 @@ macro_rules! impl_page_num { }; } -// phyical page number +/// physical page number #[repr(transparent)] #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] pub struct Ppn(pub usize); impl_page_num!(Ppn, Paddr); -// virtual page number +/// virtual page number #[repr(transparent)] #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] pub struct Vpn(pub usize); impl_page_num!(Vpn, Vaddr); -// trait to represent a range of page numbers +/// page number range #[repr(C)] #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct PageNumRange @@ -94,10 +104,12 @@ impl PageNumRange where T: PageNum, { + /// create a new page number range pub fn new(start: T, end: T) -> Self { Self { start, end } } + /// create a page number range from a Range pub fn from_range(range: Range) -> Self { Self { start: range.start, @@ -105,6 +117,7 @@ where } } + /// create a page number range from start and length pub fn from_start_len(start: T, len: usize) -> Self { Self { start, @@ -112,27 +125,33 @@ where } } + /// get the length of the range pub fn len(&self) -> usize { debug_assert!(self.end.as_usize() >= self.start.as_usize()); self.end.as_usize() - self.start.as_usize() } + /// check if the range is empty pub fn empty(&self) -> bool { self.start == self.end } + /// check if the range contains a page number pub fn contains(&self, addr: T) -> bool { addr >= self.start && addr < self.end } + /// check if the range contains another range pub fn contains_range(&self, other: &Self) -> bool { other.start >= self.start && other.end <= self.end } + /// check if the range is contained in another range pub fn contains_in(&self, other: &Self) -> bool { self.start >= other.start && self.end <= other.end } + /// get an iterator over the range pub fn iter(&self) -> PageNumRangeIterator { PageNumRangeIterator { range: *self, @@ -153,7 +172,7 @@ where } } -// iterator for PageNumRange +/// iterator for page number range pub struct PageNumRangeIterator where T: PageNum,