ArceOS 内部机制
本文档面向准备修改内核模块、进行性能分析、补充特性或向上层系统复用 ArceOS 能力的开发者,重点阐述以下内 容:
- ArceOS 在 TGOSKits 中的分层边界。
- 能力如何从
Cargo feature装配到运行时模块。 - 启动、调度、文件系统、网络等核心子系统的内部协作机制。
- 功能改进、性能优化或二次开发的推荐切入点。
若仅需要运行示例,请先阅读 quick-start.md 和 arceos-guide.md。
1. 系统定位与设计目标
ArceOS 在本仓库中同时扮演三种角色:
| 角色 | 含义 | 在 TGOSKits 中的体现 |
|---|---|---|
| 组件化单内核 | 通过 Rust crate 与 feature 做编译期装配,尽量减少不需要的运行时负担 | os/arceos/modules/*、os/arceos/api/*、os/arceos/ulib/* |
| 基础系统平台 | 直接承载示例应用、测试包和实验性系统程序 | os/arceos/examples/*、test-suit/arceos/* |
| 共享能力提供者 | 为 StarryOS 和 AxVisor 复用 HAL、任务、内存、驱动等基础能力 | ax-hal、ax-task、ax-mm、ax-driver 等模块被上层系统直接依赖 |
ArceOS 的设计目标并非构建"大而全"的宏内核,而是强调以下原则:
| 目标 | 含义 | 典型实现 |
|---|---|---|
| 编译期可裁剪 | 只链接被 feature 选中的能力,避免把不需要的子系统塞进镜 像 | ax-feat、ax-runtime/Cargo.toml |
| 层次分离 | 把可复用 crate、OS 相关模块、API 封装、用户库和应用分开管理 | components/、modules/、api/、ulib/ |
| 跨平台 | 用统一 HAL 和平台 crate 支撑多架构与多板级目标 | ax-hal、axplat-*、platform/* |
| 低抽象损耗 | ax-std 直接调用 ArceOS 模块,而不是先走 libc 和 syscall | os/arceos/ulib/axstd/src/lib.rs |
| Rust 安全性 | 利用所有权、trait、类型系统和同步原语减少数据竞争和空悬引用 | ax-sync、ax-task、ax-crate-interface |
2. 架构概览
从仓库结构来看,ArceOS 的核心价值在于这些 crate 被有意识地组织成一条从底层平台到上层应用的能力传递链。
理解此图可从两个方向入手:
- 自下而上:应用最终经由
user lib -> API -> modules -> HAL/platform链路获取能力。 - 自右向左:StarryOS 和 AxVisor 复用的是底层模块能力,修改
ax-hal、ax-task、ax-driver等模块可能同时影响多个系统。
2.1 分层职责
| 层次 | 主要目录 | 关注点 |
|---|---|---|
| 可复用 crate 层 | components/* | 算法、同步、容器、地址空间、设备抽象等可被多个系统复用的基础构件 |
| 平台与 HAL 层 | platform/*、components/axplat_crates/platforms/*、os/arceos/modules/axhal | 架构相关启动、时钟、中断、内存映射、设备访问 |
| 内核服务模块层 | os/arceos/modules/* | 内存分配、页表、任务调度、驱动、文件系统、网络、图形等 OS 能力 |
| API 聚合层 | os/arceos/api/* | feature 选择、稳定 API 封装、POSIX 兼容接口 |
| 用户库层 | os/arceos/ulib/* | ax-std、ax-libc 等高层开发接口 |
| 应用与测试层 | os/arceos/examples/*、test-suit/arceos/* | 场景化验证与系统回归 |
2.2 必选模块与可选模块
ArceOS 的基础骨架由四个必选模块组成:
ax-runtime:启动与初始化总控。ax-hal:统一硬件抽象层。axconfig:平台常量、栈大小、物理内存、目标平台等构建时参数。ax-log:日志输出与格式化。
其余模块大多按 feature 启用,以下按功能域分类列出:
| 模块 | 典型 feature | 作用 |
|---|---|---|
ax-alloc | alloc | 全局内存分配器(支持 TLSF、buddy、slab 等策略) |
ax-mm | paging | 地址空间与页表管理 |
ax-task | multitask、sched-* | 任务创建、调度(FIFO/RR/CFS)、sleep、wait queue |
ax-sync | multitask | mutex、信号量等同步原语 |
ax-driver | driver-*、fs、net、display | 设备探测与驱动初始化(virtio、AHCI、SDMMC 等) |
ax-fs | fs | 文件系统(FAT、ramfs、ext4) |
ax-fs-ng | fs-ng | 下一代文件系统(FAT、ext4,带 LRU 缓存) |
ax-net | net | 网络栈(基于 smoltcp) |
ax-net-ng | net-ng | 下一代网络栈(异步感知) |
ax-display | display | 图形显示(帧缓冲) |
ax-input | input | 输入设备管理 |
ax-dma | dma | DMA 内存分配与管理 |
ax-ipi | ipi | 处理器间中断管理 |
3. 核心设计机制
3.1 Crates 与 Modules 的边界
ArceOS 文档中 Crates 与 Modules 的区别如下:
components/*中的 crate 偏向通用基础构件,尽量与具体 OS 设计解耦。modules/*则体现 ArceOS 的设计取向,如任务模型、驱动装配方式、文件系统初始化路径等。
分层的收益:
- 更多基础能力可在 StarryOS、AxVisor 等系统中复用。
- OS 语义集中在
modules/*和api/*,降低 API 污染。 - 能力启用由 Cargo feature 控制,而非运行时动态决策。
3.2 Feature 驱动的系统装配
ArceOS 的装配逻辑分布在应用依赖、ax-std/ax-feat feature 以及 ax-runtime 的 feature 依赖图中。
一个很典型的例子是 httpserver 示例应用只在依赖里声明:
[dependencies]
ax-std = { workspace = true, features = ["alloc", "multitask", "net"], optional = true }
而 ax-runtime 将这些 feature 继续映射为更底层的模块依赖:
[features]
# 内存
alloc = ["dep:ax-alloc"]
paging = ["dep:ax-mm"]
dma = ["dep:ax-dma"]
# 并发
multitask = ["ax-task/multitask", "dep:ax-sync"]
smp = ["ax-hal/smp"]
tls = ["ax-hal/tls"]
ipi = ["dep:ax-ipi", "ax-hal/ipi"]
# 中断与时间
irq = ["ax-hal/irq"]
rtc = ["ax-hal/rtc"]
# 虚拟化
hv = ["ax-hal/hv", "ax-alloc/hv"]
# 平台
plat-dyn = ["ax-hal/plat-dyn"]
ax-driver = ["dep:ax-driver"]
# 文件系统
fs = ["ax-driver", "dep:ax-fs"]
fs-ng = ["ax-driver", "dep:ax-fs-ng"]
# 网络
net = ["ax-driver", "dep:ax-net"]
net-ng = ["ax-driver", "dep:ax-net-ng"]
vsock = ["dep:ax-net", "dep:ax-net-ng"]
# 显示与输入
display = ["ax-driver", "dep:ax-display"]
input = ["ax-driver", "dep:ax-input"]
这意味着对开发者而言:ArceOS 的"功能是否存在"本质上是编译期装配问题,而非运行时开关问题。
3.3 API 封装策略
ArceOS 提供三种不同粒度的对外接口:
| 接口层 | 目录 | 适合谁使用 | 特点 |
|---|---|---|---|
ax-api | os/arceos/api/arceos_api | 内核模块、系统软件、需要直接使用 ArceOS 能力的上层系统 | 提供 sys、time、mem、task、fs、net、display 等明确分类的 API |
ax-posix-api | os/arceos/api/arceos_posix_api | 需要 POSIX 风格接口的用户层或兼容层 | 更接近 C / POSIX 习惯 |
ax-std / ax-libc | os/arceos/ulib/* | 应用开发者 | 分别提供 Rust 风格 mini-std 与 libc 风格接口 |
ax-api 的组织方式很直接:按能力域导出稳定函数。例如:
| API 模块 | 典型能力 |
|---|---|
sys | CPU 数、关机 |
time | 单调时间、实时时间 |
mem | 内存分配、DMA 分配 |
task | spawn、sleep、yield、wait queue |
fs | 文件与目录操作 |
net | TCP/UDP socket 与 DNS |
display | 帧缓冲与刷新 |
modules | 在需要时直接回落到具体模块 |
3.4 ax-std 不走 syscall 的原因
ax-std 提供类似 Rust std 的接口,但其实现不是通过 libc 和 syscall,而是直接调用 ArceOS 模块。这带来两个影响:
- 单内核应用调用路径更短,减少中间 ABI 层开销。
- 应用接口与内核能力之间的对应关系更清晰,便于 feature 裁剪和性能分析。
以下时序图展示了 ArceOS 中两条典型的能力调用路径:
分析此图需注意:
ax-std路径偏向应用开发接口。ax-api路径偏向系统软件与内部组件接口。- 两者最终均落到
modules/*和ax-hal,性能瓶颈与行为差异通常在此层。
4. 功能组件与模块
本节从模块总览、交互主线和任务调度模型三个角度介绍 ArceOS 的核心功能组件。
4.1 核心模块总览
以下表格汇总了 ArceOS 各核心模块的目录位置、职责及常见联动对象:
| 组件 | 目录 | 关键职责 | 常见联动对象 |
|---|---|---|---|
ax-runtime | os/arceos/modules/axruntime | 系统主入口、初始化顺序、主核/从核协同 | ax-hal、ax-log、ax-alloc、ax-mm、ax-task、ax-driver |
ax-hal | os/arceos/modules/axhal | CPU、内存、时间、中断、页表、TLS、DTB 等硬件抽象 | 平台 crate、ax-runtime |
ax-alloc | os/arceos/modules/axalloc | 全局堆分配、DMA 相关地址转换 | ax-runtime、ax-mm |
ax-mm | os/arceos/modules/axmm | 地址空间、页表、映射后端 | ax-runtime、上层内存管理逻辑 |
ax-task | os/arceos/modules/axtask | 调度器、任务创建、等待队列、定时器驱动的 sleep | ax-runtime、ax-sync |
ax-sync | os/arceos/modules/axsync | mutex 等同步原语 | ax-task、任意并发模块 |
ax-driver | os/arceos/modules/axdriver | 设备探测与驱动初始化 | ax-fs、ax-net、ax-display |
ax-fs | os/arceos/modules/axfs | 文件系统挂载、文件/目录 API | ax-driver |
ax-net | os/arceos/modules/ax-net | 网络栈、socket 抽象 | ax-driver |
axconfig | os/arceos/modules/axconfig | 构建期常量与目标参数 | 所有模块 |
ax-log | os/arceos/modules/axlog | 多级日志与格式化输出 | 所有模块 |
ax-fs-ng | os/arceos/modules/axfs-ng | 下一代文件系统(FAT、ext4,LRU 缓存) | ax-driver |
ax-net-ng | os/arceos/modules/axnet-ng | 下一代网络栈(异步感知,基于 starry-smoltcp) | ax-driver |
ax-dma | os/arceos/modules/axdma | DMA 内存分配与管理 | ax-runtime、ax-mm |
ax-ipi | os/arceos/modules/axipi | 处理器间中断管理 | ax-hal |
ax-input | os/arceos/modules/axinput | 输入设备管理与事件分发 | ax-driver |
4.2 模块交互
ArceOS 的模块间交互可归纳为四条主线,覆盖从系统启动到应用调用的完整数据与控制流:
-
启动主线
ax-runtime -> ax-hal -> ax-alloc/ax-mm -> ax-task -> ax-driver -> ax-fs/ax-net -
API 主线
ax-std/arceos_api -> ax-task/ax-fs/ax-net/... -> ax-hal -
平台主线
axplat-* / platform/* -> ax-hal -> ax-runtime -
测试主线
examples/* / test-suit/* -> ax-std or ax-api -> modules/*
4.3 任务与调度模型
ax-task 是 ArceOS 并发模型的核心,其设计有几个值得注意的点:
multitask打开前后,模块会走完全不同的实现路径。- 调度 算法由
sched-fifo、sched-rr、sched-cfs等 feature 选择。 - 如果启用了
irq,sleep、定时等待和 timer tick 才能利用中断驱动;否则很多时间相关行为只能退化为更朴素的实现。
下面的状态图可以帮助你理解大部分任务 API 最终如何影响调度状态:
这张图适合用来判断:
- 一个“卡住”的任务更可能是在
Blocked等待某个唤醒事件,还是根本没有被放进Ready队列。 - 一个调度问题究竟是“没有启用正确 scheduler feature”,还是“唤醒条件没有成立”。
5. 关键执行流程
本节描述 ArceOS 从引导入口到应用运行的启动初始化流程、Feature 装配对启动路径的影响,以及从应用入口到模块能力的典型调用链。
5.1 系统启动与运行时初始化
ArceOS 的主入口位于 ax_runtime::rust_main(),从平台引导代码跳入后,按固定顺序建立运行时环境。
此流程中有几个需注意的要点:
ax-hal::init_early()与ax-hal::init_later()分两阶段执行,平台初始化并非一次性完成。- 文件系统、网络、显示等服务依赖
ax-driver::init_drivers()的探测结果,而非自行初始 化。 main()被调用前,调度器、中断、构造器可能已完成初始化,应用拿到的是"已具备最小运行时"的环境。
5.2 Feature 装配对启动路径的影响
启动流程虽固定,但每一步是否执行取决于 feature 是否启用:
- 没有
alloc,就不会初始化全局堆。 - 没有
paging,就不会进入ax-mm::init_memory_management()。 - 没有
multitask,则不会初始化调度器,main()返回后会直接system_off()。 - 没有
fs、net、display,相应的驱动初始化与子系统初始化也不会发生。
这也是定位问题时应优先检查 Cargo feature,而非先怀疑运行时分支的原因。
5.3 从应用入口到模块能力的调用链
最小 Hello World 示例如下:
#![cfg_attr(feature = "ax-std", no_std)]
#![cfg_attr(feature = "ax-std", no_main)]
#[cfg(feature = "ax-std")]
use ax_std::println;
#[cfg_attr(feature = "ax-std", unsafe(no_mangle))]
fn main() {
println!("Hello, world!");
}
但此示例已隐含以下事实:
- 应用必须通过
ax-std或其他用户接口接入 ArceOS 运行时。 println!最终落到控制台输出能力,由ax-hal的平台控制台接口承接。- 若替换为
httpserver示例,则额外要求alloc、multitask、net三类 feature,网络栈与任务系统随之装配进镜像。