|
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;
|
7 | 11 | use crate::structures::paging::{PageOffset, PageTableIndex};
|
8 | 12 | use bit_field::BitField;
|
9 | 13 |
|
| 14 | +#[cfg(feature = "step_trait")] |
| 15 | +const ADDRESS_SPACE_SIZE: u64 = 0x1_0000_0000_0000; |
| 16 | + |
10 | 17 | /// A canonical 64-bit virtual memory address.
|
11 | 18 | ///
|
12 | 19 | /// This is a wrapper type around an `u64`, so it is always 8 bytes, even when compiled
|
@@ -331,6 +338,66 @@ impl Sub<VirtAddr> for VirtAddr {
|
331 | 338 | }
|
332 | 339 | }
|
333 | 340 |
|
| 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 | + |
334 | 401 | /// A passed `u64` was not a valid physical address.
|
335 | 402 | ///
|
336 | 403 | /// This means that bits 52 to 64 were not all null.
|
@@ -595,6 +662,120 @@ mod tests {
|
595 | 662 | assert_eq!(VirtAddr::new_truncate(123 << 47), VirtAddr(0xfffff << 47));
|
596 | 663 | }
|
597 | 664 |
|
| 665 | + #[test] |
| 666 | + #[cfg(feature = "step_trait")] |
| 667 | + fn virtaddr_step_forward() { |
| 668 | + assert_eq!(Step::forward(VirtAddr(0), 0), VirtAddr(0)); |
| 669 | + assert_eq!(Step::forward(VirtAddr(0), 1), VirtAddr(1)); |
| 670 | + assert_eq!( |
| 671 | + Step::forward(VirtAddr(0x7fff_ffff_ffff), 1), |
| 672 | + VirtAddr(0xffff_8000_0000_0000) |
| 673 | + ); |
| 674 | + assert_eq!( |
| 675 | + Step::forward(VirtAddr(0xffff_8000_0000_0000), 1), |
| 676 | + VirtAddr(0xffff_8000_0000_0001) |
| 677 | + ); |
| 678 | + assert_eq!( |
| 679 | + Step::forward_checked(VirtAddr(0xffff_ffff_ffff_ffff), 1), |
| 680 | + None |
| 681 | + ); |
| 682 | + assert_eq!( |
| 683 | + Step::forward(VirtAddr(0x7fff_ffff_ffff), 0x1234_5678_9abd), |
| 684 | + VirtAddr(0xffff_9234_5678_9abc) |
| 685 | + ); |
| 686 | + assert_eq!( |
| 687 | + Step::forward(VirtAddr(0x7fff_ffff_ffff), 0x8000_0000_0000), |
| 688 | + VirtAddr(0xffff_ffff_ffff_ffff) |
| 689 | + ); |
| 690 | + assert_eq!( |
| 691 | + Step::forward(VirtAddr(0x7fff_ffff_ff00), 0x8000_0000_00ff), |
| 692 | + VirtAddr(0xffff_ffff_ffff_ffff) |
| 693 | + ); |
| 694 | + assert_eq!( |
| 695 | + Step::forward_checked(VirtAddr(0x7fff_ffff_ff00), 0x8000_0000_0100), |
| 696 | + None |
| 697 | + ); |
| 698 | + assert_eq!( |
| 699 | + Step::forward_checked(VirtAddr(0x7fff_ffff_ffff), 0x8000_0000_0001), |
| 700 | + None |
| 701 | + ); |
| 702 | + } |
| 703 | + |
| 704 | + #[test] |
| 705 | + #[cfg(feature = "step_trait")] |
| 706 | + fn virtaddr_step_backward() { |
| 707 | + assert_eq!(Step::backward(VirtAddr(0), 0), VirtAddr(0)); |
| 708 | + assert_eq!(Step::backward_checked(VirtAddr(0), 1), None); |
| 709 | + assert_eq!(Step::backward(VirtAddr(1), 1), VirtAddr(0)); |
| 710 | + assert_eq!( |
| 711 | + Step::backward(VirtAddr(0xffff_8000_0000_0000), 1), |
| 712 | + VirtAddr(0x7fff_ffff_ffff) |
| 713 | + ); |
| 714 | + assert_eq!( |
| 715 | + Step::backward(VirtAddr(0xffff_8000_0000_0001), 1), |
| 716 | + VirtAddr(0xffff_8000_0000_0000) |
| 717 | + ); |
| 718 | + assert_eq!( |
| 719 | + Step::backward(VirtAddr(0xffff_9234_5678_9abc), 0x1234_5678_9abd), |
| 720 | + VirtAddr(0x7fff_ffff_ffff) |
| 721 | + ); |
| 722 | + assert_eq!( |
| 723 | + Step::backward(VirtAddr(0xffff_8000_0000_0000), 0x8000_0000_0000), |
| 724 | + VirtAddr(0) |
| 725 | + ); |
| 726 | + assert_eq!( |
| 727 | + Step::backward(VirtAddr(0xffff_8000_0000_0000), 0x7fff_ffff_ff01), |
| 728 | + VirtAddr(0xff) |
| 729 | + ); |
| 730 | + assert_eq!( |
| 731 | + Step::backward_checked(VirtAddr(0xffff_8000_0000_0000), 0x8000_0000_0001), |
| 732 | + None |
| 733 | + ); |
| 734 | + } |
| 735 | + |
| 736 | + #[test] |
| 737 | + #[cfg(feature = "step_trait")] |
| 738 | + fn virtaddr_steps_between() { |
| 739 | + assert_eq!(Step::steps_between(&VirtAddr(0), &VirtAddr(0)), Some(0)); |
| 740 | + assert_eq!(Step::steps_between(&VirtAddr(0), &VirtAddr(1)), Some(1)); |
| 741 | + assert_eq!(Step::steps_between(&VirtAddr(1), &VirtAddr(0)), None); |
| 742 | + assert_eq!( |
| 743 | + Step::steps_between( |
| 744 | + &VirtAddr(0x7fff_ffff_ffff), |
| 745 | + &VirtAddr(0xffff_8000_0000_0000) |
| 746 | + ), |
| 747 | + Some(1) |
| 748 | + ); |
| 749 | + assert_eq!( |
| 750 | + Step::steps_between( |
| 751 | + &VirtAddr(0xffff_8000_0000_0000), |
| 752 | + &VirtAddr(0x7fff_ffff_ffff) |
| 753 | + ), |
| 754 | + None |
| 755 | + ); |
| 756 | + assert_eq!( |
| 757 | + Step::steps_between( |
| 758 | + &VirtAddr(0xffff_8000_0000_0000), |
| 759 | + &VirtAddr(0xffff_8000_0000_0000) |
| 760 | + ), |
| 761 | + Some(0) |
| 762 | + ); |
| 763 | + assert_eq!( |
| 764 | + Step::steps_between( |
| 765 | + &VirtAddr(0xffff_8000_0000_0000), |
| 766 | + &VirtAddr(0xffff_8000_0000_0001) |
| 767 | + ), |
| 768 | + Some(1) |
| 769 | + ); |
| 770 | + assert_eq!( |
| 771 | + Step::steps_between( |
| 772 | + &VirtAddr(0xffff_8000_0000_0001), |
| 773 | + &VirtAddr(0xffff_8000_0000_0000) |
| 774 | + ), |
| 775 | + None |
| 776 | + ); |
| 777 | + } |
| 778 | + |
598 | 779 | #[test]
|
599 | 780 | pub fn test_align_up() {
|
600 | 781 | // align 1
|
|
0 commit comments