Skip to main content

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