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