Skip to main content

ax_hal/
lib.rs

1//! [ArceOS] hardware abstraction layer, provides unified APIs for
2//! platform-specific operations.
3//!
4//! It does the bootstrapping and initialization process for the specified
5//! platform, and provides useful operations on the hardware.
6//!
7//! Currently supported platforms (specify by cargo features):
8//!
9//! - `x86-pc`: Standard PC with x86_64 ISA.
10//! - `riscv64-qemu-virt`: QEMU virt machine with RISC-V ISA.
11//! - `aarch64-qemu-virt`: QEMU virt machine with AArch64 ISA.
12//! - `aarch64-raspi`: Raspberry Pi with AArch64 ISA.
13//! - `dummy`: If none of the above platform is selected, the dummy platform
14//!   will be used. In this platform, most of the operations are no-op or
15//!   `unimplemented!()`. This platform is mainly used for [cargo test].
16//!
17//! # Cargo Features
18//!
19//! - `smp`: Enable SMP (symmetric multiprocessing) support.
20//! - `fp-simd`: Enable floating-point and SIMD support.
21//! - `paging`: Enable page table manipulation.
22//! - `irq`: Enable interrupt handling support.
23//! - `tls`: Enable kernel space thread-local storage support.
24//! - `rtc`: Enable real-time clock support.
25//! - `uspace`: Enable user space support.
26//!
27//! [ArceOS]: https://github.com/arceos-org/arceos
28//! [cargo test]: https://doc.rust-lang.org/cargo/guide/tests.html
29
30#![no_std]
31
32#[allow(unused_imports)]
33#[macro_use]
34extern crate log;
35
36#[allow(unused_imports)]
37#[macro_use]
38extern crate ax_memory_addr;
39
40cfg_if::cfg_if! {
41    if #[cfg(feature = "myplat")] {
42        // link the custom platform crate in your application.
43    }
44    else if #[cfg(plat_dyn)] {
45        extern crate axplat_dyn;
46    }
47    else if #[cfg(all(target_os = "none", feature = "defplat"))] {
48        #[cfg(target_arch = "x86_64")]
49        extern crate ax_plat_x86_pc;
50        #[cfg(target_arch = "aarch64")]
51        extern crate ax_plat_aarch64_qemu_virt;
52        #[cfg(target_arch = "riscv64")]
53        extern crate ax_plat_riscv64_qemu_virt;
54        #[cfg(target_arch = "loongarch64")]
55        extern crate ax_plat_loongarch64_qemu_virt;
56    } else {
57        // Link the dummy platform implementation to pass cargo test.
58        mod dummy;
59    }
60}
61
62pub mod dtb;
63pub mod mem;
64pub mod percpu;
65pub mod time;
66
67#[cfg(feature = "tls")]
68pub mod tls;
69
70#[cfg(feature = "irq")]
71pub mod irq;
72
73#[cfg(feature = "paging")]
74pub mod paging;
75
76#[cfg(feature = "starry-kcov")]
77pub mod kcov;
78
79/// Console input and output.
80pub mod console {
81    #[cfg(feature = "irq")]
82    pub use ax_plat::console::{ConsoleIrqEvent, handle_irq, irq_num, set_input_irq_enabled};
83    pub use ax_plat::console::{read_bytes, write_bytes, write_text_bytes};
84}
85
86/// CPU power management.
87pub mod power {
88    #[cfg(feature = "smp")]
89    pub use ax_plat::power::cpu_boot;
90    pub use ax_plat::power::system_off;
91}
92
93/// Trap handling.
94pub mod trap {
95    #[cfg(target_arch = "x86_64")]
96    pub use ax_cpu::trap::debug_handler;
97    pub use ax_cpu::trap::{
98        PageFaultFlags, breakpoint_handler, dispatch_irq, dispatch_page_fault, irq_handler,
99        page_fault_handler, set_irq_handler, set_page_fault_handler,
100    };
101}
102
103/// CPU register states for context switching.
104///
105/// There are two types of context:
106///
107/// - [`TaskContext`][ax_cpu::TaskContext]: The context of a task.
108/// - [`TrapFrame`][ax_cpu::TrapFrame]: The context of an interrupt or an exception.
109pub mod context {
110    pub use ax_cpu::{TaskContext, TrapFrame};
111}
112
113pub use ax_cpu::asm;
114#[cfg(feature = "uspace")]
115pub use ax_cpu::uspace;
116pub use ax_plat::init::init_later;
117#[cfg(feature = "smp")]
118pub use ax_plat::init::{init_early_secondary, init_later_secondary};
119
120/// Initializes the platform and boot argument.
121/// This function should be called as early as possible.
122pub fn init_early(cpu_id: usize, arg: usize) {
123    dtb::init(arg);
124    ax_plat::init::init_early(cpu_id, arg);
125}
126
127/// Gets the number of CPUs running in the system.
128///
129/// When SMP is disabled, this function always returns 1.
130///
131/// When SMP is enabled, it's the smaller one between the platform-declared CPU
132/// number [`ax_plat::power::cpu_num`] and the configured maximum CPU number
133/// `ax_config::plat::MAX_CPU_NUM`.
134///
135/// This value is determined during the BSP initialization phase.
136pub fn cpu_num() -> usize {
137    #[cfg(feature = "smp")]
138    {
139        use spin::Lazy;
140
141        /// The number of CPUs in the system. Based on the number declared by the
142        /// platform crate and limited by the configured maximum CPU number.
143        static CPU_NUM: Lazy<usize> = Lazy::new(|| {
144            let max_cpu_num = ax_config::plat::MAX_CPU_NUM;
145            let plat_cpu_num = ax_plat::power::cpu_num();
146            let cpu_num = plat_cpu_num.min(max_cpu_num);
147
148            info!("CPU number: max = {max_cpu_num}, platform = {plat_cpu_num}, use = {cpu_num}");
149
150            if plat_cpu_num > max_cpu_num {
151                warn!(
152                    "platform declares more CPUs ({plat_cpu_num}) than configured max \
153                     ({max_cpu_num}), only the first {max_cpu_num} CPUs will be used."
154                );
155            }
156
157            cpu_num
158        });
159
160        *CPU_NUM
161    }
162    #[cfg(not(feature = "smp"))]
163    {
164        1
165    }
166}
167
168#[allow(unused_macros)]
169macro_rules! addr_of_sym {
170    ($e:ident) => {
171        $e as *const () as usize
172    };
173}
174pub(crate) use addr_of_sym;