1use core::ptr::NonNull;
2
3use cpu_local::{CpuAreaPrefix, CpuAreaRef, CpuIndex, CpuPin, CpuRuntimeAnchor};
4
5use crate::{PerCpuError, layout::installed_layout};
6
7#[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 pub const fn cpu_index(self) -> CpuIndex {
26 self.cpu_index
27 }
28
29 pub const fn runtime_base(self) -> usize {
31 self.runtime_base
32 }
33
34 pub const fn area_size(self) -> usize {
36 self.area_size
37 }
38
39 pub fn cpu_area(self) -> Result<CpuAreaRef, PerCpuError> {
41 Ok(unsafe { CpuAreaRef::from_initialized_base(self.runtime_base) }?)
44 }
45
46 pub fn prefix(self) -> Result<&'static CpuAreaPrefix, PerCpuError> {
48 Ok(self.cpu_area()?.prefix())
49 }
50
51 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
65pub fn area(cpu_index: CpuIndex) -> Result<PerCpuArea, PerCpuError> {
67 installed_layout()?.area(cpu_index)
68}
69
70pub fn layout() -> Result<&'static crate::PerCpuLayout, PerCpuError> {
72 installed_layout()
73}
74
75pub 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
88pub const fn current_cpu_index(pin: &CpuPin<'_>) -> CpuIndex {
90 pin.area().cpu_index()
91}
92
93pub(crate) fn symbol_ptr<T>(area: PerCpuArea, offset: usize) -> NonNull<T> {
95 unsafe { NonNull::new_unchecked((area.runtime_base + offset) as *mut T) }
98}