项目简介
TranquilOS 是面向 AArch64 的 object-capability 微内核操作系统。系统以 capability 作为统一授权模型,将进程管理、内存管理、IPC 命名空间、设备抽象、文件系统、网络协议栈、窗口合成与应用生命周期拆分为边界清晰的用户态服务——硬件驱动同样以独立进程(driver daemons)运行,由 devmgr 注册表按类转发;EL1 微内核专注于调度、IPC、异常、中断、定时器、futex、基础驱动与 capability 对象分发。
设计参考了 seL4 等内核的对象能力模型,目标是在 AArch64 平台上验证「微内核 + capability 授权 + 用户态系统服务」的系统化组合:内核对象如何被显式授权、服务如何发现与通信、图形桌面如何作为普通用户态组件运行、构建系统如何把分散组件组装为可启动镜像。
完整设计文档在内核仓库 docs/ 目录:basic_theory.md(AArch64 架构、MMU、上下文切换、驱动、capability、IPC、调度)、microkernel_design.md(微内核设计)、idl.md(接口定义与代码生成)、async_ipc_design.md。
快速开始
前置条件:从 newos.org/toolchains 下载交叉工具链并解压到仓库 toolchains/;macOS 需要 brew install e2fsprogs(组装 ext2 system.img)。env_setup.sh 必须在每个新 shell 中 source,其中 OS_BASE_DIR 硬编码为 ~/kernel,仓库检出到其他路径时先修改。
# QemuVirt(主要开发平台):构建 + 组装镜像 + 启动 QEMU
source env_setup.sh && ./run_qemu_virt.sh
# 手动构建
source env_setup.sh
gn gen out --args='platform="QemuVirt"'
ninja -C out
# 单目标构建
ninja -C out Windowmgr
QEMU 配置:4 核 SMP、2G 内存、macOS 上 HVF 硬件加速、ramfb 显示、VirtIO tablet/keyboard/network/block/sound。其他平台:run_qemu_pi3b.sh(headless 串口)、run_qemu_pi4b.sh(SD 卡镜像)、run_board_cm4.sh(真机,经 rpiboot 刷写)。
仓库结构
sys/ 系统基础(TCB)
kernel/ 微内核(EL1)
virt/ Type-1 hypervisor(EL2)
boot/ Bootloader
trustee/ 可信执行环境(stub)
uapps/ 启动与核心服务:base/ init、idle;core/ devmgr、fsmgr、drivers/(driver_mgr IDL)
ulibs/ libc、libcrt、libsyscall、libsystem、libsync、libfdt、libalgorithm
os/ OS 用户态
base/ zygote、netmgr
framework/ windowmgr、mmimgr、appmgr、audiomgr、fontmgr、statemgr 等
apps/ 用户应用
libs/ libwindow、libgraphics、libgl、liblvgl、liblwip 等
thrid_party/ lvgl、freetype、mbedtls、lwip、musl 等三方源码
platform/ 平台配置:QemuVirt / Pi3b / Pi4b / CM4(DTB、链接脚本、脚本;vendor/ 驱动 daemon 与 drivers.json)
build/ GN 构建系统与工具链定义
images/ ramdisk(cpio)、vendor 与 system 镜像模板
docs/ 设计文档
三方库约定:不直接修改上游源码,平台适配与兼容封装集中在 os/libs/ 与 sys/ulibs/;升级三方库时整目录替换并验证适配层。
启动链与权限模型
TranquilOS 把 ARMv8-A 异常级别用作架构边界:EL2 运行可选的 Type-1 hypervisor,EL1 是微内核,EL0 承载 SystemDaemon、框架服务与应用。bootloader 根据 CPU CurrentEL 决定启动路径:
从 EL2 启动:bootloader → hypervisor → kernel → systemd
从 EL1 启动:bootloader → kernel → systemd
hypervisor 提供 stage-2 地址转换、VM/VCPU/PCPU 生命周期管理、vGIC、vTimer、vPMU 与 hypcall 接口;虚拟机与内核一同打包进 boot.img。
用户态启动顺序:init(首个用户态进程)解析设备树找到 ramdisk,拉起 devmgr 与 fsmgr,执行 /root/etc/init.rc——其中 exec 行以显式 linear-map 三元组拉起启动关键的 block 驱动 daemon;zygote 读取 init.json,把服务 ELF 从 ext2 载入 SHM 后调 start_process_from_shm() 启动框架服务,并读取 vendor 分区的 drivers.json 拉起其余驱动 daemons;appmgr 按 applist.json 管理应用注册表并按需拉起应用。
Capability 系统
capability 是内核对象与细粒度权限的统一管理结构,也是用户态与微内核交互的统一方式。用户态对内核的所有操作可归结为「对某个内核对象执行某个方法」:OS_{Type}{Method}(ref, args...)——权限因此可以细化到每个对象、每个方法。
每个进程拥有 CNode 保存其全部 capability。CNode 由 directory array 构成:兼具数组索引的速度与动态数组的扩展性,扩展时不拷贝、保持线性索引。capability 引用(cref)为 64 位:高 32 位是 cnode ID,低 32 位是 slot 索引;根 CNode ID 为 1。方法分发前内核校验对象类型与 32 位 rights mask。
内核对象类型包括:VSpace(虚拟地址空间)、CNode(capability 存储)、SContext / XContext(调度 / 执行状态)、IPC Endpoint / Pool、Timer、Futex、IRQ、Console。
内存管理
内核只保留 boot allocator,为内核启动阶段与 SystemDaemon 运行分配内存;全部内存策略都在用户态。SystemDaemon 的 memmgr 以 buddy 分配器管理物理页,并管理进程的虚拟地址空间与 SHM 共享内存。
内核侧覆盖 AArch64 MMU 的完整配置:MAIR/TCR、block/table 描述符、identity map、ASID 与 TLB 管理;VSpace 对象代表一个进程的地址空间,经 capability 调用操作。
IPC 模型
传统内核的进程间同步(socket、pipe、共享内核缓冲)响应依赖调度器行为,延迟不确定。TranquilOS 提供控制流立即切换的迁移线程 IPC:client 发起同步调用时,内核把 server 地址空间与一个构造好的 execute_context_s 装上 CPU——参数按 AAPCS 放入 x0–x7,接口函数地址放入 pc;lr 中放入跳板函数地址,接口返回时跳板发起 REPLY 调用切回 client。调度元数据全程由调度器独立控制,IPC 不影响调度公平性。
- IPC Endpoint:单线程模型,一个 handler 线程服务一个端点。
- Endpoint Pool:在预分配的多个端点间负载均衡,支撑多线程服务;其上构建弹性 IPC。
- Upcall:内核 → 用户态的反向调用,用于系统调用转发、页错误等事件。
- Name service:内核端点 cref
0x1。服务以sys_register_service()/sys_register_service_pool()注册,客户端以sys_get_service()/sys_get_service_pool()查找。
调度器
传统 TCB 被拆分为执行实体 execute_context_s(x0–x30、sp、pc、pstate 等寄存器状态)与调度实体 schedule_context_s(优先级、时间片、队列节点、CPU 亲和性)。per-CPU 调度器只操作调度元数据,真正切换上下文时才构造 / 恢复执行状态——这也让迁移线程 IPC 的实现大为简化。
SMP 下每个 CPU 有独立本地调度器并做跨核负载均衡,支持抢占。CFS 调度类以可加载内核模块实现(sys/kernel/module/),验证模块系统的真实可用性。
系统调用路径
系统调用号在 x8 中,按标识位走三条分发路径:
| 路径 | 标识位 | 用途 |
|---|---|---|
| Capability call | CAP_CALL_MASK | 路由到 capability 对象:VSpace、CNode、IPC endpoint、Timer 等,capcall 是微内核的主要系统调用 |
| Fast call | FAST_CALL_MASK | 内核内联的高性能调用(当前为 stub) |
| Compact syscall | — | Linux 兼容表(目前仅 getpid);其余经 upcall 转交进程注册的用户态 handler(libsyscall 函数表分发) |
initcall 初始化
初始化函数经宏放入专用 ELF 段,链接脚本为每级定义起止符号,initcall_run(level) 按 LV0 → LV7 顺序执行:
| LV | 宏 | 用途 |
|---|---|---|
| 0 | early_device_init | 最早期设备初始化 |
| 1 | early_device_percpu_init | per-CPU 早期设备 |
| 2 | key_device_init | 关键设备 |
| 3 | key_device_percpu_init | per-CPU 关键设备 |
| 4 | normal_device_init | 常规设备 |
| 5 | normal_device_percpu_init | per-CPU 常规设备 |
| 6 | module_init | 内核模块 |
| 7 | module_percpu_init | per-CPU 模块初始化 |
SystemDaemon
SystemDaemon 运行在 EL0,是最高特权的用户态进程,链接在 0x43080000,直接发起 capcall(libkernel/capcall.h)而不经 libsyscall。传统内核中的高层资源管理由它承担,各组件以单例对象管理以约束接口暴露:
- procmgr:进程 / 线程生命周期,ELF 装载(spawn、exit、PID 查找)
- memmgr:物理页分配、SHM 共享内存管理
- ipcmgr:IPC endpoint / pool 创建、name service、capability 克隆
- virtmgr:虚拟机管理
对外通过 systemd_client.c 暴露 17 个 IPC 方法,数据传递走 SHM。vfs、devmgr 等核心服务也由它拉起。
框架服务模式
每个 OS 服务(os/framework/* 与 sys/uapps/core/*)遵循相同结构:
main.c 初始化、经 IPC 注册服务、事件循环
service/service.c 按方法号分发的 IPC handler 表,调用内部处理函数
client/ 薄 IPC 客户端封装,用 SHM 传数据
include/ 服务内部头文件
client/include/ 公开客户端 API 头文件
分发模式在所有服务中一致:handler 函数指针表按方法号索引,service_entry 校验方法号后调用对应 handler 并以 OSIpcEndPointPoolReply() 应答;启动时以 sys_register_service_pool(IPC_SERVICE_ID_*, &service_entry) 注册。
SHM 数据传递
进程间所有数据传输都使用共享内存,这是唯一的数据通道——没有消息拷贝式 IPC。通用流程:
- 客户端经
systemd->ops.alloc_shm()申请 SHM - 映射并写入数据
- 发起 IPC 调用,SHM 句柄作为参数传递
- 服务端经
systemd->ops.get_shm()映射同一块 SHM - 直接处理共享数据(零拷贝)
- 应答;客户端释放 SHM
服务清单
| 服务 | 职责 |
|---|---|
| appmgr | 应用生命周期:注册表、按需拉起 |
| windowmgr | 窗口合成器与 surface 管理、输入分发 |
| statemgr | 系统级 KV 状态存储 |
| devmgr | 驱动 daemon 注册表与按类 IPC 转发;外设管理 |
| fsmgr | 文件系统抽象:rootfs、ext2、FAT32、procfs、sysfs |
| netmgr | lwIP TCP/IP 网络栈 |
| mmimgr | 多模态输入管理 |
| audiomgr | 音频服务 |
| fontmgr | FreeType 字体渲染 |
| agentmgr | AI agent 框架 |
| timemgr | 计时、RTC 闹钟、NTP 同步 |
| imemgr | 输入法编辑器 |
IDL 与代码生成
服务用 .idl 文件描述同步 IPC 接口,生成器(tools/idl_gen.py,通常由 GN 构建任务自动调用)产出五个文件:<service>_types.h、<service>_client.h/.c、<service>_service.h/.c。
service statemgr_ipc {
id = 0x9;
struct query { version = 1; char key[64]; };
struct result { version = 1; uint32_t found; };
uint64_t get(in query *request,
out result *response) id = 0x1;
};
参数方向控制生成代码的拷贝行为:in IPC 前复制进 SHM,out IPC 前清空、IPC 后复制回,inout 两者兼有(未标注的结构体指针默认 inout);标量直接走 IPC 参数槽,每方法最多三个参数。
服务端接收缓冲区:结构体指针使用服务端持有的固定缓冲区。首次调用按「调用方 + 方法 + 参数槽」建立 SHM 授权;客户端保存连接级 CRef 与映射地址,后续调用直接复用。每个方法用独立锁覆盖输入复制、IPC 与输出复制;变长或调用方持有的大块数据仍显式传 SHM 句柄与长度。
传输与映射:默认经 endpoint pool IPC、经 SystemDaemon 映射 SHM;可用服务属性切换 transport = endpoint、mapping = direct。
ABI 规则:传输结构体必须声明 version > 0;生成器附加 abi_size / abi_version 字段,服务端在调用处理函数前校验。传输结构体不允许指针字段(指针只在所属进程地址空间有效)。完整语法见 tools/idl_ref/tranquil_idl.ebnf。
GN 构建目标
| 目标类型 | 用途 |
|---|---|
executable() | ELF:kernel、SystemDaemon、框架服务、应用 |
source_set() | 编译进每个使用者的库(不产出独立 .a) |
group() | 依赖打包的元目标(如 uapp_runtime) |
config() | 编译 / 链接标志包,经 configs += 应用 |
每个 executable 链接平台专用链接脚本(platform/$PLATFORM/linker/*.lds),用户态可执行文件用 libcrt/uapp.lds,且必须把 libcrt/start.S(提供 _start)列为首个源文件。常用依赖组://sys/ulibs:uapp_runtime、uapp_runtime_with_syscall、//sys/ulibs/libsystem:systemd_client。
平台与镜像
| 平台 | 定位 | 说明 |
|---|---|---|
| QemuVirt | 主要开发平台 | 设备组合最完整(ramfb、VirtIO 全家桶),内核改动先在此验证 |
| Pi3B(QEMU) | 平台验证 | -nographic 串口,headless |
| Pi4B(QEMU) | 平台验证 | MBR 分区 SD 卡镜像(mkpiimg.sh) |
| CM4 | 真实硬件 | 经 rpiboot USB 刷写,需实体底板 |
boot.img (64MB)
offset 0 Bootloader 8MB
offset 2048 DTB 8MB
offset 4096 Hypervisor 16MB
offset 8192 Kernel 16MB
offset 12288 SystemDaemon 8MB
offset 14336 Ramdisk cpio 8MB
vendor.img (32MB, ext2, P2)
bin/ driver daemons (.drv)
etc/ drivers.json
system.img (128MB, ext2)
bin/ framework services
apps/ user applications
etc/ fonts · icons · init config