Skip to main content

ax_percpu/
area.rs

1use core::ptr::NonNull;
2
3use cpu_local::{CpuAreaPrefix, CpuAreaRef, CpuIndex, CpuPin, CpuRuntimeAnchor};
4
5use crate::{PerCpuError, layout::installed_layout};
6
7/// Descriptor for one initialized runtime per-CPU area.
8#[derive(Clone, Copy, Debug, Eq, PartialEq)]
9pub struct PerCpuArea {
10    cpu_index: CpuIndex,
11    runtime_base: usize,
12    area_size: usize,
13}
14
15impl PerCpuArea {
16    pub(crate) const fn new(cpu_index: CpuIndex, runtime_base: usize, area_size: usize) -> Self {
17        Self {
18            cpu_index,
19            runtime_base,
20            area_size,
21        }
22    }
23
24    /// Returns this area's logical CPU index.
25    pub const fn cpu_index(self) -> CpuIndex {
26        self.cpu_index
27    }
28
29    /// Returns this area's exact runtime base.
30    pub const fn runtime_base(self) -> usize {
31        self.runtime_base
32    }
33
34    /// Returns the initialized byte size in this area.
35    pub const fn area_size(self) -> usize {
36        self.area_size
37    }
38
39    /// Returns the validated CPU-local prefix identity.
40    pub fn cpu_area(self) -> Result<CpuAreaRef, PerCpuError> {
41        // SAFETY: PerCpuArea is only produced by the frozen layout after every
42        // prefix has been initialized in shutdown-lifetime storage.
43        Ok(unsafe { CpuAreaRef::from_initialized_base(self.runtime_base) }?)
44    }
45
46    /// Returns the initialized fixed prefix.
47    pub fn prefix(self) -> Result<&'static CpuAreaPrefix, PerCpuError> {
48        Ok(self.cpu_area()?.prefix())
49    }
50
51    /// Returns this remote area's runtime/trap anchor.
52    pub fn runtime_anchor(self) -> Result<&'static CpuRuntimeAnchor, PerCpuError> {
53        Ok(self.cpu_area()?.runtime_anchor())
54    }
55
56    pub(crate) fn runtime_ptr(self) -> *mut u8 {
57        self.runtime_base as *mut u8
58    }
59
60    pub(crate) fn prefix_ptr(self) -> *mut CpuAreaPrefix {
61        self.runtime_base as *mut CpuAreaPrefix
62    }
63}
64
65/// Returns one remote or current CPU area in O(1).
66pub fn area(cpu_index: CpuIndex) -> Result<PerCpuArea, PerCpuError> {
67    installed_layout()?.area(cpu_index)
68}
69
70/// Returns the immutable process-wide per-CPU layout.
71pub fn layout() -> Result<&'static crate::PerCpuLayout, PerCpuError> {
72    installed_layout()
73}
74
75/// Verifies that `pin` selects the area installed for its logical CPU.
76pub fn current_area(pin: &CpuPin<'_>) -> Result<PerCpuArea, PerCpuError> {
77    let expected = area(pin.area().cpu_index())?;
78    let expected_cpu_area = expected.cpu_area()?;
79    if expected_cpu_area != pin.area() {
80        return Err(PerCpuError::CurrentAreaMismatch {
81            expected: expected_cpu_area,
82            actual: pin.area(),
83        });
84    }
85    Ok(expected)
86}
87
88/// Returns the logical CPU index carried by a validated pin.
89pub const fn current_cpu_index(pin: &CpuPin<'_>) -> CpuIndex {
90    pin.area().cpu_index()
91}
92
93/// Calculates a typed pointer in a remote initialized area.
94pub(crate) fn symbol_ptr<T>(area: PerCpuArea, offset: usize) -> NonNull<T> {
95    // The offset comes from a validated final-image descriptor, and every
96    // PerCpuArea uses the same template geometry.
97    unsafe { NonNull::new_unchecked((area.runtime_base + offset) as *mut T) }
98}