Skip to main content

storage_units/
page.rs

1// Copyright 2026 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::{BlockSize, BlockSizeSpec, GenericBlockSize, MaskShiftSpec};
6use std::sync::atomic::{AtomicU64, Ordering};
7
8/// Cached system page size in the MaskShiftSpec representation, initialized on first access.
9static PAGE_MASK_SHIFT: AtomicU64 = AtomicU64::new(0);
10
11/// Initializes `PAGE_MASK_SHIFT`.
12#[cold]
13#[inline(never)]
14fn initialize_page_mask_shift() -> u64 {
15    let page_size = zx::system_get_page_size();
16    let repr = MaskShiftSpec::new(page_size as u64).0;
17    PAGE_MASK_SHIFT.store(repr, Ordering::Relaxed);
18    repr
19}
20
21/// Returns the system page size as a [`PageSize`].
22#[inline(always)]
23pub fn page_size() -> PageSize {
24    let val = PAGE_MASK_SHIFT.load(Ordering::Relaxed);
25    let val = if val != 0 { val } else { initialize_page_mask_shift() };
26    GenericBlockSize(PageSizeSpec(MaskShiftSpec(val)))
27}
28
29/// A [`GenericBlockSize`] configured with the system's page size.
30pub type PageSize = GenericBlockSize<PageSizeSpec>;
31
32/// [`BlockSizeSpec`] implementation representing the Fuchsia system memory page size.
33#[derive(Copy, Clone, Debug, Eq, PartialEq)]
34pub struct PageSizeSpec(MaskShiftSpec);
35
36impl BlockSizeSpec for PageSizeSpec {
37    #[inline(always)]
38    fn size(self) -> u64 {
39        self.0.size()
40    }
41
42    #[inline(always)]
43    fn mask(self) -> u64 {
44        self.0.mask()
45    }
46
47    #[inline(always)]
48    fn shift(self) -> u32 {
49        self.0.shift()
50    }
51}
52
53impl From<PageSize> for BlockSize {
54    #[inline(always)]
55    fn from(page_size: PageSize) -> Self {
56        GenericBlockSize(page_size.0.0)
57    }
58}
59
60#[cfg(test)]
61mod tests {
62    use super::*;
63
64    #[fuchsia::test]
65    fn test_page_size() {
66        let expected = zx::system_get_page_size() as u64;
67        let page_size = page_size();
68        assert_eq!(page_size.get(), expected);
69        assert_eq!(page_size.mask(), expected - 1);
70        assert_eq!(page_size.shift(), (expected - 1).trailing_ones());
71        assert!(page_size.is_aligned(expected));
72        assert!(!page_size.is_aligned(expected - 1));
73    }
74
75    #[fuchsia::test]
76    fn test_page_size_to_block_size() {
77        let page_size = page_size();
78        let block_size: BlockSize = page_size.into();
79        assert_eq!(page_size.get(), block_size.get());
80        assert_eq!(page_size.mask(), block_size.mask());
81        assert_eq!(page_size.shift(), block_size.shift());
82    }
83}