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#![feature(allocator_api)]
33#![allow(missing_abi)]
34
35#[cfg(all(feature = "host-test", not(target_os = "none")))]
36extern crate std;
37#[cfg(all(feature = "std-compat", not(feature = "host-test")))]
38extern crate std;
39
40#[macro_use]
41extern crate ax_log;
42
43extern crate ax_driver as _;
44
45#[cfg(all(target_os = "none", not(feature = "std-compat"), not(test)))]
46mod lang_items;
47#[cfg(all(
48    feature = "stack-protector",
49    any(target_os = "none", target_env = "musl"),
50    not(test)
51))]
52mod stack_protector;
53
54#[cfg(feature = "smp")]
55mod mp;
56
57mod boot_memory;
58mod bootstrap;
59mod guard;
60#[cfg(feature = "irq-time-accounting")]
61mod irq_time;
62#[cfg(feature = "paging")]
63pub mod kernel_mapping;
64mod klib;
65#[cfg(any(feature = "std-compat", target_os = "none"))]
66mod panic_output;
67mod structured_log;
68
69/// Host-only adapters for testing runtime-owned capability providers.
70#[cfg(all(feature = "host-test", not(target_os = "none")))]
71pub mod host_test {
72    pub use crate::klib::{HostIomapOverride, try_install_iomap_override};
73}
74mod clock_event;
75
76mod clock_event_runtime;
77pub mod console;
78mod devices;
79pub mod emergency_console;
80mod error;
81mod fs;
82mod interrupt_bootstrap;
83#[cfg(any(feature = "ipi", feature = "wake-ipi", test))]
84mod ipi_delivery;
85pub mod irq;
86mod raw_console;
87mod registers;
88pub mod serial;
89mod sync_provider;
90
91/// OS-independent scheduler capabilities.
92pub use ax_task as task;
93pub mod thread;
94
95#[cfg(all(feature = "net", feature = "fs"))]
96mod unix_ns;
97
98pub use ax_hal as hal;
99pub use error::{RuntimeError, RuntimeResult};
100
101/// Drains task-console output before shutting down the whole system.
102///
103/// Fatal paths must bypass this task-context transaction and use the
104/// emergency console plus [`ax_hal::power::system_off`] directly.
105pub fn terminate() -> ! {
106    if let Ok(output) = console::output() {
107        let _ = output.drain();
108    }
109    clock_event_runtime::take_current_clock_event_offline();
110    ax_hal::power::system_off()
111}
112
113pub(crate) mod build_info {
114    include!(concat!(env!("OUT_DIR"), "/build_info.rs"));
115}
116
117/// Maximum logical CPU count represented by runtime-sized CPU masks.
118#[cfg(feature = "smp")]
119pub const CPU_CAPACITY: usize = build_info::CPU_CAPACITY;
120
121/// A uniprocessor runtime represents only CPU zero.
122#[cfg(not(feature = "smp"))]
123pub const CPU_CAPACITY: usize = 1;
124
125pub use bootstrap::rust_main;
126
127#[cfg(feature = "smp")]
128pub use self::mp::rust_main_secondary;
129
130extern crate alloc;
131
132#[cfg(feature = "fs")]
133pub(crate) fn runtime_default_task_stack_size() -> usize {
134    build_info::TASK_STACK_SIZE
135}
136
137fn ax_app_entry() {
138    #[cfg(all(feature = "std-compat", not(test)))]
139    {
140        unsafe extern "C" {
141            safe fn __axstd_std_check_entry();
142        }
143        __axstd_std_check_entry();
144    }
145
146    #[cfg(all(not(feature = "std-compat"), not(test)))]
147    {
148        unsafe extern "C" {
149            /// Legacy application's entry point.
150            safe fn main();
151        }
152        main();
153    }
154}
155
156struct LogIfImpl;
157
158#[ax_crate_interface::impl_interface]
159impl ax_log::LogIf for LogIfImpl {
160    fn try_publish(
161        meta: ax_log::RecordMeta,
162        args: core::fmt::Arguments<'_>,
163    ) -> ax_log::PublishStatus {
164        if let Some(status) = serial::try_publish_record(meta, args) {
165            return status;
166        }
167        let context = structured_log::with_runtime_log_context(core::convert::identity)
168            .unwrap_or_else(|_| structured_log::fallback_runtime_log_context(meta));
169        if let Some(status) = console::try_publish_without_runtime(meta, context, args) {
170            return status;
171        }
172        let mut writer = PlatformConsoleWriter::default();
173        if structured_log::write_record(&mut writer, meta, context, args).is_ok() {
174            ax_log::PublishStatus::Published
175        } else {
176            ax_log::PublishStatus::Dropped
177        }
178    }
179
180    fn emergency_write(args: core::fmt::Arguments<'_>) -> usize {
181        emergency_console::write_fmt(args)
182    }
183}
184
185#[derive(Default)]
186struct PlatformConsoleWriter {
187    written: usize,
188}
189
190impl core::fmt::Write for PlatformConsoleWriter {
191    fn write_str(&mut self, text: &str) -> core::fmt::Result {
192        ax_hal::console::write_text_bytes(text.as_bytes());
193        self.written = self.written.saturating_add(text.len());
194        Ok(())
195    }
196}
197
198use core::sync::atomic::{AtomicUsize, Ordering};
199
200/// Number of CPUs that have completed initialization.
201static INITED_CPUS: AtomicUsize = AtomicUsize::new(0);
202
203fn is_init_ok() -> bool {
204    INITED_CPUS.load(Ordering::Acquire) == ax_hal::cpu_num()
205}
206
207#[cfg(test)]
208mod tests {
209    #[test]
210    #[cfg(not(feature = "fs"))]
211    fn fs_init_accepts_bootargs_without_fs_feature() {
212        crate::fs::init(Some("root=/dev/nvme0n1"));
213    }
214}
215
216pub mod diagnostics;