Skip to main content

ax_cpu/
lib.rs

1#![cfg_attr(not(test), no_std)]
2#![cfg_attr(docsrs, feature(doc_cfg))]
3#![deny(missing_docs)]
4#![doc = include_str!("../README.md")]
5
6#[cfg(all(feature = "host-test", not(target_os = "none")))]
7extern crate std;
8
9#[macro_use]
10extern crate log;
11
12#[macro_use]
13extern crate ax_memory_addr;
14
15#[macro_use]
16pub mod trap;
17
18pub use trap::TrapOrigin;
19
20mod task_local;
21pub use task_local::TaskLocalState;
22
23pub mod cap;
24
25pub mod paging;
26
27/// Kernel task-local storage base owned by one execution context.
28///
29/// This value follows a task across CPUs. It must never be used as a CPU-local
30/// anchor or initialized from an architecture per-CPU register.
31#[repr(transparent)]
32#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
33pub struct KernelTlsBase(usize);
34
35impl KernelTlsBase {
36    /// Creates a kernel TLS base from its virtual address.
37    pub const fn new(address: usize) -> Self {
38        Self(address)
39    }
40
41    /// Returns the virtual address represented by this TLS base.
42    pub const fn as_usize(self) -> usize {
43        self.0
44    }
45
46    pub(crate) fn for_task_context(requested: Self) -> Self {
47        if cfg!(kernel_tls) {
48            requested
49        } else {
50            assert!(
51                requested.0 == 0,
52                "LinuxCurrent task contexts must not own a kernel TLS register"
53            );
54            Self(0)
55        }
56    }
57}
58
59/// Hardware tag policy carried with an installed userspace address space.
60#[derive(Clone, Copy, Debug, Eq, PartialEq)]
61pub enum InstalledAddressSpaceMode {
62    /// The architecture may retain translations distinguished by a hardware
63    /// tag and software generation.
64    Tagged,
65    /// The architecture uses tag zero and flushes translations when changing
66    /// address spaces.
67    FullFlush,
68}
69
70/// Complete software identity installed with one hardware page-table root.
71///
72/// The root is intentionally private. Scheduler code moves this value as a
73/// unit, while architecture code is the only layer allowed to project the
74/// materialized root that is written to a register.
75#[derive(Clone, Copy, Debug, Eq, PartialEq)]
76pub struct InstalledAddressSpace {
77    space_id: u64,
78    root: ax_memory_addr::PhysAddr,
79    hardware_tag: u16,
80    tag_generation: u64,
81    epoch: u64,
82    mode: InstalledAddressSpaceMode,
83}
84
85impl InstalledAddressSpace {
86    /// Constructs a validated userspace installation identity.
87    ///
88    /// Returns `None` for the reserved zero identity, a zero root, or a tag
89    /// that is inconsistent with its installation mode.
90    pub fn user(
91        space_id: u64,
92        root: ax_memory_addr::PhysAddr,
93        hardware_tag: u16,
94        tag_generation: u64,
95        epoch: u64,
96        mode: InstalledAddressSpaceMode,
97    ) -> Option<Self> {
98        if space_id == 0 || root.as_usize() == 0 {
99            return None;
100        }
101        match mode {
102            InstalledAddressSpaceMode::Tagged if hardware_tag == 0 => return None,
103            InstalledAddressSpaceMode::FullFlush if hardware_tag != 0 => return None,
104            InstalledAddressSpaceMode::Tagged | InstalledAddressSpaceMode::FullFlush => {}
105        }
106        Some(Self {
107            space_id,
108            root,
109            hardware_tag,
110            tag_generation,
111            epoch,
112            mode,
113        })
114    }
115
116    /// Constructs the kernel-root context used by bootstrap and CPU-offline
117    /// paths. It carries no userspace identity or reusable hardware tag.
118    pub const fn kernel(root: ax_memory_addr::PhysAddr) -> Self {
119        Self {
120            space_id: 0,
121            root,
122            hardware_tag: 0,
123            tag_generation: 0,
124            epoch: 0,
125            mode: InstalledAddressSpaceMode::FullFlush,
126        }
127    }
128
129    /// Returns whether this value represents a userspace address space.
130    pub const fn is_user(self) -> bool {
131        self.space_id != 0
132    }
133
134    /// Returns the stable software address-space identity.
135    pub const fn space_id(self) -> u64 {
136        self.space_id
137    }
138
139    /// Returns the hardware address-space tag.
140    pub const fn hardware_tag(self) -> u16 {
141        self.hardware_tag
142    }
143
144    /// Returns the software generation associated with the hardware tag.
145    pub const fn tag_generation(self) -> u64 {
146        self.tag_generation
147    }
148
149    /// Returns the VMA/PTE publication epoch represented by this context.
150    pub const fn epoch(self) -> u64 {
151        self.epoch
152    }
153
154    /// Returns the hardware tag policy.
155    pub const fn mode(self) -> InstalledAddressSpaceMode {
156        self.mode
157    }
158
159    #[cfg(feature = "uspace")]
160    pub(crate) const fn root(self) -> ax_memory_addr::PhysAddr {
161        self.root
162    }
163
164    #[cfg(feature = "uspace")]
165    pub(crate) fn validate_architecture_support(self) {
166        #[cfg(any(
167            target_arch = "x86_64",
168            target_arch = "riscv32",
169            target_arch = "riscv64",
170            target_arch = "loongarch64"
171        ))]
172        debug_assert!(
173            self.root.as_usize() != 0,
174            "this architecture requires a materialized kernel or userspace root"
175        );
176
177        #[cfg(target_arch = "aarch64")]
178        debug_assert!(
179            !self.is_user() || self.root.as_usize() != 0,
180            "a userspace identity always requires a materialized root"
181        );
182    }
183}
184
185impl Default for InstalledAddressSpace {
186    fn default() -> Self {
187        Self::kernel(ax_memory_addr::PhysAddr::from_usize(0))
188    }
189}
190
191#[cfg(feature = "exception-table")]
192mod exception_table;
193#[cfg(feature = "uspace")]
194mod user_access;
195#[cfg(feature = "uspace")]
196mod uspace_common;
197#[cfg(feature = "uspace")]
198pub use user_access::{
199    UserAccessError, UserAccessType, UserAtomicError, UserAtomicU32Op, user_atomic_u32,
200    user_read_u32,
201};
202
203cfg_if::cfg_if! {
204    if #[cfg(target_arch = "x86_64")] {
205        mod x86_64;
206        pub use self::x86_64::*;
207    } else if #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] {
208        mod riscv;
209        pub use self::riscv::*;
210    } else if #[cfg(target_arch = "aarch64")]{
211        mod aarch64;
212        pub use self::aarch64::*;
213    } else if #[cfg(any(target_arch = "loongarch64"))] {
214        mod loongarch64;
215        pub use self::loongarch64::*;
216    }
217}