Skip to content

Commit 89662dc

Browse files
committed
Merge branch 'master' into next
Signed-off-by: Joe Richey <[email protected]>
2 parents 2da1eb6 + 2c9a807 commit 89662dc

File tree

8 files changed

+536
-213
lines changed

8 files changed

+536
-213
lines changed

Cargo.toml

+3-1
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,16 @@ edition = "2018"
2929
bit_field = "0.10.1"
3030
bitflags = "1.3.2"
3131
volatile = "0.4.4"
32+
rustversion = "1.0.5"
3233

3334
[features]
3435
default = [ "nightly", "instructions" ]
3536
instructions = []
36-
nightly = [ "const_fn", "abi_x86_interrupt", "asm_const", "doc_cfg" ]
37+
nightly = [ "const_fn", "step_trait", "abi_x86_interrupt", "asm_const", "doc_cfg" ]
3738
abi_x86_interrupt = []
3839
const_fn = []
3940
asm_const = []
41+
step_trait = []
4042
doc_cfg = []
4143

4244
[package.metadata.release]

src/addr.rs

+205-8
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
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;
711
use crate::structures::paging::{PageOffset, PageTableIndex};
812
use bit_field::BitField;
913

14+
#[cfg(feature = "step_trait")]
15+
const ADDRESS_SPACE_SIZE: u64 = 0x1_0000_0000_0000;
16+
1017
/// A canonical 64-bit virtual memory address.
1118
///
1219
/// This is a wrapper type around an `u64`, so it is always 8 bytes, even when compiled
@@ -40,9 +47,18 @@ pub struct PhysAddr(u64);
4047
/// a valid sign extension and are not null either. So automatic sign extension would have
4148
/// overwritten possibly meaningful bits. This likely indicates a bug, for example an invalid
4249
/// address calculation.
43-
#[derive(Debug)]
50+
///
51+
/// Contains the invalid address.
4452
pub struct VirtAddrNotValid(pub u64);
4553

54+
impl core::fmt::Debug for VirtAddrNotValid {
55+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56+
f.debug_tuple("VirtAddrNotValid")
57+
.field(&format_args!("{:#x}", self.0))
58+
.finish()
59+
}
60+
}
61+
4662
impl VirtAddr {
4763
/// Creates a new canonical virtual address.
4864
///
@@ -70,7 +86,7 @@ impl VirtAddr {
7086
match addr.get_bits(47..64) {
7187
0 | 0x1ffff => Ok(VirtAddr(addr)), // address is canonical
7288
1 => Ok(VirtAddr::new_truncate(addr)), // address needs sign extension
73-
other => Err(VirtAddrNotValid(other)),
89+
_ => Err(VirtAddrNotValid(addr)),
7490
}
7591
}
7692

@@ -322,12 +338,81 @@ impl Sub<VirtAddr> for VirtAddr {
322338
}
323339
}
324340

341+
#[cfg(feature = "step_trait")]
342+
impl Step for VirtAddr {
343+
fn steps_between(start: &Self, end: &Self) -> Option<usize> {
344+
let mut steps = end.0.checked_sub(start.0)?;
345+
346+
// Check if we jumped the gap.
347+
if end.0.get_bit(47) && !start.0.get_bit(47) {
348+
steps = steps.checked_sub(0xffff_0000_0000_0000).unwrap();
349+
}
350+
351+
usize::try_from(steps).ok()
352+
}
353+
354+
fn forward_checked(start: Self, count: usize) -> Option<Self> {
355+
let offset = u64::try_from(count).ok()?;
356+
if offset > ADDRESS_SPACE_SIZE {
357+
return None;
358+
}
359+
360+
let mut addr = start.0.checked_add(offset)?;
361+
362+
match addr.get_bits(47..) {
363+
0x1 => {
364+
// Jump the gap by sign extending the 47th bit.
365+
addr.set_bits(47.., 0x1ffff);
366+
}
367+
0x2 => {
368+
// Address overflow
369+
return None;
370+
}
371+
_ => {}
372+
}
373+
374+
Some(Self::new(addr))
375+
}
376+
377+
fn backward_checked(start: Self, count: usize) -> Option<Self> {
378+
let offset = u64::try_from(count).ok()?;
379+
if offset > ADDRESS_SPACE_SIZE {
380+
return None;
381+
}
382+
383+
let mut addr = start.0.checked_sub(offset)?;
384+
385+
match addr.get_bits(47..) {
386+
0x1fffe => {
387+
// Jump the gap by sign extending the 47th bit.
388+
addr.set_bits(47.., 0);
389+
}
390+
0x1fffd => {
391+
// Address underflow
392+
return None;
393+
}
394+
_ => {}
395+
}
396+
397+
Some(Self::new(addr))
398+
}
399+
}
400+
325401
/// A passed `u64` was not a valid physical address.
326402
///
327403
/// This means that bits 52 to 64 were not all null.
328-
#[derive(Debug)]
404+
///
405+
/// Contains the invalid address.
329406
pub struct PhysAddrNotValid(pub u64);
330407

408+
impl core::fmt::Debug for PhysAddrNotValid {
409+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
410+
f.debug_tuple("PhysAddrNotValid")
411+
.field(&format_args!("{:#x}", self.0))
412+
.finish()
413+
}
414+
}
415+
331416
impl PhysAddr {
332417
/// Creates a new physical address.
333418
///
@@ -367,7 +452,7 @@ impl PhysAddr {
367452
pub fn try_new(addr: u64) -> Result<PhysAddr, PhysAddrNotValid> {
368453
match addr.get_bits(52..64) {
369454
0 => Ok(PhysAddr(addr)), // address is valid
370-
other => Err(PhysAddrNotValid(other)),
455+
_ => Err(PhysAddrNotValid(addr)),
371456
}
372457
}
373458

@@ -540,8 +625,7 @@ impl Sub<PhysAddr> for PhysAddr {
540625
///
541626
/// Returns the greatest `x` with alignment `align` so that `x <= addr`.
542627
///
543-
/// Panics if the alignment is not a power of two. Without the `const_fn`
544-
/// feature, the panic message will be "index out of bounds".
628+
/// Panics if the alignment is not a power of two.
545629
#[inline]
546630
pub const fn align_down(addr: u64, align: u64) -> u64 {
547631
assert!(align.is_power_of_two(), "`align` must be a power of two");
@@ -552,8 +636,7 @@ pub const fn align_down(addr: u64, align: u64) -> u64 {
552636
///
553637
/// Returns the smallest `x` with alignment `align` so that `x >= addr`.
554638
///
555-
/// Panics if the alignment is not a power of two. Without the `const_fn`
556-
/// feature, the panic message will be "index out of bounds".
639+
/// Panics if the alignment is not a power of two.
557640
#[inline]
558641
pub const fn align_up(addr: u64, align: u64) -> u64 {
559642
assert!(align.is_power_of_two(), "`align` must be a power of two");
@@ -577,6 +660,120 @@ mod tests {
577660
assert_eq!(VirtAddr::new_truncate(123 << 47), VirtAddr(0xfffff << 47));
578661
}
579662

663+
#[test]
664+
#[cfg(feature = "step_trait")]
665+
fn virtaddr_step_forward() {
666+
assert_eq!(Step::forward(VirtAddr(0), 0), VirtAddr(0));
667+
assert_eq!(Step::forward(VirtAddr(0), 1), VirtAddr(1));
668+
assert_eq!(
669+
Step::forward(VirtAddr(0x7fff_ffff_ffff), 1),
670+
VirtAddr(0xffff_8000_0000_0000)
671+
);
672+
assert_eq!(
673+
Step::forward(VirtAddr(0xffff_8000_0000_0000), 1),
674+
VirtAddr(0xffff_8000_0000_0001)
675+
);
676+
assert_eq!(
677+
Step::forward_checked(VirtAddr(0xffff_ffff_ffff_ffff), 1),
678+
None
679+
);
680+
assert_eq!(
681+
Step::forward(VirtAddr(0x7fff_ffff_ffff), 0x1234_5678_9abd),
682+
VirtAddr(0xffff_9234_5678_9abc)
683+
);
684+
assert_eq!(
685+
Step::forward(VirtAddr(0x7fff_ffff_ffff), 0x8000_0000_0000),
686+
VirtAddr(0xffff_ffff_ffff_ffff)
687+
);
688+
assert_eq!(
689+
Step::forward(VirtAddr(0x7fff_ffff_ff00), 0x8000_0000_00ff),
690+
VirtAddr(0xffff_ffff_ffff_ffff)
691+
);
692+
assert_eq!(
693+
Step::forward_checked(VirtAddr(0x7fff_ffff_ff00), 0x8000_0000_0100),
694+
None
695+
);
696+
assert_eq!(
697+
Step::forward_checked(VirtAddr(0x7fff_ffff_ffff), 0x8000_0000_0001),
698+
None
699+
);
700+
}
701+
702+
#[test]
703+
#[cfg(feature = "step_trait")]
704+
fn virtaddr_step_backward() {
705+
assert_eq!(Step::backward(VirtAddr(0), 0), VirtAddr(0));
706+
assert_eq!(Step::backward_checked(VirtAddr(0), 1), None);
707+
assert_eq!(Step::backward(VirtAddr(1), 1), VirtAddr(0));
708+
assert_eq!(
709+
Step::backward(VirtAddr(0xffff_8000_0000_0000), 1),
710+
VirtAddr(0x7fff_ffff_ffff)
711+
);
712+
assert_eq!(
713+
Step::backward(VirtAddr(0xffff_8000_0000_0001), 1),
714+
VirtAddr(0xffff_8000_0000_0000)
715+
);
716+
assert_eq!(
717+
Step::backward(VirtAddr(0xffff_9234_5678_9abc), 0x1234_5678_9abd),
718+
VirtAddr(0x7fff_ffff_ffff)
719+
);
720+
assert_eq!(
721+
Step::backward(VirtAddr(0xffff_8000_0000_0000), 0x8000_0000_0000),
722+
VirtAddr(0)
723+
);
724+
assert_eq!(
725+
Step::backward(VirtAddr(0xffff_8000_0000_0000), 0x7fff_ffff_ff01),
726+
VirtAddr(0xff)
727+
);
728+
assert_eq!(
729+
Step::backward_checked(VirtAddr(0xffff_8000_0000_0000), 0x8000_0000_0001),
730+
None
731+
);
732+
}
733+
734+
#[test]
735+
#[cfg(feature = "step_trait")]
736+
fn virtaddr_steps_between() {
737+
assert_eq!(Step::steps_between(&VirtAddr(0), &VirtAddr(0)), Some(0));
738+
assert_eq!(Step::steps_between(&VirtAddr(0), &VirtAddr(1)), Some(1));
739+
assert_eq!(Step::steps_between(&VirtAddr(1), &VirtAddr(0)), None);
740+
assert_eq!(
741+
Step::steps_between(
742+
&VirtAddr(0x7fff_ffff_ffff),
743+
&VirtAddr(0xffff_8000_0000_0000)
744+
),
745+
Some(1)
746+
);
747+
assert_eq!(
748+
Step::steps_between(
749+
&VirtAddr(0xffff_8000_0000_0000),
750+
&VirtAddr(0x7fff_ffff_ffff)
751+
),
752+
None
753+
);
754+
assert_eq!(
755+
Step::steps_between(
756+
&VirtAddr(0xffff_8000_0000_0000),
757+
&VirtAddr(0xffff_8000_0000_0000)
758+
),
759+
Some(0)
760+
);
761+
assert_eq!(
762+
Step::steps_between(
763+
&VirtAddr(0xffff_8000_0000_0000),
764+
&VirtAddr(0xffff_8000_0000_0001)
765+
),
766+
Some(1)
767+
);
768+
assert_eq!(
769+
Step::steps_between(
770+
&VirtAddr(0xffff_8000_0000_0001),
771+
&VirtAddr(0xffff_8000_0000_0000)
772+
),
773+
None
774+
);
775+
}
776+
580777
#[test]
581778
pub fn test_align_up() {
582779
// align 1

src/lib.rs

+1-33
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,9 @@
33
44
#![cfg_attr(not(test), no_std)]
55
#![cfg_attr(feature = "const_fn", feature(const_mut_refs))] // GDT add_entry()
6-
#![cfg_attr(feature = "const_fn", feature(const_fn_fn_ptr_basics))] // IDT new()
7-
#![cfg_attr(feature = "const_fn", feature(const_fn_trait_bound))] // PageSize marker trait
86
#![cfg_attr(feature = "asm_const", feature(asm_const))]
97
#![cfg_attr(feature = "abi_x86_interrupt", feature(abi_x86_interrupt))]
8+
#![cfg_attr(feature = "step_trait", feature(step_trait))]
109
#![cfg_attr(feature = "doc_cfg", feature(doc_cfg))]
1110
#![warn(missing_docs)]
1211
#![deny(missing_debug_implementations)]
@@ -17,37 +16,6 @@ use core::sync::atomic::{AtomicBool, Ordering};
1716

1817
pub use crate::addr::{align_down, align_up, PhysAddr, VirtAddr};
1918

20-
/// Makes a function const only when `feature = "const_fn"` is enabled.
21-
///
22-
/// This is needed for const functions with bounds on their generic parameters,
23-
/// such as those in `Page` and `PhysFrame` and many more.
24-
macro_rules! const_fn {
25-
(
26-
$(#[$attr:meta])*
27-
$sv:vis fn $($fn:tt)*
28-
) => {
29-
$(#[$attr])*
30-
#[cfg(feature = "const_fn")]
31-
$sv const fn $($fn)*
32-
33-
$(#[$attr])*
34-
#[cfg(not(feature = "const_fn"))]
35-
$sv fn $($fn)*
36-
};
37-
(
38-
$(#[$attr:meta])*
39-
$sv:vis unsafe fn $($fn:tt)*
40-
) => {
41-
$(#[$attr])*
42-
#[cfg(feature = "const_fn")]
43-
$sv const unsafe fn $($fn)*
44-
45-
$(#[$attr])*
46-
#[cfg(not(feature = "const_fn"))]
47-
$sv unsafe fn $($fn)*
48-
};
49-
}
50-
5119
pub mod addr;
5220
pub mod instructions;
5321
pub mod registers;

0 commit comments

Comments
 (0)