ostd/
lib.rs

1// SPDX-License-Identifier: MPL-2.0
2
3#![doc = include_str!("../README.md")]
4#![feature(alloc_error_handler)]
5#![feature(allocator_api)]
6#![feature(btree_cursors)]
7#![feature(core_intrinsics)]
8#![feature(iter_advance_by)]
9#![feature(linkage)]
10#![feature(macro_metavar_expr)]
11#![feature(min_specialization)]
12#![feature(negative_impls)]
13#![feature(ptr_metadata)]
14#![feature(sync_unsafe_cell)]
15#![expect(internal_features)]
16#![no_std]
17#![warn(missing_docs)]
18
19extern crate alloc;
20#[macro_use]
21extern crate ostd_pod;
22
23#[cfg_attr(target_arch = "x86_64", path = "arch/x86/mod.rs")]
24#[cfg_attr(target_arch = "riscv64", path = "arch/riscv/mod.rs")]
25#[cfg_attr(target_arch = "loongarch64", path = "arch/loongarch/mod.rs")]
26pub mod arch;
27
28pub mod boot;
29pub mod bus;
30pub mod console;
31pub mod cpu;
32mod error;
33mod ex_table;
34pub mod io;
35pub mod irq;
36pub mod logger;
37pub mod mm;
38pub mod panic;
39pub mod power;
40pub mod prelude;
41pub mod smp;
42pub mod sync;
43pub mod task;
44pub mod timer;
45pub mod user;
46pub mod util;
47
48#[cfg(feature = "coverage")]
49mod coverage;
50
51use core::sync::atomic::{AtomicBool, Ordering};
52
53pub use ostd_macros::{
54    global_frame_allocator, global_heap_allocator, global_heap_allocator_slot_map, main,
55    panic_handler,
56};
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    // SAFETY: This function is called only once on the BSP.
112    unsafe { arch::late_init_on_bsp() };
113
114    #[cfg(target_arch = "x86_64")]
115    arch::if_tdx_enabled!({
116        arch::serial::init();
117    });
118
119    smp::init();
120
121    // SAFETY:
122    // 1. The kernel page table is activated on the BSP.
123    // 2. The function is called only once on the BSP.
124    // 3. No remaining `with_borrow` invocations from now.
125    unsafe { crate::mm::page_table::boot_pt::dismiss() };
126
127    arch::irq::enable_local();
128
129    invoke_ffi_init_funcs();
130
131    IN_BOOTSTRAP_CONTEXT.store(false, Ordering::Relaxed);
132}
133
134/// Indicates whether the kernel is in bootstrap context.
135pub(crate) static IN_BOOTSTRAP_CONTEXT: AtomicBool = AtomicBool::new(true);
136
137/// Invoke the initialization functions defined in the FFI.
138/// The component system uses this function to call the initialization functions of
139/// the components.
140fn invoke_ffi_init_funcs() {
141    unsafe extern "C" {
142        fn __sinit_array();
143        fn __einit_array();
144    }
145    let call_len = (__einit_array as *const () as usize - __sinit_array as *const () as usize) / 8;
146    for i in 0..call_len {
147        unsafe {
148            let function = (__sinit_array as *const () as usize + 8 * i) as *const fn();
149            (*function)();
150        }
151    }
152}
153
154mod feature_validation {
155    #[cfg(all(not(target_arch = "riscv64"), feature = "riscv_sv39_mode"))]
156    compile_error!(
157        "feature \"riscv_sv39_mode\" cannot be specified for architectures other than RISC-V"
158    );
159}
160
161/// Simple unit tests for the ktest framework.
162#[cfg(ktest)]
163mod test {
164    use crate::prelude::*;
165
166    #[ktest]
167    #[expect(clippy::eq_op)]
168    fn trivial_assertion() {
169        assert_eq!(0, 0);
170    }
171
172    #[ktest]
173    #[should_panic]
174    fn failing_assertion() {
175        assert_eq!(0, 1);
176    }
177
178    #[ktest]
179    #[should_panic(expected = "expected panic message")]
180    fn expect_panic() {
181        panic!("expected panic message");
182    }
183}
184
185#[doc(hidden)]
186pub mod ktest {
187    //! The module re-exports everything from the [`ostd_test`] crate, as well
188    //! as the test entry point macro.
189    //!
190    //! It is rather discouraged to use the definitions here directly. The
191    //! `ktest` attribute is sufficient for all normal use cases.
192
193    pub use ostd_macros::{test_main as main, test_panic_handler as panic_handler};
194    pub use ostd_test::*;
195}