Skip to content

Commit

Permalink
update Step::steps_between to latest rust nightly version
Browse files Browse the repository at this point in the history
This implements the signature change in rust-lang/rust#130867
  • Loading branch information
Wasabi375 committed Nov 29, 2024
1 parent e016a4c commit 266160b
Show file tree
Hide file tree
Showing 6 changed files with 86 additions and 47 deletions.
61 changes: 41 additions & 20 deletions src/addr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -239,26 +239,32 @@ impl VirtAddr {
PageTableIndex::new_truncate((self.0 >> 12 >> ((level as u8 - 1) * 9)) as u16)
}

// FIXME: Move this into the `Step` impl, once `Step` is stabilized.
/// Returns the number of *successor* steps required to get from `start` to `end`.
///
/// This is simlar to [Step::steps_between] but can not overflow.
/// Returns `None` if `end > start`
#[cfg(any(feature = "instructions", feature = "step_trait"))]
pub(crate) fn steps_between_impl(start: &Self, end: &Self) -> Option<usize> {
pub fn steps_between_u64(start: &Self, end: &Self) -> Option<u64> {
let mut steps = end.0.checked_sub(start.0)?;

// Mask away extra bits that appear while jumping the gap.
steps &= 0xffff_ffff_ffff;

usize::try_from(steps).ok()
Some(steps)
}

// FIXME: Move this into the `Step` impl, once `Step` is stabilized.
#[inline]
pub(crate) fn forward_checked_impl(start: Self, count: usize) -> Option<Self> {
let offset = u64::try_from(count).ok()?;
if offset > ADDRESS_SPACE_SIZE {
/// Returns the value that would be obtainted by taking the *successor* of
/// `self` `count` times.
///
/// If this would overflow the range of valid addresses, returns `None`.
///
/// See [core::iter::Step::forward_checked].
pub fn forward_checked_u64(start: Self, count: u64) -> Option<Self> {
if count > ADDRESS_SPACE_SIZE {
return None;
}

let mut addr = start.0.checked_add(offset)?;
let mut addr = start.0.checked_add(count)?;

match addr.get_bits(47..) {
0x1 => {
Expand Down Expand Up @@ -360,13 +366,22 @@ impl Sub<VirtAddr> for VirtAddr {
#[cfg(feature = "step_trait")]
impl Step for VirtAddr {
#[inline]
fn steps_between(start: &Self, end: &Self) -> Option<usize> {
Self::steps_between_impl(start, end)
fn steps_between(start: &Self, end: &Self) -> (usize, Option<usize>) {
use core::usize;

let Some(steps) = VirtAddr::steps_between_u64(start, end) else {
return (0, None);
};

match usize::try_from(steps) {
Ok(steps) => (steps, Some(steps)),
Err(_) => (usize::MAX, None),
}
}

#[inline]
fn forward_checked(start: Self, count: usize) -> Option<Self> {
Self::forward_checked_impl(start, count)
Self::forward_checked_u64(start, count as u64)
}

#[inline]
Expand Down Expand Up @@ -721,43 +736,49 @@ mod tests {
#[test]
#[cfg(feature = "step_trait")]
fn virtaddr_steps_between() {
assert_eq!(Step::steps_between(&VirtAddr(0), &VirtAddr(0)), Some(0));
assert_eq!(Step::steps_between(&VirtAddr(0), &VirtAddr(1)), Some(1));
assert_eq!(Step::steps_between(&VirtAddr(1), &VirtAddr(0)), None);
assert_eq!(
Step::steps_between(&VirtAddr(0), &VirtAddr(0)),
(0, Some(0))
);
assert_eq!(
Step::steps_between(&VirtAddr(0), &VirtAddr(1)),
(1, Some(1))
);
assert_eq!(Step::steps_between(&VirtAddr(1), &VirtAddr(0)), (0, None));
assert_eq!(
Step::steps_between(
&VirtAddr(0x7fff_ffff_ffff),
&VirtAddr(0xffff_8000_0000_0000)
),
Some(1)
(1, Some(1))
);
assert_eq!(
Step::steps_between(
&VirtAddr(0xffff_8000_0000_0000),
&VirtAddr(0x7fff_ffff_ffff)
),
None
(0, None)
);
assert_eq!(
Step::steps_between(
&VirtAddr(0xffff_8000_0000_0000),
&VirtAddr(0xffff_8000_0000_0000)
),
Some(0)
(0, Some(0))
);
assert_eq!(
Step::steps_between(
&VirtAddr(0xffff_8000_0000_0000),
&VirtAddr(0xffff_8000_0000_0001)
),
Some(1)
(1, Some(1))
);
assert_eq!(
Step::steps_between(
&VirtAddr(0xffff_8000_0000_0001),
&VirtAddr(0xffff_8000_0000_0000)
),
None
(0, None)
);
}

Expand Down
7 changes: 3 additions & 4 deletions src/instructions/tlb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -315,14 +315,14 @@ where
if let Some(mut pages) = self.page_range {
while !pages.is_empty() {
// Calculate out how many pages we still need to flush.
let count = Page::<S>::steps_between_impl(&pages.start, &pages.end).unwrap();
let count = Page::<S>::steps_between_u64(&pages.start, &pages.end).unwrap();

// Make sure that we never jump the gap in the address space when flushing.
let second_half_start =
Page::<S>::containing_address(VirtAddr::new(0xffff_8000_0000_0000));
let count = if pages.start < second_half_start {
let count_to_second_half =
Page::steps_between_impl(&pages.start, &second_half_start).unwrap();
Page::steps_between_u64(&pages.start, &second_half_start).unwrap();
cmp::min(count, count_to_second_half)
} else {
count
Expand All @@ -348,8 +348,7 @@ where
// Even if the count is zero, one page is still flushed and so
// we need to advance by at least one.
let inc_count = cmp::max(count, 1);
pages.start =
Page::forward_checked_impl(pages.start, usize::from(inc_count)).unwrap();
pages.start = Page::forward_checked_u64(pages.start, u64::from(inc_count)).unwrap();
}
} else {
unsafe {
Expand Down
8 changes: 3 additions & 5 deletions src/structures/paging/mapper/mapped_page_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -646,11 +646,9 @@ impl<P: PageTableFrameMapping> CleanUp for MappedPageTable<'_, P> {
.skip(usize::from(start))
{
if let Ok(page_table) = page_table_walker.next_table_mut(entry) {
let start = VirtAddr::forward_checked_impl(
table_addr,
(offset_per_entry as usize) * i,
)
.unwrap();
let start =
VirtAddr::forward_checked_u64(table_addr, offset_per_entry * i as u64)
.unwrap();
let end = start + (offset_per_entry - 1);
let start = Page::<Size4KiB>::containing_address(start);
let start = start.max(range.start);
Expand Down
8 changes: 3 additions & 5 deletions src/structures/paging/mapper/recursive_page_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -891,11 +891,9 @@ impl CleanUp for RecursivePageTable<'_> {
})
{
if let Ok(frame) = entry.frame() {
let start = VirtAddr::forward_checked_impl(
table_addr,
(offset_per_entry as usize) * i,
)
.unwrap();
let start =
VirtAddr::forward_checked_u64(table_addr, offset_per_entry * i as u64)
.unwrap();
let end = start + (offset_per_entry - 1);
let start = Page::<Size4KiB>::containing_address(start);
let start = start.max(range.start);
Expand Down
41 changes: 30 additions & 11 deletions src/structures/paging/page.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,18 +158,27 @@ impl<S: PageSize> Page<S> {
PageRangeInclusive { start, end }
}

// FIXME: Move this into the `Step` impl, once `Step` is stabilized.
/// Returns the number of *successor* steps required to get from `start` to `end`.
///
/// This is simlar to [Step::steps_between] but can not overflow.
/// Returns `None` if `end > start`
#[cfg(any(feature = "instructions", feature = "step_trait"))]
pub(crate) fn steps_between_impl(start: &Self, end: &Self) -> Option<usize> {
VirtAddr::steps_between_impl(&start.start_address, &end.start_address)
.map(|steps| steps / S::SIZE as usize)
pub(crate) fn steps_between_u64(start: &Self, end: &Self) -> Option<u64> {
let steps = VirtAddr::steps_between_u64(&start.start_address, &end.start_address)?;

Some(steps / S::SIZE)
}

// FIXME: Move this into the `Step` impl, once `Step` is stabilized.
/// Returns the value that would be obtainted by taking the *successor* of
/// `self` `count` times.
///
/// If this would overflow the range of valid addresses, returns `None`.
///
/// See [core::iter::Step::forward_checked].
#[cfg(any(feature = "instructions", feature = "step_trait"))]
pub(crate) fn forward_checked_impl(start: Self, count: usize) -> Option<Self> {
let count = count.checked_mul(S::SIZE as usize)?;
let start_address = VirtAddr::forward_checked_impl(start.start_address, count)?;
pub(crate) fn forward_checked_u64(start: Self, count: u64) -> Option<Self> {
let count = count.checked_mul(S::SIZE)?;
let start_address = VirtAddr::forward_checked_u64(start.start_address, count)?;
Some(Self {
start_address,
size: PhantomData,
Expand Down Expand Up @@ -293,12 +302,22 @@ impl<S: PageSize> Sub<Self> for Page<S> {

#[cfg(feature = "step_trait")]
impl<S: PageSize> Step for Page<S> {
fn steps_between(start: &Self, end: &Self) -> Option<usize> {
Self::steps_between_impl(start, end)
fn steps_between(start: &Self, end: &Self) -> (usize, Option<usize>) {
use core::convert::TryFrom;
use core::usize;

let Some(steps) = Self::steps_between_u64(start, end) else {
return (0, None);
};

match usize::try_from(steps) {
Ok(steps) => (steps, Some(steps)),
Err(_) => (usize::MAX, None),
}
}

fn forward_checked(start: Self, count: usize) -> Option<Self> {
Self::forward_checked_impl(start, count)
Self::forward_checked_u64(start, count as u64)
}

fn backward_checked(start: Self, count: usize) -> Option<Self> {
Expand Down
8 changes: 6 additions & 2 deletions src/structures/paging/page_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -353,8 +353,12 @@ impl From<PageTableIndex> for usize {
#[cfg(feature = "step_trait")]
impl Step for PageTableIndex {
#[inline]
fn steps_between(start: &Self, end: &Self) -> Option<usize> {
end.0.checked_sub(start.0).map(usize::from)
fn steps_between(start: &Self, end: &Self) -> (usize, Option<usize>) {
end.0
.checked_sub(start.0)
.map(usize::from)
.map(|steps| (steps, Some(steps)))
.unwrap_or((0, None))
}

#[inline]
Expand Down

0 comments on commit 266160b

Please sign in to comment.