Skip to content

Commit 3680907

Browse files
committed
implement Step for VirtAddr
1 parent a143355 commit 3680907

File tree

3 files changed

+115
-1
lines changed

3 files changed

+115
-1
lines changed

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,10 @@ volatile = "0.4.4"
3333
[features]
3434
default = [ "nightly", "instructions" ]
3535
instructions = []
36-
nightly = [ "const_fn", "abi_x86_interrupt", "doc_cfg" ]
36+
nightly = [ "const_fn", "step_trait", "abi_x86_interrupt", "doc_cfg" ]
3737
abi_x86_interrupt = []
3838
const_fn = []
39+
step_trait = []
3940
doc_cfg = []
4041

4142
# These features are no longer used and only there for backwards compatibility.

src/addr.rs

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
//! Physical and virtual addresses manipulation
22
3+
#[cfg(feature = "step_trait")]
4+
use core::convert::TryFrom;
35
use core::fmt;
6+
#[cfg(feature = "step_trait")]
7+
use core::iter::Step;
48
use core::ops::{Add, AddAssign, Sub, SubAssign};
59

610
use crate::structures::paging::page_table::PageTableLevel;
@@ -322,6 +326,44 @@ impl Sub<VirtAddr> for VirtAddr {
322326
}
323327
}
324328

329+
#[cfg(feature = "step_trait")]
330+
impl Step for VirtAddr {
331+
fn steps_between(start: &Self, end: &Self) -> Option<usize> {
332+
let mut steps = end.0.checked_sub(start.0)?;
333+
334+
// Check if we jumped the gap.
335+
if end.0.get_bit(47) && !start.0.get_bit(47) {
336+
steps -= 0xffff_0000_0000_0000;
337+
}
338+
339+
usize::try_from(steps).ok()
340+
}
341+
342+
fn forward_checked(start: Self, count: usize) -> Option<Self> {
343+
let offset = u64::try_from(count).ok()?;
344+
let mut addr = start.0.checked_add(offset)?;
345+
346+
// Jump the gap by sign extending the 47th bit.
347+
if addr.get_bits(47..) == 0x1 {
348+
addr.set_bits(47.., 0x1ffff);
349+
}
350+
351+
Some(Self(addr))
352+
}
353+
354+
fn backward_checked(start: Self, count: usize) -> Option<Self> {
355+
let offset = u64::try_from(count).ok()?;
356+
let mut addr = start.0.checked_sub(offset)?;
357+
358+
// Jump the gap by sign extending the 47th bit.
359+
if addr.get_bits(47..) == 0x1fffe {
360+
addr.set_bits(47.., 0);
361+
}
362+
363+
Some(Self(addr))
364+
}
365+
}
366+
325367
/// A passed `u64` was not a valid physical address.
326368
///
327369
/// This means that bits 52 to 64 were not all null.
@@ -577,6 +619,76 @@ mod tests {
577619
assert_eq!(VirtAddr::new_truncate(123 << 47), VirtAddr(0xfffff << 47));
578620
}
579621

622+
#[test]
623+
#[cfg(feature = "step_trait")]
624+
fn virtaddr_step() {
625+
assert_eq!(Step::forward(VirtAddr(0), 0), VirtAddr(0));
626+
assert_eq!(Step::forward(VirtAddr(0), 1), VirtAddr(1));
627+
assert_eq!(
628+
Step::forward(VirtAddr(0x7fff_ffff_ffff), 1),
629+
VirtAddr(0xffff_8000_0000_0000)
630+
);
631+
assert_eq!(
632+
Step::forward(VirtAddr(0xffff_8000_0000_0000), 1),
633+
VirtAddr(0xffff_8000_0000_0001)
634+
);
635+
assert_eq!(
636+
Step::forward_checked(VirtAddr(0xffff_ffff_ffff_ffff), 1),
637+
None
638+
);
639+
640+
assert_eq!(Step::backward(VirtAddr(0), 0), VirtAddr(0));
641+
assert_eq!(Step::backward_checked(VirtAddr(0), 1), None);
642+
assert_eq!(Step::backward(VirtAddr(1), 1), VirtAddr(0));
643+
assert_eq!(
644+
Step::backward(VirtAddr(0xffff_8000_0000_0000), 1),
645+
VirtAddr(0x7fff_ffff_ffff)
646+
);
647+
assert_eq!(
648+
Step::backward(VirtAddr(0xffff_8000_0000_0001), 1),
649+
VirtAddr(0xffff_8000_0000_0000)
650+
);
651+
652+
assert_eq!(Step::steps_between(&VirtAddr(0), &VirtAddr(0)), Some(0));
653+
assert_eq!(Step::steps_between(&VirtAddr(0), &VirtAddr(1)), Some(1));
654+
assert_eq!(Step::steps_between(&VirtAddr(1), &VirtAddr(0)), None);
655+
assert_eq!(
656+
Step::steps_between(
657+
&VirtAddr(0x7fff_ffff_ffff),
658+
&VirtAddr(0xffff_8000_0000_0000)
659+
),
660+
Some(1)
661+
);
662+
assert_eq!(
663+
Step::steps_between(
664+
&VirtAddr(0xffff_8000_0000_0000),
665+
&VirtAddr(0x7fff_ffff_ffff)
666+
),
667+
None
668+
);
669+
assert_eq!(
670+
Step::steps_between(
671+
&VirtAddr(0xffff_8000_0000_0000),
672+
&VirtAddr(0xffff_8000_0000_0000)
673+
),
674+
Some(0)
675+
);
676+
assert_eq!(
677+
Step::steps_between(
678+
&VirtAddr(0xffff_8000_0000_0000),
679+
&VirtAddr(0xffff_8000_0000_0001)
680+
),
681+
Some(1)
682+
);
683+
assert_eq!(
684+
Step::steps_between(
685+
&VirtAddr(0xffff_8000_0000_0001),
686+
&VirtAddr(0xffff_8000_0000_0000)
687+
),
688+
None
689+
);
690+
}
691+
580692
#[test]
581693
pub fn test_align_up() {
582694
// align 1

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#![cfg_attr(feature = "const_fn", feature(const_fn_fn_ptr_basics))] // IDT new()
77
#![cfg_attr(feature = "const_fn", feature(const_fn_trait_bound))] // PageSize marker trait
88
#![cfg_attr(feature = "abi_x86_interrupt", feature(abi_x86_interrupt))]
9+
#![cfg_attr(feature = "step_trait", feature(step_trait))]
910
#![cfg_attr(feature = "doc_cfg", feature(doc_cfg))]
1011
#![warn(missing_docs)]
1112
#![deny(missing_debug_implementations)]

0 commit comments

Comments
 (0)