twizzler_rt_abi/
core.rs

1//! Low-level runtime functionality.
2
3/// Type for exit code.
4pub type ExitCode = crate::bindings::exit_code;
5#[cfg(not(feature = "kernel"))]
6use crate::error::{GenericError, TwzError};
7
8/// Exit with the provided error code. If the main thread for a program
9/// exits, the remaining threads will exit as well.
10#[cfg(not(feature = "kernel"))]
11pub fn twz_rt_exit(code: ExitCode) -> ! {
12    unsafe {
13        crate::bindings::twz_rt_exit(code);
14        unreachable!()
15    }
16}
17
18/// Abort execution due to unrecoverable language error.
19#[cfg(not(feature = "kernel"))]
20pub fn twz_rt_abort() -> ! {
21    unsafe {
22        crate::bindings::twz_rt_abort();
23        unreachable!()
24    }
25}
26
27/// Call this before calling main, after initializing the runtime.
28/// If this function returns None, then call main. Otherwise, act
29/// as if main returned the provided [ExitCode].
30#[cfg(not(feature = "kernel"))]
31pub fn twz_rt_pre_main_hook() -> Option<ExitCode> {
32    unsafe { crate::bindings::twz_rt_pre_main_hook().into() }
33}
34
35impl From<crate::bindings::option_exit_code> for Option<ExitCode> {
36    #[inline]
37    fn from(value: crate::bindings::option_exit_code) -> Self {
38        if value.is_some == 0 {
39            None
40        } else {
41            Some(value.value)
42        }
43    }
44}
45
46/// Call this after return from main, before running destructors.
47#[cfg(not(feature = "kernel"))]
48pub fn twz_rt_post_main_hook() {
49    unsafe {
50        crate::bindings::twz_rt_post_main_hook();
51    }
52}
53
54/// Called by security context code on compartment entry
55#[cfg(not(feature = "kernel"))]
56pub fn twz_rt_cross_compartment_entry() -> Result<(), TwzError> {
57    unsafe {
58        if crate::bindings::twz_rt_cross_compartment_entry() {
59            Ok(())
60        } else {
61            Err(GenericError::AccessDenied.into())
62        }
63    }
64}
65
66pub use crate::bindings::{
67    basic_aux as BasicAux, basic_return as BasicReturn, comp_init_info as CompartmentInitInfo,
68    ctor_set as CtorSet, init_info_ptrs as InitInfoPtrs, minimal_init_info as MinimalInitInfo,
69    runtime_info as RuntimeInfo, RUNTIME_INIT_COMP, RUNTIME_INIT_MIN, RUNTIME_INIT_MONITOR,
70};
71
72// Safety: this holds functions pointers, but these pointers have 'static lifetime.
73unsafe impl Send for CtorSet {}
74
75// Safety: this holds functions pointers, but these pointers have 'static lifetime.
76unsafe impl Sync for CtorSet {}
77
78unsafe impl Send for RuntimeInfo {}
79unsafe impl Sync for RuntimeInfo {}
80unsafe impl Send for CompartmentInitInfo {}
81unsafe impl Sync for CompartmentInitInfo {}
82
83/// The entry point for the runtime. Not for public use.
84#[cfg(not(feature = "kernel"))]
85pub fn twz_rt_runtime_entry(
86    info: *const RuntimeInfo,
87    std_entry: unsafe extern "C-unwind" fn(BasicAux) -> BasicReturn,
88) -> ! {
89    unsafe {
90        crate::bindings::twz_rt_runtime_entry(info, Some(std_entry));
91        unreachable!()
92    }
93}
94
95#[cfg(all(feature = "rt0", not(feature = "kernel")))]
96pub mod rt0 {
97    //! rt0 defines a collection of functions that the basic Rust ABI expects to be defined by some
98    //! part of the C runtime:
99    //!
100    //!   - __tls_get_addr for handling non-local TLS regions.
101    //!   - _start, the entry point of an executable (per-arch, as this is assembly code).
102
103    #[cfg(target_arch = "aarch64")]
104    #[no_mangle]
105    #[naked]
106    pub unsafe extern "C" fn _start() {
107        core::arch::naked_asm!(
108            "b {entry}",
109            entry = sym entry,
110        );
111    }
112
113    #[cfg(target_arch = "x86_64")]
114    #[no_mangle]
115    #[naked]
116    pub unsafe extern "C" fn _start() {
117        // Align the stack and jump to rust code. If we come back, trigger an exception.
118        core::arch::naked_asm!(
119            "and rsp, 0xfffffffffffffff0",
120            "call {entry}",
121            "ud2",
122            entry = sym entry,
123        );
124    }
125
126    #[used]
127    // Ensure the compiler doesn't optimize us away!
128    static ENTRY: unsafe extern "C" fn() = _start;
129
130    use super::{BasicAux, BasicReturn, RuntimeInfo};
131
132    // The C-based entry point coming from arch-specific assembly _start function.
133    unsafe extern "C" fn entry(arg: usize) -> ! {
134        // Just trampoline to rust-abi code.
135        rust_entry(arg as *const _)
136    }
137
138    /// Entry point for Rust code wishing to start from rt0.
139    ///
140    /// # Safety
141    /// Do not call this unless you are bootstrapping a runtime.
142    pub unsafe fn rust_entry(arg: *const RuntimeInfo) -> ! {
143        // All we need to do is grab the runtime and call its init function. We want to
144        // do as little as possible here.
145        super::twz_rt_runtime_entry(arg, std_entry_from_runtime)
146    }
147
148    extern "C-unwind" {
149        fn std_entry_from_runtime(aux: BasicAux) -> BasicReturn;
150    }
151}