Skip to main content

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