Skip to content

update Step::steps_between to latest rust nightly version #518

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading