ostd/
lib.rs

1// SPDX-License-Identifier: MPL-2.0
2
3//! The standard library for Asterinas and other Rust OSes.
4
5#![feature(alloc_error_handler)]
6#![feature(allocator_api)]
7#![feature(btree_cursors)]
8#![feature(core_intrinsics)]
9#![feature(iter_advance_by)]
10#![feature(linkage)]
11#![feature(macro_metavar_expr)]
12#![feature(min_specialization)]
13#![feature(negative_impls)]
14#![feature(ptr_metadata)]
15#![feature(sync_unsafe_cell)]
16#![expect(internal_features)]
17#![no_std]
18#![warn(missing_docs)]
19
20extern crate alloc;
21#[macro_use]
22extern crate ostd_pod;
23
24#[cfg_attr(target_arch = "x86_64", path = "arch/x86/mod.rs")]
25#[cfg_attr(target_arch = "riscv64", path = "arch/riscv/mod.rs")]
26#[cfg_attr(target_arch = "loongarch64", path = "arch/loongarch/mod.rs")]
27pub mod arch;
28
29pub mod boot;
30pub mod bus;
31pub mod console;
32pub mod cpu;
33mod error;
34mod ex_table;
35pub mod io;
36pub mod irq;
37pub mod logger;
38pub mod mm;
39pub mod panic;
40pub mod power;
41pub mod prelude;
42pub mod smp;
43pub mod sync;
44pub mod task;
45pub mod timer;
46pub mod user;
47pub mod util;
48
49#[cfg(feature = "coverage")]
50mod coverage;
51
52use core::sync::atomic::{AtomicBool, Ordering};
53
54pub use ostd_macros::{
55    global_frame_allocator, global_heap_allocator, global_heap_allocator_slot_map, main,
56    panic_handler,
57};
58
59pub use self::{error::Error, prelude::Result};
60
61/// Initializes OSTD.
62///
63/// This function represents the first phase booting up the system. It makes
64/// all functionalities of OSTD available after the call.
65///
66/// # Safety
67///
68/// This function should be called only once and only on the BSP.
69//
70// TODO: We need to refactor this function to make it more modular and
71// make inter-initialization-dependencies more clear and reduce usages of
72// boot stage only global variables.
73unsafe fn init() {
74    arch::enable_cpu_features();
75
76    // SAFETY: This function is called only once, before `allocator::init`
77    // and after memory regions are initialized.
78    unsafe { mm::frame::allocator::init_early_allocator() };
79
80    #[cfg(target_arch = "x86_64")]
81    arch::if_tdx_enabled!({
82    } else {
83        arch::serial::init();
84    });
85    #[cfg(not(target_arch = "x86_64"))]
86    arch::serial::init();
87
88    logger::init();
89
90    // SAFETY:
91    //  1. They are only called once in the boot context of the BSP.
92    //  2. The number of CPUs are available because ACPI has been initialized.
93    //  3. CPU-local storage has NOT been used.
94    unsafe { cpu::init_on_bsp() };
95
96    // SAFETY: We are on the BSP and APs are not yet started.
97    let meta_pages = unsafe { mm::frame::meta::init() };
98    // The frame allocator should be initialized immediately after the metadata
99    // is initialized. Otherwise the boot page table can't allocate frames.
100    // SAFETY: This function is called only once.
101    unsafe { mm::frame::allocator::init() };
102
103    mm::kspace::init_kernel_page_table(meta_pages);
104
105    // SAFETY: This function is called only once on the BSP.
106    unsafe { mm::kspace::activate_kernel_page_table() };
107
108    sync::init();
109
110    boot::init_after_heap();
111
112    // SAFETY: This function is called only once on the BSP.
113    unsafe { arch::late_init_on_bsp() };
114
115    #[cfg(target_arch = "x86_64")]
116    arch::if_tdx_enabled!({
117        arch::serial::init();
118    });
119
120    smp::init();
121
122    // SAFETY:
123    // 1. The kernel page table is activated on the BSP.
124    // 2. The function is called only once on the BSP.
125    // 3. No remaining `with_borrow` invocations from now.
126    unsafe { crate::mm::page_table::boot_pt::dismiss() };
127
128    arch::irq::enable_local();
129
130    invoke_ffi_init_funcs();
131
132    IN_BOOTSTRAP_CONTEXT.store(false, Ordering::Relaxed);
133}
134
135/// Indicates whether the kernel is in bootstrap context.
136pub(crate) static IN_BOOTSTRAP_CONTEXT: AtomicBool = AtomicBool::new(true);
137
138/// Invoke the initialization functions defined in the FFI.
139/// The component system uses this function to call the initialization functions of
140/// the components.
141fn invoke_ffi_init_funcs() {
142    unsafe extern "C" {
143        fn __sinit_array();
144        fn __einit_array();
145    }
146    let call_len = (__einit_array as *const () as usize - __sinit_array as *const () as usize) / 8;
147    for i in 0..call_len {
148        unsafe {
149            let function = (__sinit_array as *const () as usize + 8 * i) as *const fn();
150            (*function)();
151        }
152    }
153}
154
155mod feature_validation {
156    #[cfg(all(not(target_arch = "riscv64"), feature = "riscv_sv39_mode"))]
157    compile_error!(
158        "feature \"riscv_sv39_mode\" cannot be specified for architectures other than RISC-V"
159    );
160}
161
162/// Simple unit tests for the ktest framework.
163#[cfg(ktest)]
164mod test {
165    use crate::prelude::*;
166
167    #[ktest]
168    #[expect(clippy::eq_op)]
169    fn trivial_assertion() {
170        assert_eq!(0, 0);
171    }
172
173    #[ktest]
174    #[should_panic]
175    fn failing_assertion() {
176        assert_eq!(0, 1);
177    }
178
179    #[ktest]
180    #[should_panic(expected = "expected panic message")]
181    fn expect_panic() {
182        panic!("expected panic message");
183    }
184}
185
186#[doc(hidden)]
187pub mod ktest {
188    //! The module re-exports everything from the [`ostd_test`] crate, as well
189    //! as the test entry point macro.
190    //!
191    //! It is rather discouraged to use the definitions here directly. The
192    //! `ktest` attribute is sufficient for all normal use cases.
193
194    pub use ostd_macros::{test_main as main, test_panic_handler as panic_handler};
195    pub use ostd_test::*;
196}