cpu_local/register/
mod.rs1use core::{pin::Pin, ptr::NonNull, sync::atomic::Ordering};
4
5use crate::{CpuAreaRef, CpuLocalError, CpuPin, CurrentThreadHeader, ThreadSwitchError};
6
7#[cfg(all(not(feature = "host-test"), target_arch = "aarch64"))]
8mod aarch64;
9#[cfg(feature = "host-test")]
10mod host;
11#[cfg(all(not(feature = "host-test"), target_arch = "loongarch64"))]
12mod loongarch64;
13#[cfg(all(
14 not(feature = "host-test"),
15 any(target_arch = "riscv32", target_arch = "riscv64")
16))]
17mod riscv;
18#[cfg(all(not(feature = "host-test"), target_arch = "x86_64"))]
19mod x86_64;
20
21#[cfg(all(not(feature = "host-test"), target_arch = "aarch64"))]
22use aarch64 as imp;
23#[cfg(feature = "host-test")]
24use host as imp;
25#[cfg(all(not(feature = "host-test"), target_arch = "loongarch64"))]
26use loongarch64 as imp;
27#[cfg(all(
28 not(feature = "host-test"),
29 any(target_arch = "riscv32", target_arch = "riscv64")
30))]
31use riscv as imp;
32#[cfg(all(not(feature = "host-test"), target_arch = "x86_64"))]
33use x86_64 as imp;
34
35#[cfg(all(
36 not(feature = "host-test"),
37 not(any(
38 target_arch = "x86_64",
39 target_arch = "aarch64",
40 target_arch = "riscv32",
41 target_arch = "riscv64",
42 target_arch = "loongarch64"
43 ))
44))]
45compile_error!("cpu-local supports x86_64, AArch64, RISC-V, and LoongArch64 only");
46
47#[doc(hidden)]
54pub unsafe fn install_cpu_area(area: CpuAreaRef) -> Result<(), CpuLocalError> {
55 imp::validate_environment()?;
56 let boot_thread = area.prefix().boot_thread().header();
57 let boot_pointer = boot_thread as *const CurrentThreadHeader as usize;
58 unsafe { imp::install_cpu_base(area.base(), boot_pointer) };
60 if unsafe { imp::read_cpu_base()? } != area.base() {
61 fatal_register_invariant();
62 }
63 Ok(())
64}
65
66pub(crate) fn current_area() -> Result<CpuAreaRef, CpuLocalError> {
67 let area_base = unsafe { imp::read_cpu_base()? };
68 if area_base == 0 {
69 return Err(CpuLocalError::AreaNotInstalled);
70 }
71 unsafe { CpuAreaRef::from_initialized_base(area_base) }
74}
75
76pub(crate) unsafe fn commit_current_thread(area: CpuAreaRef, value: usize) {
83 area.runtime_anchor()
84 .current_thread_slot()
85 .store(value, Ordering::Release);
86}
87
88pub fn current_thread(pin: &CpuPin<'_>) -> Result<NonNull<CurrentThreadHeader>, CpuLocalError> {
90 let area = pin.area();
91 let slot = area.runtime_anchor().current_thread_raw();
92 let register = unsafe { imp::read_current_thread(area.base()) };
93 if slot == 0
94 || slot != register
95 || !slot.is_multiple_of(core::mem::align_of::<CurrentThreadHeader>())
96 {
97 return Err(CpuLocalError::CurrentThreadMismatch);
98 }
99 let pointer = NonNull::new(slot as *mut CurrentThreadHeader)
100 .ok_or(CpuLocalError::CurrentThreadMismatch)?;
101 let thread_area = unsafe { pointer.as_ref() }
104 .cpu_area()
105 .ok_or(CpuLocalError::CurrentThreadMismatch)?;
106 if thread_area != area {
107 return Err(CpuLocalError::CurrentThreadMismatch);
108 }
109 Ok(pointer)
110}
111
112#[doc(hidden)]
119pub unsafe fn scheduler_current_thread() -> Result<NonNull<CurrentThreadHeader>, CpuLocalError> {
120 let area = current_area()?;
121 let slot = area.runtime_anchor().current_thread_raw();
122 let register = unsafe { imp::read_current_thread(area.base()) };
123 if slot == 0 || slot != register {
124 return Err(CpuLocalError::CurrentThreadMismatch);
125 }
126 NonNull::new(slot as *mut CurrentThreadHeader).ok_or(CpuLocalError::CurrentThreadMismatch)
127}
128
129#[doc(hidden)]
136pub unsafe fn install_bootstrap_thread(
137 pin: &CpuPin<'_>,
138 header: Pin<&CurrentThreadHeader>,
139) -> Result<(), ThreadSwitchError> {
140 let epoch = unsafe { header.bind_cpu(pin.area()) }?;
141 let pointer = header.as_non_null().as_ptr() as usize;
142 unsafe { commit_current_thread(pin.area(), pointer) };
143 unsafe { imp::write_current_thread(pointer) };
146 if current_thread(pin) != Ok(header.as_non_null()) {
147 let _ = epoch;
150 fatal_register_invariant();
151 }
152 Ok(())
153}
154
155#[cfg(feature = "tls")]
157pub fn kernel_tls(_pin: &CpuPin<'_>) -> usize {
158 unsafe { imp::read_kernel_tls() }
159}
160
161#[cfg(feature = "tls")]
168#[doc(hidden)]
169pub unsafe fn install_kernel_tls(_pin: &CpuPin<'_>, value: usize) {
170 unsafe { imp::write_kernel_tls(value) };
171}
172
173#[cold]
174#[inline(never)]
175fn fatal_register_invariant() -> ! {
176 panic!("CPU-local register commit did not retain the validated state")
177}