|
1 | 1 | //! Physical and virtual addresses manipulation
|
2 | 2 |
|
| 3 | +#[cfg(feature = "step_trait")] |
| 4 | +use core::convert::TryFrom; |
3 | 5 | use core::fmt;
|
| 6 | +#[cfg(feature = "step_trait")] |
| 7 | +use core::iter::Step; |
4 | 8 | use core::ops::{Add, AddAssign, Sub, SubAssign};
|
5 | 9 |
|
6 | 10 | use crate::structures::paging::page_table::PageTableLevel;
|
@@ -322,6 +326,44 @@ impl Sub<VirtAddr> for VirtAddr {
|
322 | 326 | }
|
323 | 327 | }
|
324 | 328 |
|
| 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 | + |
325 | 367 | /// A passed `u64` was not a valid physical address.
|
326 | 368 | ///
|
327 | 369 | /// This means that bits 52 to 64 were not all null.
|
@@ -577,6 +619,76 @@ mod tests {
|
577 | 619 | assert_eq!(VirtAddr::new_truncate(123 << 47), VirtAddr(0xfffff << 47));
|
578 | 620 | }
|
579 | 621 |
|
| 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 | + |
580 | 692 | #[test]
|
581 | 693 | pub fn test_align_up() {
|
582 | 694 | // align 1
|
|
0 commit comments