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