Skip to main content

ax_runtime/
lib.rs

1// Copyright 2025 The Axvisor Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Runtime library of [ArceOS](https://github.com/arceos-org/arceos).
16//!
17//! Any application uses ArceOS should link this library. It does some
18//! initialization work before entering the application's `main` function.
19//!
20//! # Cargo Features
21//!
22//! - `paging`: Enable page table manipulation support.
23//! - `smp`: Enable SMP (symmetric multiprocessing) support.
24//! - `fs`: Enable filesystem support.
25//! - `net`: Enable networking support.
26//! - `display`: Enable graphics support.
27//!
28//!
29//! Interrupt handling and task scheduling are mandatory runtime capabilities.
30
31#![cfg_attr(not(test), no_std)]
32#![allow(missing_abi)]
33
34#[cfg(all(feature = "host-test", not(target_os = "none")))]
35extern crate std;
36#[cfg(all(feature = "std-compat", not(feature = "host-test")))]
37extern crate std;
38
39#[macro_use]
40extern crate ax_log;
41
42extern crate ax_driver as _;
43
44#[cfg(all(target_os = "none", not(feature = "std-compat"), not(test)))]
45mod lang_items;
46#[cfg(all(
47    feature = "stack-protector",
48    any(target_os = "none", target_env = "musl"),
49    not(test)
50))]
51mod stack_protector;
52
53#[cfg(feature = "smp")]
54mod mp;
55
56mod boot_memory;
57mod bootstrap;
58mod guard;
59#[cfg(feature = "irq-time-accounting")]
60mod irq_time;
61#[cfg(feature = "paging")]
62pub mod kernel_mapping;
63mod klib;
64#[cfg(any(feature = "std-compat", target_os = "none"))]
65mod panic_output;
66mod structured_log;
67
68/// Host-only adapters for testing runtime-owned capability providers.
69#[cfg(all(feature = "host-test", not(target_os = "none")))]
70pub mod host_test {
71    pub use crate::klib::{HostIomapOverride, try_install_iomap_override};
72}
73mod clock_event;
74
75mod clock_event_runtime;
76pub mod console;
77mod devices;
78pub mod emergency_console;
79mod error;
80mod fs;
81mod interrupt_bootstrap;
82#[cfg(any(feature = "ipi", feature = "wake-ipi", test))]
83mod ipi_delivery;
84pub mod irq;
85mod raw_console;
86mod registers;
87pub mod serial;
88mod sync_provider;
89
90/// OS-independent scheduler capabilities.
91pub use ax_task as task;
92pub mod thread;
93
94#[cfg(all(feature = "net", feature = "fs"))]
95mod unix_ns;
96
97pub use ax_hal as hal;
98pub use error::{RuntimeError, RuntimeResult};
99
100/// Drains task-console output before shutting down the whole system.
101///
102/// Fatal paths must bypass this task-context transaction and use the
103/// emergency console plus [`ax_hal::power::system_off`] directly.
104pub fn terminate() -> ! {
105    if let Ok(output) = console::output() {
106        let _ = output.drain();
107    }
108    clock_event_runtime::take_current_clock_event_offline();
109    ax_hal::power::system_off()
110}
111
112pub(crate) mod build_info {
113    include!(concat!(env!("OUT_DIR"), "/build_info.rs"));
114}
115
116/// Maximum logical CPU count represented by runtime-sized CPU masks.
117#[cfg(feature = "smp")]
118pub const CPU_CAPACITY: usize = build_info::CPU_CAPACITY;
119
120/// A uniprocessor runtime represents only CPU zero.
121#[cfg(not(feature = "smp"))]
122pub const CPU_CAPACITY: usize = 1;
123
124pub use bootstrap::rust_main;
125
126#[cfg(feature = "smp")]
127pub use self::mp::rust_main_secondary;
128
129extern crate alloc;
130
131#[cfg(feature = "fs")]
132pub(crate) fn runtime_default_task_stack_size() -> usize {
133    build_info::TASK_STACK_SIZE
134}
135
136fn ax_app_entry() {
137    #[cfg(all(feature = "std-compat", not(test)))]
138    {
139        unsafe extern "C" {
140            safe fn __axstd_std_check_entry();
141        }
142        __axstd_std_check_entry();
143    }
144
145    #[cfg(all(not(feature = "std-compat"), not(test)))]
146    {
147        unsafe extern "C" {
148            /// Legacy application's entry point.
149            safe fn main();
150        }
151        main();
152    }
153}
154
155struct LogIfImpl;
156
157#[ax_crate_interface::impl_interface]
158impl ax_log::LogIf for LogIfImpl {
159    fn try_publish(
160        meta: ax_log::RecordMeta,
161        args: core::fmt::Arguments<'_>,
162    ) -> ax_log::PublishStatus {
163        if let Some(status) = serial::try_publish_record(meta, args) {
164            return status;
165        }
166        let context = structured_log::with_runtime_log_context(core::convert::identity)
167            .unwrap_or_else(|_| structured_log::fallback_runtime_log_context(meta));
168        if let Some(status) = console::try_publish_without_runtime(meta, context, args) {
169            return status;
170        }
171        let mut writer = PlatformConsoleWriter::default();
172        if structured_log::write_record(&mut writer, meta, context, args).is_ok() {
173            ax_log::PublishStatus::Published
174        } else {
175            ax_log::PublishStatus::Dropped
176        }
177    }
178
179    fn emergency_write(args: core::fmt::Arguments<'_>) -> usize {
180        emergency_console::write_fmt(args)
181    }
182}
183
184#[derive(Default)]
185struct PlatformConsoleWriter {
186    written: usize,
187}
188
189impl core::fmt::Write for PlatformConsoleWriter {
190    fn write_str(&mut self, text: &str) -> core::fmt::Result {
191        ax_hal::console::write_text_bytes(text.as_bytes());
192        self.written = self.written.saturating_add(text.len());
193        Ok(())
194    }
195}
196
197use core::sync::atomic::{AtomicUsize, Ordering};
198
199/// Number of CPUs that have completed initialization.
200static INITED_CPUS: AtomicUsize = AtomicUsize::new(0);
201
202fn is_init_ok() -> bool {
203    INITED_CPUS.load(Ordering::Acquire) == ax_hal::cpu_num()
204}
205
206#[cfg(test)]
207mod tests {
208    #[test]
209    #[cfg(not(feature = "fs"))]
210    fn fs_init_accepts_bootargs_without_fs_feature() {
211        crate::fs::init(Some("root=/dev/nvme0n1"));
212    }
213}
214
215pub mod diagnostics;