Skip to main content

ax_memory_addr/
lib.rs

1#![cfg_attr(not(test), no_std)]
2#![doc = include_str!("../README.md")]
3
4#[cfg(all(axtest, feature = "axtest"))]
5extern crate alloc;
6
7mod addr;
8mod iter;
9mod range;
10
11#[cfg(all(axtest, feature = "axtest"))]
12/// Coverage tests for address arithmetic and range iteration.
13pub mod axtest;
14
15pub use self::{
16    addr::{MemoryAddr, PhysAddr, VirtAddr},
17    iter::{DynPageIter, PageIter},
18    range::{AddrRange, PhysAddrRange, VirtAddrRange},
19};
20
21/// The size of a 4K page (4096 bytes).
22pub const PAGE_SIZE_4K: usize = 0x1000;
23
24/// The size of a 2M page (2097152 bytes).
25pub const PAGE_SIZE_2M: usize = 0x20_0000;
26
27/// The size of a 1G page (1073741824 bytes).
28pub const PAGE_SIZE_1G: usize = 0x4000_0000;
29
30/// A [`PageIter`] for 4K pages.
31pub type PageIter4K<A> = PageIter<PAGE_SIZE_4K, A>;
32
33/// A [`PageIter`] for 2M pages.
34pub type PageIter2M<A> = PageIter<PAGE_SIZE_2M, A>;
35
36/// A [`PageIter`] for 1G pages.
37pub type PageIter1G<A> = PageIter<PAGE_SIZE_1G, A>;
38
39/// Align address downwards.
40///
41/// Returns the greatest `x` with alignment `align` so that `x <= addr`.
42///
43/// The alignment must be a power of two.
44#[inline]
45pub const fn align_down(addr: usize, align: usize) -> usize {
46    addr & !(align - 1)
47}
48
49/// Align address upwards.
50///
51/// Returns the smallest `x` with alignment `align` so that `x >= addr`.
52///
53/// The alignment must be a power of two.
54#[inline]
55pub const fn align_up(addr: usize, align: usize) -> usize {
56    (addr + align - 1) & !(align - 1)
57}
58
59/// Returns the offset of the address within the alignment.
60///
61/// Equivalent to `addr % align`, but the alignment must be a power of two.
62#[inline]
63pub const fn align_offset(addr: usize, align: usize) -> usize {
64    addr & (align - 1)
65}
66
67/// Checks whether the address has the demanded alignment.
68///
69/// Equivalent to `addr % align == 0`, but the alignment must be a power of two.
70#[inline]
71pub const fn is_aligned(addr: usize, align: usize) -> bool {
72    align_offset(addr, align) == 0
73}
74
75/// Align address downwards to 4096 (bytes).
76#[inline]
77pub const fn align_down_4k(addr: usize) -> usize {
78    align_down(addr, PAGE_SIZE_4K)
79}
80
81/// Align address upwards to 4096 (bytes).
82#[inline]
83pub const fn align_up_4k(addr: usize) -> usize {
84    align_up(addr, PAGE_SIZE_4K)
85}
86
87/// Returns the offset of the address within a 4K-sized page.
88#[inline]
89pub const fn align_offset_4k(addr: usize) -> usize {
90    align_offset(addr, PAGE_SIZE_4K)
91}
92
93/// Checks whether the address is 4K-aligned.
94#[inline]
95pub const fn is_aligned_4k(addr: usize) -> bool {
96    is_aligned(addr, PAGE_SIZE_4K)
97}
98
99#[cfg(test)]
100mod tests {
101    use super::*;
102
103    #[test]
104    fn test_align() {
105        assert_eq!(align_down(0x12345678, 0x1000), 0x12345000);
106        assert_eq!(align_up(0x12345678, 0x1000), 0x12346000);
107        assert_eq!(align_offset(0x12345678, 0x1000), 0x678);
108        assert!(is_aligned(0x12345000, 0x1000));
109        assert!(!is_aligned(0x12345678, 0x1000));
110
111        assert_eq!(align_down_4k(0x12345678), 0x12345000);
112        assert_eq!(align_up_4k(0x12345678), 0x12346000);
113        assert_eq!(align_offset_4k(0x12345678), 0x678);
114        assert!(is_aligned_4k(0x12345000));
115        assert!(!is_aligned_4k(0x12345678));
116    }
117}
118
119#[cfg(all(axtest, feature = "axtest"))]
120pub fn memory_addr_page_size_constants_hold() -> bool {
121    // Page size constants
122    assert!(PAGE_SIZE_4K == 4096);
123    assert!(PAGE_SIZE_2M == 2097152);
124    assert!(PAGE_SIZE_1G == 1073741824);
125
126    // align_down and align_up basic tests
127    assert!(align_down(0, 4096) == 0);
128    assert!(align_up(0, 4096) == 0);
129    assert!(align_down(4096, 4096) == 4096);
130    assert!(align_up(4096, 4096) == 4096);
131    assert!(align_down(4097, 4096) == 4096);
132    assert!(align_up(4097, 4096) == 8192);
133
134    true
135}
136
137#[cfg(all(axtest, feature = "axtest"))]
138pub fn memory_addr_align_4k_helpers_hold() -> bool {
139    // Test 4K-specific alignment helpers
140    assert!(align_down_4k(0x12345) == 0x12000);
141    assert!(align_up_4k(0x12345) == 0x13000);
142    assert!(align_offset_4k(0x12345) == 0x345);
143    assert!(is_aligned_4k(0x12000));
144    assert!(!is_aligned_4k(0x12001));
145
146    true
147}