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