StarryOS 开发指南
StarryOS 是构建在 ArceOS 模块层之上的 Linux 兼容操作系统。本文档面向在 TGOSKits 工作区内进行 StarryOS 相关开发的场景,覆盖开发环境、内核开发规范、Syscall 开发流程、用户态程序开发、rootfs 管理、测试策略、调试技巧和多架构注意事项。
架构分层、syscall 分发和进程模型见 StarryOS 架构。 最短命令和快速启动见 快速开始。 构建系统总览见 构建与运行。
1. 开发环境
1.1 工具链
StarryOS 共享 TGOSKits 工作区的统一工具链(nightly-2026-07-15),无需额外配置。详见 ArceOS 开发指南 → 开发环境。
1.2 QEMU
StarryOS 需要更多内存(推荐 ≥ 512M)和可能的网络/块设备:
# 基本验证
cargo xtask starry qemu --arch riscv64
# aarch64
cargo xtask starry qemu --arch aarch64
1.3 交叉编译工具链(用户态程序开发)
开发用户态测试程序时需要交叉编译器:
| 架构 | 工具链包 | 前缀 |
|---|---|---|
| aarch64 | gcc-aarch64-linux-gnu | aarch64-linux-gnu-gcc |
| riscv64 | gcc-riscv64-linux-gnu | riscv64-linux-gnu-gcc |
安装示例:
sudo apt install gcc-aarch64-linux-gnu gcc-riscv64-linux-gnu
如果使用 musl 静态链接:
# 安装 musl 交叉工具链
sudo apt install musl-tools
# 或使用 musl-cross-make 获取交叉版本
2. 目录结构总览
os/StarryOS/
├── starryos/ # StarryOS 启动包
│ ├── Cargo.toml # 包级 feature:qemu, smp, rknpu
│ └── src/
│ └── main.rs # 入口
├── kernel/ # StarryOS 内核(starry-kernel)
│ ├── Cargo.toml # 内核 feature:memtrack, input, vsock, rknpu
│ └── src/
│ ├── entry.rs # 初始进程创建,加载 /bin/sh
│ ├── lib.rs # crate root
│ ├── config/ # 内核配置
│ ├── file/ # 文件描述符表、文件操作
│ ├── mm/ # 内存管理、用户地址空间、ELF 加载
│ ├── pseudofs/ # 伪文件系统(devfs, procfs 等)
│ ├── syscall/ # Syscall 完整实现
│ │ ├── mod.rs # Syscall 分发
│ │ ├── fs/ # 文件系统相关 syscall
│ │ ├── task/ # 进程/线程相关 syscall
│ │ ├── mm/ # 内存管理相关 syscall
│ │ ├── net/ # 网络 socket syscall
│ │ ├── signal/ # 信号相关 syscall
│ │ ├── sync/ # futex、mutex、信号量
│ │ ├── ipc/ # pipe、shm、消息队列
│ │ ├── io_mpx/ # epoll、poll、select
│ │ ├── time/ # 时间相关 syscall
│ │ ├── resources/ # rlimit、prctl、getcpu
│ │ └── sys/ # uname、sysinfo、getpid 等
│ ├── task/ # 线程/进程数据、futex、信号、凭证
│ ├── time.rs # 时间管理
│ └── trap.rs # Trap/异常处理
└── Makefile # 构建 rootfs 和运行
StarryOS 专用组件(位于 components/):
| 组件 | 版本 | 职责 |
|---|---|---|
starry-process | v0.4.5 | 进程生命周期、父子关系、进程组、会话 |
starry-signal | v0.6.0 | 信号投递、信号处理、架构相关信号帧 |
starry-vm | v0.5.6 | 用户地址空间管理、虚拟内存抽象 |
3. Feature 配置
3.1 启动包 Feature(starryos/Cargo.toml)
| Feature | 说明 |
|---|---|
qemu | 启用默认平台、PCI 总线、显示、输入、vsock、网络 |
smp | 多核支持 |
rknpu | Rockchip NPU 驱动支持 |
3.2 内核 Feature(kernel/Cargo.toml)
| Feature | 说明 |
|---|---|
dev-log | 开发日志 |
input | 输入设备支持 |
memtrack | 内存追踪(gimli-based) |
rknpu | Rockchip NPU 驱动 |
vsock | VSOCK 支持 |
内核默认启用:fp-simd, irq, uspace, multitask, task-ext, sched-rr, rtc, ext4, net。
3.3 KCOV 暂不引入
StarryOS 目前不暴露 kcov feature,也不注册 /dev/kcov。此前尝试引入 Linux KCOV 兼容接口时,需要同时改动编译插桩参数、ax-hal 架构 trampoline、文件描述符状态、设备 mmap、任务生命周期和测试矩阵,侵入面过大。
另一个阻塞点是多核语义:KCOV 的 per-fd / per-task 状态需要和调度、抢占、线程退出、fork 以及中断上下文保持一致,当前实现还不能稳定覆盖 SMP 场景。因此在形成更小的边界和可靠的多核方案前,暂不把 KCOV 纳入 StarryOS。
4. Syscall 开发
4.1 Syscall 分发机制
Syscall 入口在 kernel/src/syscall/mod.rs 的 handle_syscall() 函数:
pub fn handle_syscall(uctx: &mut UserContext) {
let Some(sysno) = Sysno::new(uctx.sysno()) else { ... };
let result = match sysno {
Sysno::ioctl => sys_ioctl(uctx.arg0(), uctx.arg1(), uctx.arg2()),
Sysno::chdir => sys_chdir(uctx.arg0()),
// ... 数百个 syscall
};
}
Sysno 枚举来自 syscalls crate,覆盖 Linux 标准系统调用号。
4.2 添加新 Syscall 完整流程
以添加 sys_mycall 为例:
步骤 1:在分发函数中添加 match arm
编辑 kernel/src/syscall/mod.rs:
Sysno::mycall => sys_mycall(uctx.arg0(), uctx.arg1()),
如果
Sysno枚举中尚无此 syscall 号,需更新syscallscrate 或手动定义。
步骤 2:选择合适的子模块实现
根据 syscall 功能类别放入对应子模块:
| 类别 | 文件位置 | 典型 syscall |
|---|---|---|
| 文件操作 | syscall/fs/ | open, read, write, ioctl, stat |
| 进程/线程 | syscall/task/ | clone, execve, exit, wait4 |
| 内存管理 | syscall/mm/ | mmap, mprotect, munmap, brk |
| 网络 | syscall/net/ | socket, bind, listen, accept |
| 信号 | syscall/signal/ | sigaction, sigprocmask, kill |
| 同步 | syscall/sync/ | futex, mutex |
| IPC | syscall/ipc/ | pipe, shmget, msgsnd |
| I/O 多路复用 | syscall/io_mpx/ | epoll_create, poll, select |
| 时间 | syscall/time/ | clock_gettime, nanosleep |
| 资源/系统 | syscall/resources/ | getrlimit, prctl, getcpu |
| 系统信息 | syscall/sys/ | uname, sysinfo, getpid |
步骤 3:实现 syscall 函数
// 例:在 syscall/fs/mycall.rs 中
pub fn sys_mycall(arg0: usize, arg1: usize) -> isize {
// 参数解析和安全性检查
// 实现逻辑
// 返回值:0 表示成功,负数表示错误(-errno)
0
}
步骤 4:准备用户态测试程序
编写最小 C 程序触发新 syscall:
// test_mycall.c
#include <stdio.h>
#include <unistd.h>
#include <sys/syscall.h>
long mycall(int arg0, int arg1) {
return syscall(SYS_mycall, arg0, arg1);
}
int main() {
long ret = mycall(1, 2);
printf("mycall returned: %ld\n", ret);
return 0;
}
交叉编译并放入 rootfs:
# aarch64
aarch64-linux-gnu-gcc -static -o test_mycall test_mycall.c
# riscv64
riscv64-linux-gnu-gcc -static -o test_mycall test_mycall.c
步骤 5:启动验证
cargo xtask starry rootfs --arch riscv64
cargo xtask starry qemu --arch riscv64
在 StarryOS shell 中运行测试程序。
步骤 6:添加到 test-suit
将测试程序加入 test-suit/starryos/ 对应目录,编写配置文件。
4.3 Syscall 实现注意事项
- 参数安全性:所有来自用户空间的指针必须验证可访问性,使用
UserPtr或手动copy_from_user/copy_to_user - 错误返回:使用负数返回
-errno,而非设置errno全局变量 - 锁使用:内核代码运行在 IRQ 上下文时注意锁的使用,参考
kspin组件 - 与 Linux 对齐:参考 Linux 内核对应 syscall 的行为和边界条件,注意
man 2 <syscall>中的错误情况
5. 进程与信号开发
5.1 进程管理(starry-process)
进程相关的核心数据结构:
Process:进程结构体,管理地址空间、文件描述符表、子进程列表ProcessGroup:进程组,支持信号组播Session:会话,管理控制终端
开发流程:
- 在
components/starry-process/src/中修改进程数据结构或逻辑 - 在
kernel/src/task/中调整与内核的集成 - 通过
clone/execve/exit等 syscall 路径验证