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 in the MaskShiftSpec representation, initializing it if not already
22/// cached.
23#[inline(always)]
24fn page_mask_shift() -> u64 {
25    let val = PAGE_MASK_SHIFT.load(Ordering::Relaxed);
26    if val != 0 { val } else { initialize_page_mask_shift() }
27}
28
29/// [`BlockSizeSpec`] implementation representing the Fuchsia system memory page size.
30#[derive(Copy, Clone, Debug, Eq, PartialEq)]
31pub struct PageSizeSpec;
32
33impl BlockSizeSpec for PageSizeSpec {
34    #[inline(always)]
35    fn size(self) -> u64 {
36        self.mask() + 1
37    }
38
39    #[inline(always)]
40    fn mask(self) -> u64 {
41        page_mask_shift() >> 32
42    }
43
44    #[inline(always)]
45    fn shift(self) -> u32 {
46        page_mask_shift() as u32
47    }
48}
49
50/// The system memory page size.
51pub const PAGE_SIZE: GenericBlockSize<PageSizeSpec> = GenericBlockSize(PageSizeSpec);
52
53impl From<GenericBlockSize<PageSizeSpec>> for BlockSize {
54    #[inline(always)]
55    fn from(_value: GenericBlockSize<PageSizeSpec>) -> Self {
56        GenericBlockSize(MaskShiftSpec(page_mask_shift()))
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        assert_eq!(PAGE_SIZE.get(), expected);
68        assert_eq!(PAGE_SIZE.mask(), expected - 1);
69        assert_eq!(PAGE_SIZE.shift(), (expected - 1).trailing_ones());
70        assert_eq!(BlockSize::from(PAGE_SIZE).get(), expected);
71        assert_eq!(BlockSize::from(PAGE_SIZE).mask(), expected - 1);
72        assert_eq!(BlockSize::from(PAGE_SIZE).shift(), (expected - 1).trailing_ones());
73        assert!(PAGE_SIZE.is_aligned(expected));
74        assert!(!PAGE_SIZE.is_aligned(expected - 1));
75    }
76}