memory_addr/
lib.rs

1#![cfg_attr(not(test), no_std)]
2#![doc = include_str!("../README.md")]
3
4mod addr;
5mod iter;
6mod range;
7
8pub use self::addr::{MemoryAddr, PhysAddr, VirtAddr};
9pub use self::iter::{DynPageIter, PageIter};
10pub use self::range::{AddrRange, PhysAddrRange, VirtAddrRange};
11
12/// The size of a 4K page (4096 bytes).
13pub const PAGE_SIZE_4K: usize = 0x1000;
14
15/// The size of a 2M page (2097152 bytes).
16pub const PAGE_SIZE_2M: usize = 0x20_0000;
17
18/// The size of a 1G page (1073741824 bytes).
19pub const PAGE_SIZE_1G: usize = 0x4000_0000;
20
21/// A [`PageIter`] for 4K pages.
22pub type PageIter4K<A> = PageIter<PAGE_SIZE_4K, A>;
23
24/// A [`PageIter`] for 2M pages.
25pub type PageIter2M<A> = PageIter<PAGE_SIZE_2M, A>;
26
27/// A [`PageIter`] for 1G pages.
28pub type PageIter1G<A> = PageIter<PAGE_SIZE_1G, A>;
29
30/// Align address downwards.
31///
32/// Returns the greatest `x` with alignment `align` so that `x <= addr`.
33///
34/// The alignment must be a power of two.
35#[inline]
36pub const fn align_down(addr: usize, align: usize) -> usize {
37    addr & !(align - 1)
38}
39
40/// Align address upwards.
41///
42/// Returns the smallest `x` with alignment `align` so that `x >= addr`.
43///
44/// The alignment must be a power of two.
45#[inline]
46pub const fn align_up(addr: usize, align: usize) -> usize {
47    (addr + align - 1) & !(align - 1)
48}
49
50/// Returns the offset of the address within the alignment.
51///
52/// Equivalent to `addr % align`, but the alignment must be a power of two.
53#[inline]
54pub const fn align_offset(addr: usize, align: usize) -> usize {
55    addr & (align - 1)
56}
57
58/// Checks whether the address has the demanded alignment.
59///
60/// Equivalent to `addr % align == 0`, but the alignment must be a power of two.
61#[inline]
62pub const fn is_aligned(addr: usize, align: usize) -> bool {
63    align_offset(addr, align) == 0
64}
65
66/// Align address downwards to 4096 (bytes).
67#[inline]
68pub const fn align_down_4k(addr: usize) -> usize {
69    align_down(addr, PAGE_SIZE_4K)
70}
71
72/// Align address upwards to 4096 (bytes).
73#[inline]
74pub const fn align_up_4k(addr: usize) -> usize {
75    align_up(addr, PAGE_SIZE_4K)
76}
77
78/// Returns the offset of the address within a 4K-sized page.
79#[inline]
80pub const fn align_offset_4k(addr: usize) -> usize {
81    align_offset(addr, PAGE_SIZE_4K)
82}
83
84/// Checks whether the address is 4K-aligned.
85#[inline]
86pub const fn is_aligned_4k(addr: usize) -> bool {
87    is_aligned(addr, PAGE_SIZE_4K)
88}
89
90#[cfg(test)]
91mod tests {
92    use super::*;
93
94    #[test]
95    fn test_align() {
96        assert_eq!(align_down(0x12345678, 0x1000), 0x12345000);
97        assert_eq!(align_up(0x12345678, 0x1000), 0x12346000);
98        assert_eq!(align_offset(0x12345678, 0x1000), 0x678);
99        assert!(is_aligned(0x12345000, 0x1000));
100        assert!(!is_aligned(0x12345678, 0x1000));
101
102        assert_eq!(align_down_4k(0x12345678), 0x12345000);
103        assert_eq!(align_up_4k(0x12345678), 0x12346000);
104        assert_eq!(align_offset_4k(0x12345678), 0x678);
105        assert!(is_aligned_4k(0x12345000));
106        assert!(!is_aligned_4k(0x12345678));
107    }
108}