diff --git a/src/addr.rs b/src/addr.rs index 2959d7de..bdf3475f 100644 --- a/src/addr.rs +++ b/src/addr.rs @@ -177,7 +177,15 @@ impl VirtAddr { where U: Into, { - VirtAddr::new_truncate(align_down(self.0, align.into())) + self.align_down_u64(align.into()) + } + + /// Aligns the virtual address downwards to the given alignment. + /// + /// See the `align_down` function for more information. + #[inline] + pub(crate) const fn align_down_u64(self, align: u64) -> Self { + VirtAddr::new_truncate(align_down(self.0, align)) } /// Checks whether the virtual address has the demanded alignment. @@ -186,7 +194,13 @@ impl VirtAddr { where U: Into, { - self.align_down(align) == self + self.is_aligned_u64(align.into()) + } + + /// Checks whether the virtual address has the demanded alignment. + #[inline] + pub(crate) const fn is_aligned_u64(self, align: u64) -> bool { + self.align_down_u64(align).as_u64() == self.as_u64() } /// Returns the 12-bit page offset of this virtual address. @@ -236,6 +250,7 @@ impl VirtAddr { } // FIXME: Move this into the `Step` impl, once `Step` is stabilized. + #[inline] pub(crate) fn forward_checked_impl(start: Self, count: usize) -> Option { let offset = u64::try_from(count).ok()?; if offset > ADDRESS_SPACE_SIZE { @@ -343,14 +358,17 @@ impl Sub for VirtAddr { #[cfg(feature = "step_trait")] impl Step for VirtAddr { + #[inline] fn steps_between(start: &Self, end: &Self) -> Option { Self::steps_between_impl(start, end) } + #[inline] fn forward_checked(start: Self, count: usize) -> Option { Self::forward_checked_impl(start, count) } + #[inline] fn backward_checked(start: Self, count: usize) -> Option { let offset = u64::try_from(count).ok()?; if offset > ADDRESS_SPACE_SIZE { diff --git a/src/structures/paging/page.rs b/src/structures/paging/page.rs index 6e683430..842bb03d 100644 --- a/src/structures/paging/page.rs +++ b/src/structures/paging/page.rs @@ -77,8 +77,9 @@ impl Page { /// /// Returns an error if the address is not correctly aligned (i.e. is not a valid page start). #[inline] + #[rustversion::attr(since(1.61), const)] pub fn from_start_address(address: VirtAddr) -> Result { - if !address.is_aligned(S::SIZE) { + if !address.is_aligned_u64(S::SIZE) { return Err(AddressNotAligned); } Ok(Page::containing_address(address)) @@ -100,9 +101,10 @@ impl Page { /// Returns the page that contains the given virtual address. #[inline] + #[rustversion::attr(since(1.61), const)] pub fn containing_address(address: VirtAddr) -> Self { Page { - start_address: address.align_down(S::SIZE), + start_address: address.align_down_u64(S::SIZE), size: PhantomData, } } @@ -185,13 +187,14 @@ impl Page { impl Page { /// Returns the 1GiB memory page with the specified page table indices. #[inline] + #[rustversion::attr(since(1.61), const)] pub fn from_page_table_indices_1gib( p4_index: PageTableIndex, p3_index: PageTableIndex, ) -> Self { let mut addr = 0; - addr |= u64::from(p4_index) << 39; - addr |= u64::from(p3_index) << 30; + addr |= p4_index.into_u64() << 39; + addr |= p3_index.into_u64() << 30; Page::containing_address(VirtAddr::new_truncate(addr)) } } @@ -199,15 +202,16 @@ impl Page { impl Page { /// Returns the 2MiB memory page with the specified page table indices. #[inline] + #[rustversion::attr(since(1.61), const)] pub fn from_page_table_indices_2mib( p4_index: PageTableIndex, p3_index: PageTableIndex, p2_index: PageTableIndex, ) -> Self { let mut addr = 0; - addr |= u64::from(p4_index) << 39; - addr |= u64::from(p3_index) << 30; - addr |= u64::from(p2_index) << 21; + addr |= p4_index.into_u64() << 39; + addr |= p3_index.into_u64() << 30; + addr |= p2_index.into_u64() << 21; Page::containing_address(VirtAddr::new_truncate(addr)) } } @@ -215,6 +219,7 @@ impl Page { impl Page { /// Returns the 4KiB memory page with the specified page table indices. #[inline] + #[rustversion::attr(since(1.61), const)] pub fn from_page_table_indices( p4_index: PageTableIndex, p3_index: PageTableIndex, @@ -222,10 +227,10 @@ impl Page { p1_index: PageTableIndex, ) -> Self { let mut addr = 0; - addr |= u64::from(p4_index) << 39; - addr |= u64::from(p3_index) << 30; - addr |= u64::from(p2_index) << 21; - addr |= u64::from(p1_index) << 12; + addr |= p4_index.into_u64() << 39; + addr |= p3_index.into_u64() << 30; + addr |= p2_index.into_u64() << 21; + addr |= p1_index.into_u64() << 12; Page::containing_address(VirtAddr::new_truncate(addr)) } diff --git a/src/structures/paging/page_table.rs b/src/structures/paging/page_table.rs index 03203ed5..79b116e0 100644 --- a/src/structures/paging/page_table.rs +++ b/src/structures/paging/page_table.rs @@ -1,6 +1,8 @@ //! Abstractions for page tables and page table entries. use core::fmt; +#[cfg(feature = "step_trait")] +use core::iter::Step; use core::ops::{Index, IndexMut}; use super::{PageSize, PhysFrame, Size4KiB}; @@ -296,8 +298,8 @@ pub struct PageTableIndex(u16); impl PageTableIndex { /// Creates a new index from the given `u16`. Panics if the given value is >=512. #[inline] - pub fn new(index: u16) -> Self { - assert!(usize::from(index) < ENTRY_COUNT); + pub const fn new(index: u16) -> Self { + assert!((index as usize) < ENTRY_COUNT); Self(index) } @@ -306,6 +308,11 @@ impl PageTableIndex { pub const fn new_truncate(index: u16) -> Self { Self(index % ENTRY_COUNT as u16) } + + #[inline] + pub(crate) const fn into_u64(self) -> u64 { + self.0 as u64 + } } impl From for u16 { @@ -325,7 +332,7 @@ impl From for u32 { impl From for u64 { #[inline] fn from(index: PageTableIndex) -> Self { - u64::from(index.0) + index.into_u64() } } @@ -336,6 +343,26 @@ impl From for usize { } } +#[cfg(feature = "step_trait")] +impl Step for PageTableIndex { + #[inline] + fn steps_between(start: &Self, end: &Self) -> Option { + end.0.checked_sub(start.0).map(usize::from) + } + + #[inline] + fn forward_checked(start: Self, count: usize) -> Option { + let idx = usize::from(start).checked_add(count)?; + (idx < ENTRY_COUNT).then(|| Self::new(idx as u16)) + } + + #[inline] + fn backward_checked(start: Self, count: usize) -> Option { + let idx = usize::from(start).checked_sub(count)?; + Some(Self::new(idx as u16)) + } +} + /// A 12-bit offset into a 4KiB Page. /// /// This type is returned by the `VirtAddr::page_offset` method.