Skip to content

第二十五周工作总结

概述

本周完成了 rt-async-amp 双核 AMP(非对称多处理)项目的整体搭建与 IPC 通信链路打通。项目在 QEMU virt RISC-V 64 平台上实现了 StarryOS(S-mode, hart 0)+ rt-async(M-mode, hart 1) 的双核异构架构,包含完整的启动链路、共享内存 IPC、事件驱动中断通知机制。

本项目参考了之前的 embassy_preempt_VisionFive2 方案,在项目架构和实现方式上做了系统性改进。

项目架构

硬件平台

旧项目 (VisionFive2)新项目 (rt-async-amp)
平台JH7110 异构五核 (1×S7 + 4×U74)QEMU virt 双核
RTOS 核心S7 (RV64IMAC, 无 CAS, 小缓存)标准 riscv64 核心
OS 核心U74×4 (RV64GC)标准 riscv64 核心
实时侧特权级S-modeM-mode(零开销中断)

与旧项目的对比改进

1. 项目架构:从松散拼接到统一构建

旧项目:embassy_preempt、StarryOS、OpenSBI、U-Boot 各自独立仓库,通过顶层 Makefile 串联编译。配置常量(地址、大小)分散在各子项目中手动维护,容易出现不一致。

新项目

  • amp.toml 作为 single source of truth,集中管理所有物理地址、内存布局、ioctl 编号等常量
  • xtask 构建工具读取 amp.toml,自动生成 Rust 代码(amp_gen.rs)和 OpenSBI patch 模板替换
  • 确保所有组件(rt-async、StarryOS、用户态程序)的配置始终一致

2. RTOS 实现:从回调式到纯 async/await

旧项目 (embassy_preempt):

  • 任务定义为 fn task(args: *mut c_void),同步任务用函数指针,异步任务通过状态机
  • 调度基于手动上下文切换(IntCtxSW),任务通过 TCB(Task Control Block)管理
  • IPI 等待通过 IpiWaitList(固定 4 槽位数组)+ 回调 ipi_callback 实现
  • 平台耦合:executor 直接引用 GlobalSyncExecutorOS_TCB_REF 等全局状态

新项目 (rt-async):

  • 任务定义为 async fn,通过 #[executor::task] 宏自动转换为 SpawnToken
  • 调度基于 Rust Future 机制 + 优先级抢占,无需手动上下文切换
  • 平台抽象:Chip trait + TimerChip trait + extern_trait 零成本抽象,executor 不依赖具体硬件
  • 用户态级别的 WaitForMessage Future 直接检查共享内存,不需要 executor 内部的 wait list

3. IPC 模型:从 wake_all 到精确通知

旧项目

rust
// ipi_callback — 中断中唤醒所有等待任务
fn ipi_callback(_ctx: *mut ()) {
    IPI_WAIT_LIST.wake_all();           // 唤醒所有等待者,不区分是否有数据
    GlobalSyncExecutor().IntCtxSW();    // 手动触发上下文切换
}
  • IPI 到来时 wake_all() 唤醒所有等待任务,不检查是否有真实数据
  • 最多支持 4 个任务同时等待
  • 任务引用通过裸指针管理,需要手动生命周期

新项目

rust
// notify_from_isr — 中断中检查共享内存后精确唤醒
pub fn notify_from_isr() {
    if !intercom::has_pending() { return; }  // 无数据则不唤醒
    // ... wake registered waker
}

// task_ipc — 两行循环完成整个 IPC 处理
loop {
    WaitForMessage.await;
    while process_pending() {}
}
  • ISR 中检查共享内存 has_pending(),仅在真实数据存在时唤醒,零伪唤醒
  • 基于 Rust 标准 Waker 机制,无固定槽位限制
  • 全关中断保护 waker 注册,无竞态

4. IPC 协议:从原始共享内存到结构化 RPC

旧项目:通过 intercom 模块手动读写共享内存,无结构化协议。

新项目

  • ov-channels:无锁双通道共享内存 ring buffer(SQ/CQ 模型)
  • ov-rpc:基于共享内存的 RPC 框架,define_service! 宏定义服务接口
  • 用户态通过 /dev/rt_shm 设备 mmap 共享内存 + ioctl 发送/等待 IPI
  • rt-async 侧通过 process_one() 逐条处理,支持 RPC 和通知两种消息类型

5. 内存安全与正确性

新项目增加的保障

  • 双向 IPI 发送前均有 fence(Release) 保证共享内存写入对端 hart 可见
  • mmap 长度从 align_down 改为 align_up,修复非页对齐 device region 映射截断 bug
  • SHMSIZE 页对齐(67072 → 69632),跨组件通过 amp.toml 自动同步
  • StarryOS CLINT 映射通过 axconfig.tomlmmio-ranges 显式声明,不依赖 OpenSBI patch 的隐式映射

核心工作详述

OpenSBI AMP hart 路由

fw_base.S_start 中添加 hart 路由逻辑:hart 1 直接跳转 rt-async 入口(0x82800000),跳过 OpenSBI 初始化,以 M-mode 运行。hart 0 走正常 OpenSBI → StarryOS 流程。

WaitForMessage Future

ipc_wait.rs 实现事件驱动 IPC 等待:

  • WaitForMessage 是 zero-size Future,poll 时检查共享内存 has_pending()
  • 无数据:关中断 → 注册 waker → 二次检查 → 开中断 → Pending
  • notify_from_isr() 仅在 has_pending() 为 true 时 wake waker

executor-macro 中断分发

__Inner_MachineSoft 移到 MachineSoft ISR 开头(clear_pend 之前),使得 notify_from_isr() → wake → pend → 同一次中断内调度执行。

StarryOS 侧

  • rt_shm 设备提供 /dev/rt_shm,支持 mmap(共享内存)、ioctl(NOTIFY/AWAIT/CLR_PENDING)
  • send_ipi_to_rt_async() 直接写 CLINT MSIP1 + fence(Release)(低延迟路径)
  • ipi_irq_handler() 接收 hart 1 的 IPI,清除 SSIP,通知用户态