项目介绍
k3x-HERA-RT 是面向 K3/K3x 芯片的 AI 运行时与实时调度项目。
项目目标是把 X100、A100、CPU fallback、IME、DMA、TCM 和实时控制路径统一看成一个异构计算系统。我们希望在这个系统上打造一套更贴近 K3x 硬件形态的 AI 算力运行通道,让 CPU 与 AI 算力之间可以按任务规模、核心负载、数据依赖和实时性要求动态分配工作。
项目目标
- 构建一套纯异构 AI 算力运行体系,使 X100、A100 和 CPU fallback 都能作为可调度计算资源参与推理。
- 建立用户态算子库,把 MatMul、RMSNorm、RoPE、Softmax 等算子转换成可选 backend candidate。
- 建立内核侧调度器,让内核不理解具体算子语义,只根据 DAG 依赖、backend candidate、队列状态和资源状态选择执行位置。
- 支持 CPU 与 AI 算力之间的负载均衡:小任务优先留在 X100 本地路径或 CPU,本地超限时转 A100;A100 拥塞时可回退到等价 X100/CPU backend。
- 保持实时控制路径隔离,避免 AI 推理、缺页、fallback 或高负载调度影响 RT24/CAN 等实时任务。
核心思路
项目分为用户态算子库和内核调度器两层。
用户态算子库负责理解算子语义。它知道一个算子是什么、有哪些输入输出、有哪些 dtype/layout/quant 限制,也知道这个算子可以由哪些 backend 实现。例如同一个 mul_mat 可能有 A100 IME backend、X100 IME/RVV backend 和 CPU fallback backend。
内核调度器不承接具体算子结构,也不判断某个 node 是 MatMul 还是 RoPE。用户态会先把算子图 lower 成 opaque DAG,内核只看到 node 依赖、backend candidate、buffer handle、优先级和资源提示。
术语和补充说明见特别说明和信息。
负载均衡方向
不同场景下,最优选择可能不同:
- 小算子或单进程低负载场景,用户态 DirectInline 执行可能延迟最低。
- 大矩阵乘法、长 DAG、多核心高负载场景,KernelScheduled 更容易利用多个 X100/A100 核心。
- X100 本地路径适合小 tensor、RVV/IME 轻量计算和低提交开销任务。
- A100 路径适合更大的 tensor/vector 计算和更重的 LLM 核心算子。
- CPU fallback 负责正确性兜底、异常降级和不支持算子的兼容执行。
阶段三通过 benchmark 明确这些边界,包括 DirectInline 与 KernelScheduled 的延迟边界、多核心吞吐、多进程竞争、DAG 依赖调度以及 llama.cpp end-to-end 对比。
开发进度
见开发进度
比赛题目分析和相关资料调研
题目理解
本赛题是异步操作系统。我对“异步”的理解是把原本串行、阻塞的执行流拆成多个可以独立推进的分支:当某个分支在等待设备、DMA、AI 计算或 completion 这类长耗时事件时,CPU 不应该空转等待,而应该去推进其他已经就绪的任务,从而提高系统吞吐和实时响应能力。
本项目把这个理解放到 K3/K3x 异构平台上验证。K3 上有 X100、A100、RT 核、DMA、IME 等不同执行资源,存在提交任务后等待硬件完成,不同核心之间传递任务,长耗时 AI 计算不能阻塞实时路径 等问题。因此我第一阶段先做同步/纯线程最小闭环,第二阶段再重点推进驱动异步化和调度异步化:内核可以延迟调度 AI graph,提交方不被长耗时任务阻塞,completion 到达后再唤醒后续执行流。
K3/K3x AI 算力结构分析
根据 K3/K3x 公开资料和官方 AI 文档,平台可以按 X100 cluster 与 A100 cluster 两类计算域理解:
- X100 侧承担通用计算、系统调度、用户态入口和轻量 AI 任务。资料中 X100 core 旁也标出 AI 模块,因此文档中暂称为
X100 local tensor path。 - A100 侧面向重型 AI 计算,包含 Scalar Processor、Vector Processor、Tensor Processor、L2 Cache 和 TCM,更适合大矩阵乘法、LLM 核心算子和长 DAG。
- CPU fallback 用于正确性兜底、异常降级和暂未支持算子的兼容执行。
X100 和 A100 的向量宽度不同,线程一旦使用某类向量/IME 状态,就不能随意跨核心类型迁移。这直接影响系统调度、线程亲和性和上下文保存恢复策略。
资料调研
调研主要围绕以下材料展开:
- SpacemiT AI CPU 与 IME 指令资料:确认 A100 Tensor Processor、Integer Tensor、Float Tensor 和 IME 子扩展能力。
- SpacemiT K3 HMP 文档:确认 Linux 侧通过
/proc/set_ai_thread标记 AI 线程,并约束到 AI 核心集合。 - SpacemiT 交叉编译工具链资料:确认 A100 专用 IME 指令需要官方工具链支持,普通 RISC-V 工具链不足以覆盖扩展指令。
linux-k3公开驱动:检查是否存在在传统/dev/npu或/dev/a100command-submission 风格驱动,避免后期实现时丢失关键信息。- StarryOS/tgoskits: 查看os完成K3板级适配的程度,评估后期工作量.
相关资料入口:
系统框架设计
设计目标
k3x-HERA-RT 中用户态负责把 AI 框架中的算子转换成稳定 UAPI,内核侧只处理 graph、依赖、队列、buffer 映射和 completion,具体算子执行由 backend 根据目标路径完成。
用户库明确知道算子的语义,到了内核中内核只管执行和调度计算任务(内核不懂算子语义,会根据系统负载来调度)
当前总体架构
注意:这里是根据当前初赛阶段的实现程度写的,后期大的变化就是增加复杂的调度路径,整体的执行流程还是这样
模块划分
| 模块 | 职责 |
|---|---|
k3_aiRuntime | 用户态 frontend,提供 tensor 分配、graph 构建、channel 建立、graph 提交和 completion 等待接口 |
k3_aiUabi | 内核和用户态共享的稳定 ABI,定义 AiTensorDesc、AiKernelDesc、AiGraphSubmitEntry、graph blob、算子 attr 和错误类型 |
k3_aiScheduler | 内核侧 graph scheduler,解析 DAG,生成稳定拓扑序,维护 ready queue,驱动 worker 执行 node |
k3_kernel_backend | backend 分发入口,根据 KernelOp 与 AiTargetHint 调用 CPU/X100/A100 对应实现 |
k3_ggml_bridge | 测试版 ggml/llama.cpp bridge,当前将 F32 MatMul 请求转换为 k3_aiRuntime graph 提交 |
k3_test | 最小集成测试,构造 DAG 并提交到 /dev/k3_airunner |
tgoskits 仓库 | StarryOS K3 板级适配、k3_airunner 设备驱动、/proc/set_ai_thread、UFS/GMAC/SDMMC 等板级代码 |
提交流程
- AI 应用可以直接调用
k3_aiRuntimefrontend;测试版 ggml/llama.cpp 接入则先经过k3_ggml_bridge。 TensorManager分配稳定的MAP_SHAREDtensor buffer,并生成AiTensorDesc。GraphManager把算子和依赖关系组织成AiGraphBlob。- 用户态通过
/dev/k3_airunner建立共享 channel,并提交AiGraphSubmitEntry。 - 内核驱动拷贝 graph blob,校验用户 buffer,并把 tensor 映射为内核可访问地址。
k3_aiScheduler将 DAG 解析为稳定拓扑序,送入 worker。- worker 调用
k3_kernel_backend::k3_run_kernel,由 backend 执行 CPU fallback、X100 或 A100 路径。 - graph 完成后,内核通过 channel 回写 completion token,用户态按 token 匹配完成状态。
当前 调度策略
当前阶段:DAG 通过拓扑排序为稳定直链,worker 按 FIFO 执行。后续调度策略会逐步加入:
- 小 tensor、低负载、低提交开销场景优先 直接用户态执行(不进内核) 或 X100 local tensor path。
- 大计算任务、长 DAG、高吞吐任务优先 A100 tensor path。
- A100 拥塞时,尝试将具备等价 backend 的任务卸载到 X100 或 CPU fallback。
- X100 本地路径过载时,尝试将重任务转移到 A100。
- timeout、error、unsupported op 触发 CPU fallback 或错误 completion。
内存与一致性设计
graph blob 在提交后会被内核拷贝为私有数据,避免用户态在提交后修改 graph 语义造成 TOCTOU(用户数据在内核安全检查后进行二次修改) 问题。tensor data 不直接复制,当前通过建立内核到物理内存的映射建立数据通路。
开发进度
演示视频说明
所有阶段的演示视频都基于阶段一改造后的模型推理后端展开。后续阶段不更换演示基础,而是在同一套或可对照的 LLM、YOLO 等推理场景中,分别展示单核心算力限制、静态多核心分配的残留问题、动态负载均衡的改善效果,以及异步 AI 运行时在长时间高强度压力下的稳定性。
阶段一:纯线程最小闭环
| 任务 | 目标 |
|---|---|
| [*] 用户态 frontend 与 ring API | 完成用户态算子结构、最小 UAPI、ring entry 和 uring 用户 API(3 天) |
| [*] 纯线程内核执行路径 | 完成纯线程调度器、核心队列、worker、buffer pin/map/cache 最小路径(3 天) |
| [*] completion 回到用户态 | job/node/graph 完成后能通知用户态等待方(2 天) |
| [*] CPU fallback MatMul | 用 CPU fallback 跑通 MatMul 正确性(2 天) |
| [*] A100/X100 IME probe | 验证 A100/X100 IME backend 的最小执行与结果正确性(2 天) |
| [*] 计划外平台侧适配与驱动补齐 | 原先预期 K3 平台侧适配已有其他人接手,但实际推进中需要临时补齐真板启动、驱动和 V 扩展上下文支持,明显占用了阶段一时间 |
[ ] ggml mul_mat 接入 | llama.cpp 的核心矩阵乘法能走用户态算子库(5 天) |
| [ ] llama.cpp 文本生成跑通 | 改造后的 ggml backend 能跑通一个文本生成模型(5 天) |
阶段一子任务拆分
- 用户态 frontend 与 ring API(3 天)
- 用户态 frontend 小 DAG、算子结构体与调用入口
- 最小 MatMul UAPI / submit struct / ring entry
- graph submit 到 ring
- uring 用户 API
- 纯线程内核执行路径(3 天)
- 用户态 backend 算子库骨架
- 纯线程内核调度器
- 核心队列与 worker
- buffer pin/map/cache 最小路径
- completion 回到用户态(2 天)
- completion ring entry
- token 匹配与错误码返回
- 用户态等待/唤醒 API
- [*] CPU fallback MatMul(2 天)
- CPU fallback MatMul 实现
- [*] MatMul golden case 对比
- A100/X100 IME probe(2 天)
- [*] 使用官方支持文档和工具链编写最小 IME probe
- [*] 验证 A100/X100 IME 执行结果正确性
- 计划外平台侧适配与驱动补齐
- K3 真板启动路径和 rootfs/UFS 启动验证
- UFS 驱动迁移和调试
- RISC-V DMA cache 同步问题定位与补齐
-
/proc/set_ai_threadAI 线程控制接口 - RISC-V V 扩展上下文保存恢复
- V 扩展同线程、跨线程和真板测试
- ggml
mul_mat接入(5 天)- [-] 找到 ggml
mul_matbackend 接入点 - 加入
k3_ggml_bridge测试版,用 C ABI 接收 F32 MatMul 请求 - 将测试版 F32 MatMul 请求转换为阶段一 UAPI graph
- 接入用户态算子库和 graph submit 测试路径
- [-] 接入真实 ggml backend
- 补充 dtype/layout/quant 支持
- 对比 ggml CPU fallback 输出
- [-] 找到 ggml
- llama.cpp 文本生成跑通(5 天)
- 固定模型、prompt 和运行参数
- 跑通文本生成
- 记录 tokens/s、latency 和错误日志
阶段一计划外插入:平台侧适配与驱动补齐
阶段一原本主要计划推进 AI runtime、UAPI、调度器和 backend 闭环。当时预期 K3 平台侧适配、真板启动和基础驱动已有其他人接手,因此这些工作没有放进最初的 AI runtime 开发估算里。
实际推进过程中发现,要验证 K3/K3x AI 算力调度,必须先让 StarryOS 能稳定在 K3 真板上启动,并且要补齐 IME 指令依赖的底层系统能力。这部分成为计划外插入项,耗时明显超出最初预期,主要包括:
- K3 真板启动和 UFS rootfs 路径。
- UFS 驱动迁移、初始化序列调试和真板验证。
- StarryOS RISC-V DMA cache 同步空实现的定位与补齐。
/proc/set_ai_threadAI 线程控制接口和核心亲和性验证。- RISC-V V 扩展上下文保存恢复。
- V 扩展同线程 yield、跨线程隔离和 K3 真板测试。
这部分工作虽然打乱了阶段一原先节奏,但它是后续 A100/X100 IME backend、AI 线程调度和真实硬件测试的前置条件。如果没有这些平台侧基础,AI runtime 只能在 QEMU 或用户态模拟路径中验证,无法证明 K3 真板上的 AI 算力调度链路。
阶段二:内核调度器 async 化与多核心简单调度
| 任务 | 目标 |
|---|---|
| [ ] async 调度器与 completion waker | 将阶段一纯线程调度器改造成 Rust async 调度器,并完成异步 completion 唤醒(4天) |
| [ ] 多 A100/X100 核心队列 | 支持多个 A100 和 X100 核心的独立队列(2 天) |
| [ ] 简单核心选择与 backpressure | 先按空闲状态、队列长度或轮询选择目标核心,并支持基础反压(2 天) |
| [ ] cancel/timeout/reset | 任务取消、超时和错误恢复路径可用(2 天) |
| [ ] Buffer planner 与一次性图提交 | 能规划 buffer 复用/布局转换,并支持一个 graph 一次提交(2 天) |
| [ ] 图返回点与可观测性 | 长 graph 可以嵌入检查点返回用户态,并记录基础调度事件(2 天) |
| [ ] 阶段二演示与性能文档 | 展示多核心简单调度改善效果,同时展示静态分配无法处理后台算力占用的问题(3 天) |
阶段三:负载均衡调度和性能优化
| 任务 | 目标 |
|---|---|
| [ ] ResourceState 采样与 metrics | 汇总 PMU/Trace、队列深度、DMA backlog 和 latency(3 天) |
| [ ] 保守负载均衡规则 | 实现 DirectInline、KernelScheduled、X100 本地优先、X100 -> A100、A100 -> X100 的第一版规则(3 天) |
| [ ] 多 A100 核选择与异常降级 | 根据队列、PMU、DMA backlog 和历史 latency 选择低负载 A100,并支持 timeout/error fallback(2 天) |
| [ ] 双向卸载演示 | 展示 A100 满载溢出卸载到 X100,以及 X100 过载卸载到 A100(2 天) |
| [ ] benchmark 矩阵 | 完成微基准、多核心吞吐、多进程竞争、DAG 依赖和 llama.cpp end-to-end 对比(3 天) |
| [ ] 阶段三稳定性与最终演示 | 完成长时间负压测试、阶段三改善演示和最终比赛合成视频(3 天) |
| [ ] 用户态性能监控工具(如果时间允许) | 时间允许时实现可视化/命令行监控,展示核心负载、队列深度、latency 和模型运行状态(可选) |
比赛过程中的重要进展
1. 完成 K3/K3x AI 算力形态调研
第一阶段确认了 K3/K3x 更适合按异构计算系统设计,而不是按传统外挂 NPU 设计。调研覆盖 X100、A100、IME、Vector、FPU、DMA、TCM、HMP 和官方 ONNX Runtime EP 后端。
2. 建立 AI runtime 与 UAPI 雏形
完成用户态 frontend、tensor desc、kernel desc、graph blob、submit entry 和 completion token 的最小设计。后续将分散在 runtime 中的 ABI 类型拆到独立 k3_aiUabi crate,使用户态和内核态共享同一套接口定义。 因为内核也必须至少懂节点这些语义,所以把二者都用的一些数据结构放在uapi里面,并且添加了版本检查.
3. 打通共享 channel 与内存保活路径
完成 /dev/k3_airunner 的 BUILD_CHANNEL 最小通路。用户态先建立 MAP_SHARED 内存,内核验证并保活该共享区,再通过 ov-channels 发送 graph entry 和 completion。
这一阶段验证了用户态句柄释放后,内核仍能稳定持有共享区引用,为后续无锁队列和异步 completion 打基础。
4. StarryOS 成功在 K3 真板上启动
围绕 K3 COM260 Kit 完成 StarryOS 板级启动路径,重点实现 UFS 驱动,使系统可以从 UFS rootfs 启动到 shell。
UFS 驱动迁移为采用了Spacemit的Linux仓库中的驱动copy + bindgen 寄存器定义 + c2rust 初始翻译 + 手工胶水和调试”的方式完成。该工作解决了比赛环境从 QEMU 走向真板验证的问题,同时节省了大量手工翻译的时间。
5. 实现 AI 线程亲和性控制
根据 K3 HMP 机制,在 StarryOS 中实现 /proc/set_ai_thread 接口。用户态写入 1 后可以把当前线程标记为 AI 线程,并进入 AI 核心集合调度。
注意:目前set_ai_thread接口不支持设置其他线程为ai线程,并且留有写入0取消为ai线程,并且立即将自己调度到core0-7的x100核心. 这时可用的vlen已经变了,如果要做测试请注意! 目前这个接口是开发测试用
这处理 X100/A100 向量宽度不同的问题,避免使用某类向量状态的线程被随意迁移到另一类核心。
6. 补齐 RISC-V V 扩展上下文保存恢复
在 StarryOS 任务上下文中补齐 V 扩展状态保存恢复,包括 32 个 vector register group 和相关 CSR 状态。由于 K3 上向量状态较大,采用堆内存保存上下文。
完成同线程 yield、跨线程 yield、新线程初始状态和跨线程隔离测试,确保任务切换时32个通用向量寄存器+7个csr非特权级控制寄存器+1个特权级寄存器能够正确保存和恢复。
7. 完成 DAG 调度器最小形态
k3_aiScheduler 从占位骨架推进到可工作的最小原型:
- 完成
GraphScheduler、ready queue 和 worker。 - 实现 DAG 到稳定拓扑序的解析。
- 支持
(a || b) -> d(d依赖a和b,必须在a和b都完成后才能执行d)形式的依赖图。 - graph 完成后通过 completion token 回到用户态。
8. 打通 MatMul CPU fallback 数据链路
k3_test 从共享内存保活验证升级为真实数据通路测试。测试构造 MatMul DAG,经 UABI、runtime、driver、scheduler 和 backend 执行,最后回读输出数据。
9. 完成 A100 IME MatMul 探针验证
在配套真板测试环境中,使用 SpacemiT 工具链编译 IME 指令测试程序,完成 A100 smt.vmadot int8 MatMul tile 验证。测试输出与参考结果一致,pad 区域保持未写入状态,说明基本 IME 执行路径正确。
后续工作会把该探针路径逐步收敛到正式 backend candidate 中。
10. 推进 llama.cpp bridge
已尝试使用静态链接和 RISC-V V 扩展编译 llama.cpp,使用 tinyllama-15M-stories 的模型转化为 fp32 做 test。当前仓库已加入 k3_ggml_bridge 测试版 crate,暴露 k3_ggml_matmul_f32 C ABI,用于把 ggml/llama.cpp 侧的 F32 MatMul 请求转换为 k3_aiRuntime graph 提交。
这个 bridge 目前仍是测试版本,主要用于验证接入方式、shape/stride 转换、channel 提交和 completion 链路,不代表稳定可用的完整 ggml backend。这里完成后,原本能在 K3 Linux 上跑的大部分模型都有机会获得部分加速。
系统测试情况
当前的不足
- 算子支持数量仍少,当前只支持matmul。
- 多核心并发、backpressure、timeout、cancel 和长期压力测试仍在后续阶段。
测试概览
| 测试项 | 环境 | 结论 |
|---|---|---|
| StarryOS QEMU 启动 | QEMU | 可启动并验证基础调度路径 |
| StarryOS K3 真板启动 | K3真板 | 已通过 UFS rootfs 启动到 shell |
/dev/k3_airunner channel | K3真板/QEMU | BUILD_CHANNEL 可建立共享区并由内核保活 |
| DAG MatMul CPU fallback | QEMU/K3真板 | graph/UAPI/runtime/scheduler/backend 链路可跑通 |
/proc/set_ai_thread | K3真板/QEMU | 可将当前线程标记为 AI 线程并立刻调度到 AI 核心 |
| V 扩展上下文保存恢复 | QEMU/K3真板 | 同线程、跨线程、隔离测试全部 PASS |
| A100 IME MatMul 探针(只有板子支持) | K3真板 | int8 tile MatMul 输出与参考结果一致 |
| llama.cpp V 扩展 smoke test | QEMU/K3真板 | 程序可运行 |
k3_ggml_bridge 测试版 | 本仓库测试构建 | 已加入测试版 F32 MatMul bridge,仍需继续接入真实 ggml backend |
共享 channel 测试
测试是确认用户态建立的 MAP_SHARED channel 能被内核验证和保活。流程如下:
- 用户态调用
build_channel()打开/dev/k3_airunner。 - 用户态
mmap(MAP_SHARED | MAP_ANONYMOUS)建立共享区。 - 内核通过
BUILD_CHANNELioctl 校验共享区并保存强引用。 - 用户态写入 marker 后释放表层句柄。这里是为了验证用户释放内存后物理内存不会被回收
- 再次读取共享区,确认数据仍存在。
- 使用
MAP_FIXED_NOREPLACE验证原地址范围仍被占用。
结果:成功。
DAG 与 CPU fallback 测试
k3_test 构造 (a || b) -> d 的 MatMul DAG:
a和b无依赖,可并列进入 ready 集合。d依赖a和b的输出。- 用户态通过
GraphManager冻结 graph blob。 - 内核侧解析 graph,生成稳定拓扑序并调用 backend。
- completion token 返回用户态后读取输出 tensor。
结果:成功。
AI 线程亲和性测试
通过 /proc/set_ai_thread 验证线程类型控制:
echo 1 > /proc/set_ai_thread
cat /proc/set_ai_thread
Current AI threads (1):
core=8 tid=1 pid=1 busybox
结果:成功
V 扩展上下文测试
测试程序读取硬件 vlenb,以 m8 寄存器组覆盖全部 32 个向量寄存器,并执行四类验证:
- 同线程
sched_yield后向量寄存器能恢复。 - 新线程初始向量状态为零,不泄漏父线程数据。
- worker 线程 yield 后自己的向量状态能恢复。
- worker 退出后,主线程向量状态不被污染。
真板结果为:
=== Vector Register Context Switch Test ===
Test-1 PASS
Test-A PASS
Test-C PASS
Test-3 PASS
=== ALL PASS ===
结果:成功
k3_ggml_bridge 测试版
当前仓库加入了 k3_ggml_bridge 测试版 crate。该模块暴露 k3_ggml_matmul_f32 C ABI,接收 ggml/llama.cpp 侧的 F32 MatMul 请求,完成 shape/stride 校验后分配 k3_aiRuntime tensor,构造单节点 MatMul graph,并通过 /dev/k3_airunner 等待 completion。
当前定位:
- 用于验证 ggml/llama.cpp 到
k3_aiRuntime的 bridge 接口形态。 - 当前只覆盖 F32 MatMul 的测试路径。
- 当前仍会复制输入输出数据,尚不是最终高性能零拷贝路径。
- 仍需继续接入真实 ggml backend、补充更多 dtype/layout/quant case 和端到端模型测试。
A100 IME MatMul 探针
使用 SpacemiT 工具链编译 A100 IME 指令测试程序,验证 smt.vmadot int8 MatMul tile。测试矩阵为 4x8 与 4x8 column-major,输出 4x4 tile。
日志中 IME 输出与参考输出逐项匹配,pad region 保持未写入状态:
C = A x B^T
IME Ref Match
140 140 ok
168 168 ok
...
=== PASS ===
结果:成功
遇到的主要问题和解决方法
1. K3/K3x 不是传统 NPU 提交模型
问题:调研 linux-k3 公开驱动时,没有找到传统 /dev/npu 或 /dev/a100 command-submission 风格的统一驱动。这不像我之前接触过的传统npu驱动.
解决方法:转向“用户态 runtime + 内核资源管理 + 异构核心调度”的方案。用户态理解算子和 backend candidate,内核负责 graph、队列、映射、核心类型和 completion。
2. K3 真板启动依赖 UFS 驱动
问题:StarryOS 要在 K3 真板上进入可用 shell,需要从 UFS rootfs 启动。UFS 驱动涉及 UFSHCI、UIC、MPHY 上电序列和 UTP 请求列表,迁移成本高。
解决方法:以 SpacemiT Linux 驱动为准,使用 bindgen 生成寄存器定义,然后将驱动文件copy过来,结合ai把linuxkernel的依赖剔除和替换然后使用 c2rust 翻译 C 代码,再手工补胶水代码和 Rust 化边界。这样降低了寄存器抄写错误概率,也让调试重点集中在初始化序列和内存同步上。
3. DMA cache 同步为空实现
问题:UFS 驱动逻辑按 Linux 参考实现迁移后仍然启动异常。进一步在调用前检查内存内容,发现 StarryOS RISC-V DMA cache 同步接口存在空实现,导致设备和 CPU 看到的数据不一致。
解决方法:补齐 StarryOS RISC-V 侧 DMA cache clean/invalidate/sync 路径,使 UFS 描述符和数据 buffer 在设备访问前后保持一致。
4. V 扩展上下文没有保存恢复
问题:K3 的 X100/A100 IME 路径依赖 RISC-V V 扩展。StarryOS 早期任务切换没有保存 32 个向量寄存器和相关 CSR,多个线程使用向量单元时会互相污染。
解决方法:为任务上下文增加 V 状态保存区,覆盖 32 个 vector register group 和相关 CSR。由于 K3 上向量状态较大,使用堆内存保存。然后编写同线程、跨线程和新线程初始化测试,并在 QEMU 与 K3 真板验证通过。
5. IME MatMul 形状和文档理解存在偏差
问题:接入 A100 IME MatMul 探针时,最初结果与参考值不一致,说明对 operand layout、tile shape 或 column-major 约定理解有偏差。
解决方法:通过错误输出反推实际参与计算的数据布局,重新整理 4x8x4 tile 的输入排布、输出位置和 pad 区域,再与 CPU reference 逐项对比。最终 A100 IME 输出与参考结果一致。
6. QEMU 上的向量程序性能异常
问题:llama.cpp 的 V 扩展版本在 QEMU 上出现负优化,多核 SMP 下如果不限制线程数,运行速度会明显下降。
解决方法:将 QEMU 结果定位为功能验证,不作为真实性能结论;在 QEMU 上使用 -t 1 降低原子同步开销,真实性能判断以 K3 真板为准。
分工和协作
协作项目
本项目与 关于我编程然后运行这件事 / project3136859 进行合作。两个项目关注 K3 异构系统中的不同部分:合作项目主要负责 K3 上 RT 核实时任务、通用大核 X100 的大部分控制路径以及核间通信;本项目主要负责 K3/K3x 上 AI 算力的调度、A100/X100 AI 执行路径探索,以及 StarryOS 的 K3 板级适配和驱动工作。
这两个方向是互相依赖的。我的工作解决“AI 算力如何被组织、提交、调度和执行”的问题;合作项目解决“这些 AI 算力在现实系统中如何被用好”的问题。以机器人、无人设备、实时控制系统这类场景为例,AI 推理结果必须被低延迟触发、传递和接入 RT/X100 的控制闭环,才能真正转化为动作、决策和控制效果。AI 算力如果没有 RT 核实时任务、X100 控制路径和核间低延迟通信支撑,对外界的输出就只能停留在离线计算或单点 demo;实时控制系统如果没有可调度的 AI 算力,也难以承接更复杂的感知、推理和决策任务。因此两部分缺一不可。
合作项目中的 ovchannel 原本主要服务于 K3 多核心之间的通信。本项目在此基础上进行了复用和场景扩展:将 ovchannel 作为 AI DAG 任务的提交通道和 completion 回传通道,用于连接用户态 AI runtime、/dev/k3_airunner 内核驱动和内核侧 graph scheduler。
我的负责内容
我主要负责 K3 平台上的 AI 算力调度方向,目标是把 K3/K3x 上的 AI 算力发挥出来,并探索新异构模式下的调度方式和可能性。
本项目提供的是 AI 算力组织和调度能力,而这些算力要在真实系统里发挥作用,必须依赖合作项目负责的 RT 核实时任务、X100 控制路径和低延迟核间通信,把推理结果接入机器人等实际系统的控制流程。换句话说,我负责把算力调出来,合作项目负责让这些算力在现实任务中被用好。
具体工作包括:
- 设计用户态 AI runtime、UAPI、graph blob、tensor desc、kernel desc 和 backend candidate 的接口边界。
- 设计并实现内核侧 AI graph scheduler,把用户态提交的 DAG 解析成可调度任务链。
- 接入 CPU fallback、A100 IME MatMul 探针和后续 X100/A100 backend 的调度入口。
- 实现
/proc/set_ai_thread等 AI 线程控制路径,用于处理 X100/A100 核心类型和向量宽度差异。 - 补齐 RISC-V V 扩展上下文保存恢复,使 IME 指令能够在多任务环境中安全运行。
- 完成 StarryOS 在 K3 真板上的板级适配和驱动工作,包括 UFS 启动路径、DMA cache 同步问题定位和相关驱动调试。
合作项目负责内容
合作项目侧主要负责 K3 异构系统中实时控制和通用计算控制相关的基础能力:
- RT 核实时任务路径,用于承接对确定性和低延迟要求更高的控制任务,并让本项目提供的 AI 算力调度能力进入机器人、无人设备等现实系统的控制闭环。
- 通用大核 X100 的大部分控制逻辑,包括普通任务运行、调度控制和系统侧执行环境。
- K3 多核心之间的通信机制,为不同核心之间传递任务、状态和控制消息提供基础设施。
ovchannel等核间通信组件,为本项目后续复用为 AI DAG 任务通道提供了基础。
ovchannel 的复用方式
合作项目中的 ovchannel 解决的是 K3 多核心之间的通信问题。本项目也涉及多核之间、用户态和内核态之间的任务传递,因此将它复用为 AI runtime 的基础通信组件。
在本项目中,ovchannel 的使用方式是:
- 用户态
k3_aiRuntime建立共享 channel。 /dev/k3_airunner驱动校验并保活共享内存。- 用户态通过 channel 发送
AiGraphSubmitEntry。 - 内核侧 scheduler 接收 DAG 任务并放入 ready queue。
- graph 执行完成后,内核通过 channel 回传 completion token。
这样做的好处是可以复用已经验证过的共享内存通信模型,减少重新设计 ring/channel 的成本,同时也让 AI DAG 提交天然具备向多核任务通信扩展的空间。实际测试中,这条通道在 graph 提交、共享区保活和 completion 回传场景下表现稳定。
协作方式
- 对多核通信、共享内存和 channel 设计保持接口层面的复用,避免两边重复造类似的通信组件。
- RT 核实时任务、X100 通用大核控制和核间通信由合作项目侧推进;K3 板级适配、AI 算力调度、UAPI 和 backend 接入由本项目侧推进。
- 本项目的 AI 算力调度依赖合作项目提供的低延迟控制和核间通信能力,才能进入机器人等现实实时任务场景;合作项目的实时任务和控制闭环也可以把本项目提供的 AI 算力作为可调用、可调度的计算资源。
- 对涉及 StarryOS 的问题,通过真板日志、QEMU 验证和最小测试程序交叉确认,避免只停留在接口设计层面。
比赛收获
对 K3 异构 AI 调度的理解
这次比赛最重要的收获,是认识到 K3/K3x 不能简单按“CPU + 外挂 NPU”的模式来处理。X100、A100、CPU fallback、IME、DMA、TCM 和实时控制路径共同构成了一个更复杂的异构系统。
因此 AI runtime 的核心不只是把某个算子跑快,而是要回答任务什么时候留在 X100,什么时候进入 A100,什么时候回退到 CPU,以及这些选择如何不影响系统中的实时任务。
对系统边界的理解
用户态应该理解算子语义,内核态应该负责资源裁决和执行秩序。这个边界在项目推进中越来越清晰:
- 用户态负责 graph 构建、tensor 描述、算子属性和 backend candidate。
- 内核态负责 DAG 调度、共享内存校验、线程核心类型、completion 和错误返回。
- backend 负责在 CPU/X100/A100 路径上完成具体计算。
这个分层让后续接入 llama.cpp、A100 IME backend 和多核心负载均衡时有比较清楚的扩展方向。
对复用基础设施的认识
ovchannel 的复用说明,一个好的底层通信组件不一定只能服务最初的场景。它原本用于多核通信,在本项目里可以自然扩展成 AI DAG 任务提交与 completion 通道。
这也让项目少走了一段路:通信组件不从零开始,精力可以更多放在 K3 AI 算力调度、StarryOS 板级适配和真实硬件验证上。更重要的是,AI 算力不是孤立存在的,只有和低延迟通信、RT 核实时任务、X100 控制路径结合,才能真正成为系统中可被实时调用的能力。
对 Rust OS 板级开发的经验
StarryOS K3 板级适配让我更系统地理解了驱动迁移和硬件 bring-up 的过程。UFS 驱动、DMA cache 同步、页表映射、V 扩展上下文保存恢复这些问题都说明,AI runtime 的稳定性建立在更底层的系统正确性之上。
只有板子能稳定启动,内存和 cache 一致性正确,线程上下文切换可靠,AI 指令和调度器才有继续优化的基础。
对测试方法的认识
QEMU 适合验证功能路径,真板适合验证硬件行为和真实性能。尤其是 V 扩展、IME 指令、多核通信和 DMA/cache 一致性问题,必须通过真板日志和最小测试程序确认。
这次协作也让我更明确:系统项目不能只靠单点 demo,需要把调研、接口设计、驱动适配、测试日志和问题复盘串成一条完整证据链。
提交仓库目录和文件描述
根目录
| 路径 | 说明 |
|---|---|
README.md | 项目入口、目标描述、文档索引和仓库结构 |
docs/ | 比赛文档、复现说明、开发计划、术语说明和周报 |
k3_aiUabi/ | 内核和用户态共享的 ABI crate |
k3_aiRuntime/ | 用户态 AI runtime crate |
k3_aiScheduler/ | 内核侧 graph scheduler crate |
k3_kernel_backend/ | kernel backend 算子分发 crate |
k3_ggml_bridge/ | 测试版 ggml/llama.cpp bridge crate |
k3_test/ | 最小集成测试程序 |
k3_aiUabi/
| 文件 | 说明 |
|---|---|
src/lib.rs | 导出 UAPI 模块,定义 ABI 版本、最大维度、ioctl 编号和 channel 常量 |
src/desc.rs | 定义 AiTensorDesc、AiKernelDesc、dtype、layout、format 和 tensor size 计算 |
src/graph.rs | 定义 graph blob、graph header、node、edge、parser 和 GraphManager |
src/kernel.rs | 定义 KernelOp 和 AiTargetHint |
src/kernelattr.rs | 定义 MatMul、RMSNorm、RoPE、Softmax、Conv2d 等算子 attr |
src/error.rs | 定义 runtime、scheduler、backend 的错误类型 |
k3_aiRuntime/
| 文件 | 说明 |
|---|---|
src/lib.rs | 用户态 runtime 入口,导出 frontend 模块 |
src/fronted/mod.rs | frontend 模块组织和 UABI re-export |
src/fronted/tensormanager.rs | TensorManager 和 Tensor,负责 MAP_SHARED tensor 分配与描述符生成 |
src/fronted/kd_uring.rs | /dev/k3_airunner 打开、channel 建立、graph 提交和 completion 等待 |
src/test/ | runtime 侧测试模块 |
k3_aiScheduler/
| 文件 | 说明 |
|---|---|
src/lib.rs | scheduler crate 入口,定义 OS 适配 trait |
src/scheduler.rs | GraphScheduler、ready queue、worker、run_graph 和 completion 回包 |
src/kd_kring.rs | graph 到 TaskLink 的拓扑解析,以及调度边界设计说明 |
k3_kernel_backend/
| 文件 | 说明 |
|---|---|
src/lib.rs | backend 统一入口 k3_run_kernel,将 AiGraphNode 转成 BackendCall |
src/matmul.rs | MatMul backend 骨架,当前仓库保留 CPU fallback 路径,A100/X100 路径继续接入 |
k3_ggml_bridge/
| 文件 | 说明 |
|---|---|
Cargo.toml | 测试版 bridge crate 配置,产出 cdylib 和 staticlib,供 C/C++ 侧实验接入 |
src/lib.rs | 暴露 k3_ggml_matmul_f32 C ABI,将 F32 MatMul 请求转换为 k3_aiRuntime graph 提交 |
Cargo.lock | 当前测试构建的依赖锁定文件 |
target/ | 本地构建产物目录,包含测试生成的 .so、.a 等文件,不是核心源码 |
k3_test/
| 文件 | 说明 |
|---|---|
src/main.rs | 最小集成测试,建立 channel,构造 MatMul DAG,提交 graph 并等待 completion |
docs/
| 文件 | 说明 |
|---|---|
design-topic-analysis.md | 比赛题目分析和资料调研 |
system-design.md | 系统框架设计和 Mermaid 架构图 |
progress.md | 开发计划和阶段任务 |
milestones.md | 比赛过程中的重要进展 |
testing.md | 系统测试情况 |
problems-and-solutions.md | 主要问题和解决方法 |
team-and-gains.md | 分工协作和比赛收获 |
how_to_use.md | 复现教程 |
information.md | 术语和补充信息 |
SUMMARY.md | 文档总目录 |
开发日志/ | 周报和开发过程记录 |
配套仓库说明
本提交仓库不直接保存 StarryOS K3 板级驱动源码。以下内容在配套 tgoskits dev 分支中维护:
- K3 COM260 Kit 板级配置。
/dev/k3_airunner设备驱动。/proc/set_ai_thread接口。- UFS、GMAC、SDMMC 等板级驱动。
- StarryOS 真板启动和 rootfs 集成路径。
怎么使用 / 复现本项目
本项目运行时依赖 StarryOS 中的 AI runner 内核驱动(k3_airunner)。需要特别说明的是:k3_airunner 驱动源码和 StarryOS 板级集成不在本仓库中,而是在配套的 tgoskits 仓库中维护。本仓库主要保存 AI runtime、UAPI、调度器、backend 和测试程序等 crate,这些 crate 会作为独立组件编译进 StarryOS 的用户态或内核态。
两种运行环境:QEMU 模拟和 SpacemiT K3 COM260 Kit 真板。
说明:本复现目前最大的作用是让 StarryOS 能在 K3 板子上启动,并验证 AI runtime 相关模块的集成路径。
/dev/k3_airunner内核驱动和 K3 板级适配在tgoskits仓库中;本仓库附带用户态算子库、UAPI、调度器、backend 和测试程序等开发产物。多数模块仍处于阶段一早期,尚未形成完整的端到端推理通路。板级驱动支持状态:
驱动 状态 UFS 测试版,有问题欢迎提 issue GMAC(网卡) 开发中 SDMMC(SD 卡) 开发中
环境准备
克隆项目
git clone https://github.com/Dirinkbottle/k3x-HERA-RT.git
cd k3x-HERA-RT
本项目依赖 tgoskits 仓库。必须切换到 dev 分支,K3 板级支持和 AI runner 设备驱动都在该分支上:
git clone https://github.com/Dirinkbottle/tgoskits.git
cd tgoskits
git checkout dev
两个仓库必须在同一目录!
安装 Rust 工具链
需要 nightly Rust 和 riscv64 目标:
rustup default nightly
rustup target add riscv64gc-unknown-linux-musl
rustup target add riscv64gc-unknown-none-elf
QEMU 模拟运行
在 tgoskits 仓库根目录 下执行:
cd tgoskits
cargo starry qemu --arch riscv64
这会用 QEMU 启动 StarryOS
SpacemiT K3 COM260 Kit 真板运行
1. 构建内核
在 tgoskits 仓库根目录下,使用 K3 板级配置构建:
cd tgoskits
cargo starry build --config os/StarryOS/configs/board/spacemitk3-com260kit.toml
构建产物位于 target/riscv64gc-unknown-linux-musl/release/starryos.bin。
板级配置默认开启:
k3-ufs:UFS 块设备驱动k3-gmac:GMAC 网卡驱动(开发中)- AI runner 设备
/dev/k3_airunner /proc/set_ai_thread接口
2. 刷写 rootfs
K3 开发板使用官方 Yocto BSP 分区表。分区表路径:
riscv-yocto/riscv-yocto/layers/meta-riscv/recipes-core/images/titan-cfg/partition_universal.json
板上已有原厂 UFS 镜像时,只需刷写 rootfs 分区。将 Starry 构建产物中的 rootfs 镜像写入选定分区:
tgoskits/tmp/axbuild/rootfs/rootfs-riscv64-alpine.img/rootfs-riscv64-alpine.img
为方便比赛复现,配套 tgoskits 仓库根目录也会放置一份可用 rootfs 镜像:
tgoskits/root_fs.img
该镜像用于 K3 真板启动和 AI runtime 相关模块验证。刷写时仍需确认目标分区是 rootfs 分区,避免覆盖 U-Boot、设备树或其他启动关键分区。
具体刷写方式取决于板子当前的启动介质和连接方式,常见做法是通过 U-Boot fastboot 或直接在 Linux 下 dd 写入对应 UFS 分区。
3. 上传内核与设备树
通过 USB 连接开发板,在 U-Boot 命令行和宿主机之间配合操作。
方式一:fastboot(当前使用的方式)
在 U-Boot 命令行中依次执行以下操作,每步配合宿主机端 fastboot stage 命令:
先是内核(34 MiB 加载地址,32 MiB 大小上限):
# U-Boot
fastboot -l 0x140000000 -s 0x02000000 usb 0
# Host(宿主机)
fastboot stage target/riscv64gc-unknown-linux-musl/release/starryos.bin
然后是设备树(8 MiB 大小上限):
# U-Boot(Ctrl-C 结束上一个 fastboot 会话后)
fastboot -l 0x138000000 -s 0x00800000 usb 0
# Host
fastboot stage os/StarryOS/configs/board/spacemit-k3-com260-ifx.dtb
最后启动:
# U-Boot
booti 0x140000000 - 0x138000000
方式二:ostool(备选)
也可以使用 ostool 工具配合 sftp 进行启动。
4. 验证启动
连接串口(默认 /dev/ttyUSB0,波特率 115200),启动后应看到 StarryOS shell:
root@starry:#
AI runner 设备会自动挂载,可以通过以下方式确认:
ls /dev/k3_airunner
注意事项
- V 扩展上下文支持:当前已补齐基础的 RISC-V V 扩展上下文保存/恢复,并通过同线程、跨线程和真板测试。A100/X100 IME backend 仍在继续接入,使用时仍需注意线程核心类型和向量宽度差异。
- 板级驱动状态:UFS 驱动仍在测试,但可以满足基本启动需求;SD 卡驱动和 GMAC 网卡驱动仍在开发中。
特别说明和信息
本页用于集中放置项目中的术语说明、硬件信息、阶段性判断和后续需要反复引用的背景材料。
X100 local tensor path
X100 local tensor path 指 X100 核心侧可用于轻量 AI/Tensor/RVV/IME 类任务的本地执行路径。它用于描述小 tensor、短突发、低提交开销的本地 AI 计算候选,而不是 A100 Tensor Processor 的替代品。
在调度策略中,X100 local tensor path 适合优先处理小任务;当该路径任务过多、核心被占用或本地执行成本超过阈值时,任务可以卸载到 A100 candidate。
目前 X100 侧具体支持哪些 tensor/IME 能力仍需要后续通过工具链、hwcap/cpufeature 和真机非法指令探针确认。因此文档中使用 X100 local tensor path 作为暂定术语,避免过早绑定到某个确定 ISA 子扩展集合。
A100 tensor path
A100 tensor path 指 A100 AI 核心侧面向重型 AI 推理的 Tensor/IME 执行路径。A100 更适合大矩阵乘法、LLM 核心算子、大 batch、长 DAG 和高吞吐推理场景。
从架构上看,A100 core 具备 Scalar Processor、Vector Processor 和 Tensor Processor。Tensor Processor 对应 SpacemiT IME,包含 Integer Tensor 与 Float Tensor 路径,并配合 A100 cluster 侧的 TCM/缓存资源服务重型 AI 计算。
在调度策略中,A100 tensor path 是重型任务的主要执行候选;当所有 A100 核心都接近满载或队列拥塞时,调度器可以把具备等价 backend 的溢出任务卸载到 X100 local tensor path 或 CPU fallback。
DirectInline
DirectInline 指用户态算子库直接在当前执行上下文中调用 backend,不经过内核调度器进行核心队列调度。它适合小任务、单进程低负载和对提交延迟敏感的场景。
KernelScheduled
KernelScheduled 指用户态将 lowered graph 或 backend job 提交给内核调度器,由调度器根据队列、依赖和资源状态选择目标核心执行。它适合多核心、高负载、多进程竞争、长 DAG 和需要统一资源管理的场景。
SpacemiT K3 / X100 PMU Raw Event 映射记录
状态:实验记录,2026-08-21
目标:整理 K3/X100 当前公开的mhpmeventraw selector → Linuxperfevent 映射,并记录已知映射问题。
注意:本文优先依据 SpacemiT 公开 K3 Device Tree、Bianbu perf 文档和官方论坛问题帖。
资料来源
-
K3 官方 EDK2 Device Tree:X100 PMU 映射
- https://github.com/spacemit-com/edk2-platforms/blob/k3/Platform/Spacemit/K3/DeviceTree/K3.dts
- 其中
pmu { compatible = "riscv,pmu"; ... }节点定义:riscv,event-to-mhpmeventriscv,event-to-mhpmcountersriscv,raw-event-to-mhpmcounters
-
Bianbu 官方 Perf Usage Note
- https://github.com/spacemit-com/docs-bianbu/blob/375fb8d5d8e97c30a555e0d3e499ed652d0a8b2c/en/development/perf.md
- 说明 RISC-V Linux
perf、SBI PMU、Device Treeriscv,pmu节点与 raw hardware event 的关系。 - 也说明 raw event 可通过
perf -e rNNN或 PMUevent=...形式使用。
-
K3 Datasheet
- https://github.com/spacemit-com/docs-chip/blob/main/en/key_stone/k3/k3_docs/k3_ds.md
- Datasheet 明确 X100 与 A100 均集成 RISC-V PMU;A100 支持 1024-bit RVV。
Perf Event映射链路
Linux perf event
↓
SBI PMU generic/cache event ID
↓
OpenSBI 解析 Device Tree: riscv,event-to-mhpmevent
↓
mhpmeventN 写入 raw selector
↓
X100 PMU 硬件计数
下面表格里的 Raw mhpmevent 是最终写入硬件 HPM event selector 的值
例如:
perf: stalled-cycles-frontend
↓
SBI/DT event ID: 0x00008
↓
mhpmevent raw selector: 0x03
X100:Raw mhpmevent → perf Event 映射
Raw mhpmevent | SBI / DT Event ID | Linux perf 语义 | 建议的 perf 名称 | 当前状态 |
|---|---|---|---|---|
0x01 | 0x00005 | Retired branch instructions | branches / branch-instructions | ✅ 已公开映射 |
0x02 | 0x00006 | Branch mispredictions | branch-misses | ✅ 已公开映射 |
0x03 | 0x00008 | Stalled cycles - frontend | stalled-cycles-frontend | ✅ 已公开映射 |
0x04 | 0x00009 | Stalled cycles - backend | stalled-cycles-backend | ✅ 已公开映射 |
0x05 | 0x10001 | L1D read miss | L1-dcache-load-misses | ✅ 已公开映射 |
0x06 | 0x10000 | L1D read access | L1-dcache-loads | ✅ 已公开映射 |
0x07 | 0x10005 | L1D prefetch miss | L1-dcache-prefetch-misses | ✅ 已公开映射 |
0x08 | 0x10004 | L1D prefetch access | L1-dcache-prefetches | ✅ 已公开映射 |
0x09 | 0x10003 | L1D write miss | L1-dcache-store-misses | ✅ 已公开映射 |
0x0a | 0x10002 | L1D write access | L1-dcache-stores | ✅ 已公开映射 |
0x0b | 0x10009 | L1I read miss | L1-icache-load-misses | ✅ 已公开映射 |
0x0c | 0x10008 | L1I read access | L1-icache-loads | ✅ 已公开映射 |
0x16 | 0x10018 | DTLB read access | dTLB-loads | ✅ 已公开映射 |
0x19 | 0x1001b | DTLB write miss | dTLB-store-misses | ✅ 已公开映射 |
0x1a | 0x1001a | DTLB write access | dTLB-stores | ✅ 已公开映射 |
0x1b | 0x10021 | ITLB read miss | iTLB-load-misses | ✅ 已公开映射 |
0x1c | 0x10020 | ITLB read access | iTLB-loads | ✅ 已公开映射 |
0x1e | 0x00001 | CPU cycles | cycles | ✅ 已公开映射 |
0x1f | 0x00002 | Retired instructions | instructions | ✅ 已公开映射 |
当前 DTS 允许使用、但公开资料尚未给出语义的 Raw Event
K3 官方 DTS 的 riscv,raw-event-to-mhpmcounters 还允许下列 raw selector 被配置到普通 HPM counter:
0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08
0x09 0x0a 0x0b 0x0c
0x10 0x11 0x12 0x13 0x14 0x15 0x16 0x17
0x18 0x19 0x1a 0x1b 0x1c
0x1e 0x1f
0x20 0x21 0x22
0x24 0x25 0x26 0x27 0x28 0x29
0x2b 0x2d
0x32 0x33 0x34 0x35 0x36 0x37 0x38
0x3a 0x3b 0x3c 0x3d 0x3f
其中只有一部分已经通过 riscv,event-to-mhpmevent 给出公开语义。
官方论坛对“完整 PMU event 对照表”的公开答复是:
这个暂时不对外提供的
来源同上:
- https://forum.spacemit.com/t/topic/1500
开发日志
这里记录项目开发过程中的阶段性总结、技术判断、问题复盘和后续计划。
周三技术交流纪要:StarryOS 在 K3 上的驱动与 AI 运行时适配
一、本次交流核心总结
我的工作以 SpacemiT K3 COM260 Kit 为硬件平台、StarryOS 为软件平台,目标是将 K3 板载 AI 算力纳入 StarryOS 的内核资源管理与调度体系。在此基础上,进一步提高 AI 任务分配和调度的灵活性,并为上层应用提供更统一、易用的 AI 算力调用方式。
当前工作已经从 QEMU 上的架构原型推进到 K3 COM260 Kit 真板验证。StarryOS 已可以通过 UFS rootfs 启动到 shell,并具备串口调试、基础中断、DMA/cache 一致性处理、RISC-V V 扩展上下文保存恢复等必要条件。
AI 运行时方面,已经打通“用户态 Runtime → UAPI → /dev/k3_airunner(目前是以ioctl操作k3_airunner来提交任务的实验性方式与starryos内核的调度器进行交互) → 内核 Scheduler → Backend → Completion”的最小闭环,CPU fallback MatMul、DAG 拓扑执行、共享 channel 和 A100 IME int8 MatMul 探针均已通过正确性验证。
完整 ggml/llama.cpp 模型尚未经由我自己的 Runtime 正确跑通,原因因为ggml的某些计算节点的实现有问题,具体点还未定位;K3 官方 Runtime 中与 spacemit-k3 Backend、Task 和 Scheduler 直接相关的实现细节也不足以支持 StarryOS 完整复用。
二、StarryOS 在 K3 上的驱动适配进展
| 模块 | 当前状态 | 已完成的验证 | 尚存问题 |
|---|---|---|---|
| K3 真板启动 | 已打通 | StarryOS 可通过 UFS rootfs 启动到 shell | 暂无核心阻塞 |
| UFS 驱动 | 可用 | 完成 UFSHCI/UIC/MPHY/UTP 主要链路的迁移和真板启动 | 暂无核心阻塞 |
| 串口与调试通路 | 已可用 | 可用于启动、UFS、USB、AI runner、V/IME 调试 | 暂无核心阻塞 |
| APLIC/平台中断 | 已接入 | 已接入 StarryOS 的 K3 平台中断框架 | 暂无核心阻塞 |
| DMA/cache 基础能力 | 已补齐基本机制 | 使用 Zicbom 完成流式 DMA buffer 的 clean/invalidate;使用 Svpbmt 处理 USB ring/context 等高频共享结构 | 暂无核心阻塞 |
| USB/DWC3 | 枚举链路已打通 | 完成 K3 DWC3 平台兼容层;修复 ring/context 一致性后,crabusb 可继续枚举和传输流程 | 实际设备的长时间传输、异常恢复及小车控制尚未充分验证 |
| GMAC 网卡 | 可用 | 可以有效的进行网络通信 | 暂无核心阻塞 |
| SDMMC/SD 卡 | 开发中 | 无 | 尚未完成 |
| RISC-V V 扩展上下文 | 已通过基础验证 | 完成 32 个向量寄存器组及相关 CSR 的保存恢复;QEMU 和 K3 真板的同线程、跨线程、新线程隔离测试均通过 | X100 与 A100 的 VLEN 分别为 256 和 1024,活跃向量上下文目前不能随意跨类型迁移 |
| AI 线程控制 | 开发测试版 | /proc/set_ai_thread 可将当前线程标记为 AI 线程并调度到 AI 核心集合 | 只能设置当前线程;取消 AI 标记后的跨 VLEN 返迁需要明确 safe point 和状态约束 |
三、AI 运行时适配进展
1. 已经打通的最小闭环
当前 AI 通路由以下模块组成:
AI 应用
↓
onnx runtime ep/ggml
↓
k3_aiRuntime:tensor、graph、channel、submit/completion
↓
k3_aiUabi:内核与用户态共用 ABI
↓
/dev/k3_airunner:共享内存校验、保活和任务通道
↓
k3_aiScheduler:DAG 解析、ready queue、worker
↓
k3_kernel_backend:CPU / X100 / A100 路径分发
↓
completion token 返回用户态
已经完成的包括:
/dev/k3_airunner的BUILD_CHANNEL能校验并保活用户态MAP_SHARED区域,用户态表层句柄释放后共享区仍然有效。k3_aiScheduler能把(a || b) -> d这类 DAG 解析为满足依赖约束的稳定拓扑序,当前由 worker 按 FIFO 执行。- CPU fallback MatMul 已打通 UAPI、Runtime、Driver、Scheduler、Backend 和 Completion 数据链路。
- llama.cpp 的 RVV 与非 RVV 版本均能在 StarryOS K3 真板上运行 TinyStories 类小模型。
2. Backend 与模型接入进展
k3_kernel_backend 已经补充了 MatMul、Conv2D、二元/一元 elementwise、Softmax、RMSNorm、RoPE、SwiGLU、MaxPool、ReduceMax、TopK 和多种 tensor transform 等算子,并对部分路径实现 RVV 加速。量化方面已覆盖 I8/U8 及 ggml Q8_0、Q3_K、IQ4_NL 的部分路径。
- 当前只覆盖 F32 MatMul 桥接的核心路径。
- 输入和输出仍需要复制,还不是零拷贝高性能方案。
- 完整 ggml backend 接入 TinyStories 模型时的输出与预期不一致,尚未定位是节点遗漏、shape/stride/layout、量化语义、KV cache 还是其他推理环节的问题。
3. 官方 Runtime 行为调研
为了避免在不清楚官方 Scheduler 能力时重复造轮子,已在 K3 Ubuntu 上使用官方 ONNX Runtime + SpaceMIT Execution Provider 和量化 YOLOv8n 进行 E0-E3 黑盒实验。
当前 E0/E1 结果显示:
- E0 无干扰时,100 次推理平均延迟约为
52.68 ms,吞吐约为18.98 inference/s。 - E1 中把 Runtime 外部负载逐核移动到 CPU8-15 后,推理活跃核和性能会随外部负载位置变化。其中一轮外部负载位于 CPU8 时,平均延迟约为
107.41 ms,吞吐降到约9.31 inference/s。 - 这可以证明官方 Scheduler 至少会对 Runtime 外的硬件负载产生响应,但还不能说明它已经具备 workload-aware 或 PMU-aware 的调度能力。
PMU 方面已整理出一部分 X100 raw event 映射,并验证 instructions、cycles、frontend/backend stall 等基本事件的采样链路。后续还需要校准 cache/memory 事件、采样周期、multiplexing 误差和数据归属。
4. 调度器目前只是最小形态
当前 Scheduler 只是完成 DAG 拓扑排序和 FIFO worker 执行。以下能力还未具备:
- 多 A100/X100 核心的ai任务更灵活的调度策略。
- Rust async 调度和 completion waker。
- backpressure、cancel、timeout、reset 和 error fallback。
- buffer planner、一次性 graph 提交和长 graph 检查点。
- 多进程竞争、公平性和长时间压力测试。
- 结合队列长度、PMU/Trace、DMA backlog 和历史延迟的动态负载均衡。
四、当前 K3 AI 算力适配 StarryOS 的主要困难
1. 官方 AI Runtime 与 StarryOS 调度层之间尚缺少稳定的对接边界
SpineRuntime 已经公开 BackendHandle、Stream、Grid/Tile、Future、Barrier/Event、Core Coordinator 和 runtime_stats() 等编程模型。但是,与 K3 真实硬件紧密相关的 spacemit-k3 Backend、Task descriptor 及其生命周期、Core Coordinator 内部机制,以及 Scheduler 的选核与资源统计实现,目前仍不足以支持我们直接修改、编译并重新部署到 StarryOS。
因此,当前存在两条不完全重合的技术路线:一条是继续完善 StarryOS 上的自研 Runtime,另一条是获得官方 Scheduler 扩展点后,在官方 Runtime 的任务模型和调度策略上进行对接。如果不先明确两者边界,就可能在 Task、Stream、TCM/DMA 以及多进程资源协调等方面,重复实现官方 Runtime 已经具备的能力。
目前开发重心正逐步转向:在保留官方 Runtime 执行模型和既有调度策略的基础上,将 K3 AI 算力纳入 StarryOS 内核的统一资源管理与调度。这样可以同时结合官方 Runtime 对 AI 任务的理解,以及 StarryOS 对系统负载、核心状态和任务优先级的全局视角,使 AI 算力的调度和分配更加灵活。
以 YOLOv5 为当前验证对象,具体落点是对 ONNX Runtime 的 K3 Execution Provider(K3 后端)进行必要的代码适配:将模型推理任务通过明确的接口交给 StarryOS 调度层,再由内核结合当前资源状态完成 AI 核心的分配和任务放置。这一路径的重点是将官方 Runtime 与 StarryOS 调度机制结合起来,而不是重新实现整套模型推理流水线。
2. PMU 数据丰富度影响调度策略
目前公开的 PMU 映射仅覆盖部分 X100 性能事件,一些 DTS 允许使用的 raw selector 仍没有公开语义;A100 侧可供 Runtime 稳定采集的资源事件范围也不明确。A100 cluster 中配有专用的 TCM(Tightly Coupled Memory,紧耦合存储器)。如果 A100 PMU 能够提供足够丰富且语义明确的性能事件,尤其是能够反映 TCM 访问、冲突、带宽或等待压力的事件,调度器就有机会识别“计算单元空闲但片上存储受限”这类状态。相比只依赖队列长度或核心 busy/idle,这类信息可以为任务选核、负载均衡和干扰规避提供更细粒度的依据。
另一方面,PMU counter 数量有限,事件多路复用、采样窗口、上下文切换以及样本数据能否准确归属到具体任务或核心,都会影响统计结果的准确性。因此,现阶段应先通过微基准完成事件语义、采样周期、开销和稳定性校准,不宜仅根据单次 PMU 差值直接决定任务放置。
周报
这里按周记录开发进展。
- 第一周 6.2-6.8
- 第二周 6.9-6.15
- 第三周 6.16-6.22
- 第四周 6.23-6.29
- 第五周 7.20-7.26
- 第六周 8.2-8.8
- 第七周 8.9-8.15(一)
- 第七周 8.9-8.15(二)
- 第八周 8.31-9.6
- 第九周 9.7-9.12
- 第九周 Bug 发现:SpacemiT K3 A100 偶发产生非法
stval - 第九周阶段性工作总结(FP16 YOLOv5 推理验证)
- 第十周 9.13-9.19
第一周周报(6.2-6.8)
本周主要围绕 K3/K3x 的 datasheet、用户手册、开源资料和官方 AI runtime 包进行资料梳理,目标是确认 K3x 的 AI 算力组织方式,并据此制定后续开发计划。
本周工作概览
本周完成了五件事:
- 阅读 K3/K3x 相关硬件资料,整理 X100、A100、Vector、FPU、Tensor/AI 单元、DMA、TCM 等关键模块之间的关系。
- 检索 linux-k3 公开驱动,确认是否存在传统 NPU/A100 command-submission 风格驱动。
- 逆向分析 SpacemiT 官方 ONNX Runtime EP 后端,确认
libspacemit_ep.so中图编译、算子派发、TCM/DMA/MMZ 管理和算子执行的大致位置。 - 确认要编译和使用 A100 专用 IME 指令,需要使用 SpacemiT 官方交叉编译工具链。
- 开始实现用户态算子库 frontend 的最小结构,先把提交到 uring 的 kernel desc、tensor desc 和 data token 这些基础结构定下来。
这些工作共同指向一个结论:K3/K3x 的 AI 算力更适合按“异构计算资源”来组织,而不是按传统外挂 NPU 驱动来组织。
K3x 的异构 AI 算力结构
根据当前资料,K3x 可按 8 个 X100 核心和 8 个 A100 核心来理解。X100 主要承担通用计算、系统调度、用户态入口和轻量 AI 任务;A100 是更重的 AI 计算核心,面向更大的 tensor/vector 工作负载。
从 cluster 图可以看到,X100 cluster 中的每个 X100 core 除了 RISC-V 64GCVBH Core、Vector、FPU 之外,还并列标出了 AI 模块。这说明 X100 侧并不是完全没有本地 AI 能力。后续文档中,暂时将 X100 侧这种轻量 AI/Tensor 执行路径称为 X100 local tensor path。
A100 cluster 则更明确地面向 AI 计算:每组 A100 core 配套 Vector、AI/Tensor Processor、L2 Cache 和 TCM。A100 侧的 tensor 执行路径后续称为 A100 tensor path 或 A100 Tensor Processor。
A100 架构图中可以看到,A100 core 由 Scalar Processor、Vector Processor 和 Tensor Processor 组成。Tensor Processor 标注为 SpacemiT IME,并进一步分为 Integer Tensor 和 Float Tensor。这与官方 IME 指令集资料中 A100 支持完整矩阵扩展的描述一致。
X100 local tensor path 与 A100 tensor path
X100 与 A100 都可以参与 AI 计算,但定位不同。
X100 local tensor path 更适合短突发、轻量级、小 tensor 或低提交开销任务。它的价值不在于替代 A100,而是在系统负载较轻或任务规模较小时,避免所有 AI 任务都进入 A100 队列。
A100 tensor path 更适合重型矩阵乘法、LLM 核心算子、大 batch 或长 DAG 场景。A100 的 RVV VLEN 更大,并且公开资料中明确列出了更完整的 IME 子扩展支持。
X100 cluster 图中虽然标出了 AI 模块,但 X100 local tensor path 的精确 ISA 支持范围还需要后续通过工具链、hwcap/cpufeature 和真机非法指令探针确认。当前可以先把 X100 侧视为轻量 AI candidate,把 A100 侧视为完整 AI candidate。
IME 支持范围整理
公开 IME 资料中明确列出了 A100 支持 13 个 IME 子扩展。A60 作为较早一代 AI 核,只支持 2 个子扩展。X100 local tensor path 的具体支持矩阵仍需后续验证,但可以先参考这种“轻量路径 vs 完整路径”的差异来规划调度策略。
| 路径 | 已知/待确认支持 | 说明 |
|---|---|---|
| A60 / 轻量矩阵路径参考 | Xsmti8i32mm、Xsmti8i32mm_slide | 公开 IME 文档中已列出的轻量 AI 核支持范围,可作为 X100 local tensor path 的最小参考模型 |
| A100 tensor path | 13 个 IME 子扩展 | 支持整数、滑窗、结构化稀疏、分块量化、FP16/BF16 到 FP32 等完整矩阵路径 |
| X100 local tensor path | 待真机探针确认 | cluster 图显示 X100 core 旁存在 AI 模块,但具体指令支持范围需后续验证 |
A100 支持的子扩展如下:
| 子扩展 | 类型 | 说明 |
|---|---|---|
Xsmti4i32mm | Int4 -> Int32 | 整数矩阵乘法 |
Xsmti8i32mm | Int8 -> Int32 | 整数矩阵乘法 |
Xsmti8i32mm_slide | Int8 -> Int32 | 面向卷积/滑窗的整数矩阵乘法 |
Xsmti4i32mm_42sp | Int4 -> Int32 | 4:2 结构化稀疏整数矩阵乘法 |
Xsmti8i32mm_42sp | Int8 -> Int32 | 4:2 结构化稀疏整数矩阵乘法 |
Xsmti4fp16mm_scl16f | Int4 + scale -> FP16 | 分块量化矩阵乘法 |
Xsmti4bf16mm_scl16f | Int4 + scale -> BF16 | 分块量化矩阵乘法 |
Xsmti8fp16mm_scl16f | Int8 + scale -> FP16 | 分块量化矩阵乘法 |
Xsmti8bf16mm_scl16f | Int8 + scale -> BF16 | 分块量化矩阵乘法 |
Xsmtfp16fp32mm | FP16 -> FP32 | 浮点矩阵乘法 |
Xsmtbf16fp32mm | BF16 -> FP32 | 浮点矩阵乘法 |
Xsmtfp16fp32mm_slide | FP16 -> FP32 | 面向卷积/滑窗的浮点矩阵乘法 |
Xsmtbf16fp32mm_slide | BF16 -> FP32 | 面向卷积/滑窗的浮点矩阵乘法 |
这个差异直接影响后续调度策略:X100 local tensor path 适合作为轻量、低延迟、本地优先的候选路径;A100 tensor path 适合作为重型 AI 任务的主要执行路径;CPU fallback 则用于正确性兜底和不支持算子的兼容执行。
SpacemiT AI 矩阵扩展指令集(Zvvm_spacemit Profile)
linux-k3 驱动检索结果
本周在 linux-k3 公开驱动中检索 A100/NPU 风格的传统计算提交驱动,没有发现类似 /dev/npu、/dev/a100 这种内核接收算子或 command buffer 并提交计算的驱动路径。
目前能对应到 AI 运行链路的更多是资源和通道类接口,例如 DMA、TCM、线程绑定、共享内存或中断相关机制。这说明 K3/K3x 的 A100 更像可运行用户态代码的 AI CPU 域,而不是一个只能通过内核 ioctl 提交任务的外设 NPU。
这一点对项目方向非常关键:如果 A100/X100 的 AI 指令可以在用户态执行,那么我们的运行时不必围绕“内核接收完整算子并代替用户态执行”来设计,而应围绕“用户态 backend 实现 + 内核调度资源和队列”来设计。
SpacemiT ONNX Runtime EP 逆向发现
随后对 SpacemiT 官方 ONNX Runtime EP 后端进行了逆向分析,重点观察 libspacemit_ep.so 和相关运行时库的行为。
初步结论如下:
- ONNX Runtime 负责模型加载、图解析和 EP 分区。
libspacemit_ep.so负责 SpineGraph 构建、算子支持判断、算子派发和具体 compute kernel 调用。- TCM 管理通过
libspine_tcm.so动态加载并调用。 - DMA、MMZ、TCM、线程绑定等资源管理逻辑主要在用户态 runtime 中完成。
- 没有发现“内核驱动接收完整算子并统一提交 A100 计算”的传统路径。
这进一步验证了本周的判断:SpacemiT 官方路径本身就是以用户态 AI runtime 为中心的。官方 runtime 在用户态完成图编译、算子选择、内存准备和计算执行;内核供资源节点、映射、同步和线程绑定能力。
6.7-6.8:工具链确认与用户态算子库 frontend 雏形
6.7-6.8 主要从资料确认转到第一阶段的代码结构设计。
首先确认了编译工具链问题。普通 RISC-V 工具链可以编译常规 RV64 程序,但要写 A100 专用 IME 指令,不能只靠系统默认 gcc/clang。后续需要使用 SpacemiT 官方交叉编译工具链,尤其是其中对 SpacemiT 扩展指令、汇编 mnemonic 和目标架构参数的支持。这样后面写 A100 IME kernel、验证 IME 指令能不能正常汇编、跑最小指令探针时,路径是明确的。
第二周周报(6.9-6.15)
本周工作概览
本周到目前为止完成了四件事:
- 完成用户态 backend 算子库的框架和 ABI,补出
matmul算子的最小调用骨架。 - 完成 buffer pin/map/cache 最小路径,用户库负责 tensor 的分配和管理,共享任务队列通过
airunner + ioctl + shared mmap建立。 - 完成
k3_airunner的BUILD_CHANNEL最小通路,并在k3_test中验证共享内存保活是否成立。 - 根据 K3 HMP 文档进一步确认 Linux 侧的 AI 核使用方式,明确后续需要补线程类型和核心亲和性控制接口。
buffer pin/map/cache 最小路径
目前的实现是:
- tensor 的分配和生命周期先由用户态算子库承担;
- 用来提交任务和接收执行结果的共享内存,不走普通堆内存,而是通过打开
airunner后由用户先mmap(MAP_SHARED | MAP_ANONYMOUS)建立一片共享区; - 然后用户把这片共享区的信息通过 ioctl 交给内核;
- 内核检查这段用户地址空间确实对应 shared backend 之后,抓住它背后的强引用做保活。
这样做以后,这片共享内存就可以稳定地拿来做无锁任务队列。
当前任务提交流程
现阶段整个任务提交流程还是偏传统外挂设备风格:
- 打开设备文件
- 通过 ioctl 建立通道
- 后续继续通过 ioctl 或共享区提交任务
在 K3 上先这么做,不是因为 A100 只能这样用,而是为了后面多线程、多重型任务和多核心调度时,内核需要有一个统一的裁决点。这样后续做负载均衡、核心裁决和跨进程竞争控制时,路径是通的。
后面仍然会保留更轻的执行方式。后续会补一条更轻量的异步、纯用户态调度路径,把小任务、低冲突场景和直接用户态执行的效率保留下来。
k3_test 最小通路验证
这周已经在 k3_test 里把 BUILD_CHANNEL 最小链路跑通了。
当前测试过程是:
- 用户态调用
build_channel(); - 用户先
mmap出共享区; k3_airunner收到 ioctl 后验证这段共享区,并在内核里建立保活记录;- 用户往共享区写入标记字符串;
- 用户态主动 drop 掉表层
UringChannel; - 再次访问原共享区地址,确认数据还在;
- 再尝试
MAP_FIXED_NOREPLACE到同一地址,确认原映射仍然占着这段地址范围。
当前运行日志如下:
root@starry:/root # ./k3_test
[ 70.972350 0:27 starry_kernel::pseudofs::dev::k3_airunner:60] k3_airunner: BUILD_CHANNEL ioctl reached, arg=0x3fffffb30
[ 70.973101 0:27 starry_kernel::pseudofs::dev::k3_airunner:119] k3_airunner: BUILD_CHANNEL keepalive pid=27, user_va=0x75000, size=0x10400, channels=2
[ 70.973589 0:27 starry_kernel::pseudofs::dev::k3_airunner:138] k3_airunner: BUILD_CHANNEL registered pid=27, va=0x75000, size=0x11000, pages=17
k3_test: channel built, va=0x75000, size=0x10400
k3_test: wrote marker string into shared channel memory
k3_test: dropped user-facing UringChannel handle
k3_test: readback after drop="ovchannel"
k3_test: MAP_FIXED_NOREPLACE failed as expected, original mapping is still occupying the same va range
这个结果说明当前共享区保活路径是成立的。用户态先放手之后,内核侧仍然能把这段共享区托住。
文档发现
从这份文档里可以确认,Linux 上是通过线程类型和亲和性控制来做的。
当前公开路径里,Linux 侧是通过 /proc/set_ai_thread 把线程标记成 AI 线程,然后再由内核把它约束到 A100 核心集合上运行。这个是因为 X100 和 A100 的向量宽度不同,线程一旦开始使用对应的向量状态,就不能再随意跨类型迁移。
第三周周报(6.16-6.22)
本周工作集中在两条线:StarryOS 的 K3 板级适配(目标是让 Starry 能在 K3 真板上启动到 shell)和 AI 运行时的内核驱动与用户态算子库继续推进。
本周工作概览
本周完成了五件事:
- 完成 K3 板级 UFS 驱动,对照 Linux 参考实现逐段翻译为 Rust,StarryOS 成功在 K3 真板上进入 shell。
- 确认 K3 板级其余存储/网络基础设施缺口(SD 卡驱动、GMAC 网卡驱动),验证分区表和刷写流程。
- 根据 K3 HMP 文档在内核中创建
/proc/set_ai_thread接口,实现对 AI 线程的核心亲和性控制。 - 完成用户态运行时 UABI 层的统一重构,建立
k3_aiUabi作为内核-用户态接口的唯一真源。 - 实现 AI 调度器基本框架,完成 DAG 到直链的拓扑解析,并在
k3_test中用 2x5 矩阵乘法通路做真实数据验证。
StarryOS K3 板级适配
本周板级适配的核心是让 StarryOS 摆脱纯内存文件系统的限制,能够从 UFS 存储介质加载 rootfs。
分区表与镜像制备
K3 开发板的镜像结构需要遵循官方 Yocto BSP 中定义的分区表。具体路径在官方 Yocto 源码的 partition_universal.json 中给出。由于板子上已存在原厂 UFS 镜像,本次只刷写 rootfs 分区,将 Starry 构建产物中的 rootfs-riscv64-alpine.img 写入选定分区。
- 注意! 在spacemit yocto的readme中指出,blk sd设备需使用partition_universal格式的布局,如果需要全面重刷切勿刷错
UFS 驱动实现
UFS 驱动是本周围绕 K3 板级投入最大的单项工作。K3 使用 JEDEC UFS 2.1 存储方案,驱动需要处理 UFSHCI 寄存器、UIC 层(DME_SET / DME_LINK_STARTUP)、MPHY 上电序列以及 UTP 传输请求列表的管理。
实现策略是严格对照 Linux 主线 ufs-spacemit.c 的实现逐段翻译为 Rust。
由于驱动体量较大,采用了 AI 辅助对照翻译的协作方式:以 Linux 版本为唯一参考,逐段翻译并保持寄存器定义、初始化和命令提交流程的严格对应。这样可以让我将精力集中在后续 AI 运行时本身的开发上。
当前板级状态
- UFS 驱动:已完成,StarryOS 在 K3 板上成功进入 shell。
- SD 卡驱动(SDHCI):开发中。
- GMAC 网卡驱动:开发中。
上板测试中还有一个重要发现:Starry 当前在任务上下文保存时,还没有考虑 RISC-V V 扩展的 vector 寄存器保存/恢复。而 K3 的 X100/A100 IME 扩展指令都以 V 扩展为基础,这意味着在 Starry 上使用 AI 指令之前,必须先补齐 V 扩展的上下文支持。
AI 运行时内核驱动
/proc/set_ai_thread 接口
根据 K3 HMP 说明文档,Linux 侧通过 /proc/set_ai_thread 把线程标记为 AI 类型,再由内核将其约束到 A100 核心集合上运行。这是因为 X100 和 A100 的向量宽度(VLEN)不同,线程一旦开始使用对应类型的向量状态,就不能再跨类型迁移。
本周在 Starry 内核中创建了对等的 /proc/set_ai_thread 接口。实现上与 Linux 参考有一处关键策略差异:我们没有直接死板地把线程亲和性锁在 A100 核心集合上,而是根据实际负载和程序要求动态决定亲和性。
这个决策的主要考量:
- X100 侧同样具备轻量 AI 能力(第一周已确认 X100 cluster 图中标出了 AI 模块),对于小 tensor、低提交开销任务,走 X100 local path 更高效。
- A100 侧适合重型矩阵乘法和 LLM 核心算子,但不意味着所有 AI 任务都应被排他性地路由到 A100。
- 动态策略使调度器能在了解任务规模后做路由决策,而不是在入口就把所有 AI 线程钉死在 A100 上。
注意这一层控制不只是“设置亲和性“,还需要把 X100/A100 的核心类型语义带进调度器,防止已使用某类向量/IME 状态的线程跨到另一类核心上运行。这部分与 V 扩展上下文保存是一体两面的问题,需要后续在调度路径中一并解决,目前暂且认为迁移到a100上的线程不能迁移回x100,但是当线程尝试设置自己为ai线程时会尝试将线程留在x100核心上。
参考:K3 HMP 说明
用户态 AI 运行时重构
本周用户态运行时经历了一次较大的结构调整,核心目标是建立统一的 UABI(User-ABI)层。
k3_aiUabi:统一 UABI 层
将原先分散在 k3_aiRuntime 中的 desc(tensor/kernel 描述符)、graph(计算图)、kernel(算子定义)和 kernelattr(算子属性)模块提升到独立的 k3_aiUabi crate 中。这个 crate 作为内核和用户态之间的接口定义层,两边共用同一套类型。
主要变更:
- MatMulAttr 重新设计,补全 stride 信息。之前的实现将 stride 提取逻辑放在 backend 侧,依赖 TensorView 的形状推断。新的 MatMulAttr 在构造时就携带完整的 lhs/rhs/out 的 row_stride、col_stride 和 batch_stride(以元素为单位),并加入
MAX_STRIDE_BYTE(4GB)上限常量。这样 backend 不再需要理解 tensor 布局,只管按属性执行。 - 新增
AiRuntimeErr、SchedulerErr、BackendErr三级错误类型,替换各 crate 中散落的io::Result、Result<(), ()>和i32错误码。现在错误从 backend → scheduler → runtime 有统一的类型传递路径。 k3_aiRuntime和k3_kernel_backend同步迁移到新的 UABI 类型。
k3_aiScheduler:调度器框架
调度器本周从占位骨架推进到可工作的最小原型:
- 完成
GraphScheduler的基本操作:new、take_task、push_task。 - 实现
run_graph:按节点迭代执行,带调试日志输出(op 类型、tensor 信息、形状)。 - 完成 DAG 到直链的拓扑解析(
resolve_parsed_graph)。阶段一先按稳定拓扑序把所有节点收成一条TaskLink直链:入度为 0 的节点入 ready 队列,按 node id 自然序出队,完成后减少后继入度,重复到图空。这样a→b, c→b会解析为a→c→b等满足边约束的稳定顺序。 - 定义
K3SchedulerOpstrait(copy_from_user、map_user_to_kernel等)和K3DmaAllocatortrait(alloc_dma、cache 操作),作为调度器与 OS 层的接口契约。后续在不同 OS(StarryOS / Linux)上只需要实现这些 trait。
k3_test:真实数据通路验证(在qemu上用cpu纯算)
k3_test 从上一周的共享内存保活验证升级为 2x5 矩阵乘法通路测试:
- 构造 lhs 矩阵
[[1,2,3], [4,5,6]](2x3)。 - 构造 rhs 为 3x5 单位矩阵。
- 构造完整的 MatMulAttr(含所有 stride 字段),通过调度器链路提交执行。
- 打印结果验证计算正确性。
这个测试打通了 UABI → Runtime → Scheduler → Backend 的完整调用链路,虽然 backend 的 matmul 目前还是 CPU 软件实现(IME 指令路径需要工具链支持),但数据结构、接口和调度流程已经可以在本地跑通。
后续工作
- V 扩展上下文支持:在 Starry 的任务上下文切换中补齐 vector 寄存器的保存/恢复,这是 K3 AI 指令执行的前置条件。
- K3 板级驱动补完:SD 卡驱动和 GMAC 网卡驱动。
- 调度器第二阶段:在拓扑排序的基础上加入实际的多核心路由决策,结合负载和核心类型做任务分发。
- AI thread 类型控制面:将 X100/A100 核心类型语义完整带入 Starry 调度路径。
第四周周报(6.23-6.29)
本周工作主要为 K3 板级适配和 AI 运行时。其次是比赛文档的编写. 与最初计划相比,本周有相当一部分时间被平台侧基础能力占用:V 扩展上下文、串口驱动、GMAC 驱动和真板运行环境都直接影响后续 A100/X100 IME backend 能否可靠运行。
本周工作概览
本周主要完成和推进了六件事:
- 补齐 StarryOS 上 RISC-V V 扩展的上下文保存、恢复、初始化和线程隔离测试。
- 完成 K3 串口驱动相关支持,改善真板调试和日志输出条件。
- 编译 llama.cpp 的 V 扩展版本和非 V 扩展版本,并分别在 QEMU 和 K3 真板上运行 TinyStories/TinyStory 类小模型,确认两类构建都能跑通。
- 继续推进 GMAC 网卡驱动,但本周尚未完成。
- 建立
k3_ggml_bridge测试版,用于把 ggml/llama.cpp 侧 F32 MatMul 请求转成k3_aiRuntimegraph 提交。
V 扩展上下文支持
第三周已经确认 K3 的 IME 指令依赖 RISC-V V 扩展,因此本周首先补齐 V 扩展上下文支持。K3 上向量状态较大,如果任务切换时不保存向量寄存器和相关 CSR,多线程或多任务环境下会直接破坏 IME/向量计算结果。
实现上需要处理:
- 32 个向量寄存器的保存和恢复。
vl、vtype、vstart、vxrm、vxsat、vcsr等向量相关状态。- 新线程向量状态初始化,避免泄漏父线程或前一个任务的数据。
- 跨线程切换时的向量寄存器隔离。
测试程序使用 vlenb 自动读取硬件 VLEN,并以 m8 register group 覆盖全部 32 个向量寄存器。测试点包括同线程 sched_yield 恢复、新线程初始状态、worker 线程 yield 恢复和父子线程隔离。QEMU 和 K3 真板验证均通过,真板日志显示 ALL PASS。
这部分工作是 A100/X100 IME backend 的前置条件。如果没有 V 扩展上下文保存,单次 demo 可能能跑,但一旦进入多任务环境就不可靠。
串口驱动与真板调试支持
本周补齐了 K3 平台串口相关支持。串口驱动本身不属于 AI runtime 的核心逻辑,但它对真板 bring-up、内核日志、驱动调试和异常定位非常关键。
在 K3 真板上,UFS、GMAC、AI runner、V 扩展和 IME backend 的问题都需要依赖串口日志观察启动阶段和运行阶段的状态。串口支持稳定后,后续定位 DMA cache、设备初始化和线程亲和性问题的效率明显提高。
llama.cpp V 扩展与非 V 扩展运行测试
本周尝试编译 llama.cpp 的两类版本:
- 带 RISC-V V 扩展的版本。
- 不带 V 扩展的普通版本。
两类版本都分别放到 QEMU 和 K3 真板上运行 TinyStories/TinyStory 类小模型,结果均能正常跑起来。这说明当前 StarryOS 真板环境已经具备运行更复杂用户态程序的基础条件,也验证了 V 扩展上下文支持没有破坏普通用户程序运行。
测试中也观察到一个现象:QEMU 上 V 扩展版本不一定更快,甚至可能因为模拟器开销和多线程同步开销表现更差。因此 QEMU 更适合做功能验证,真实性能判断仍需要以 K3 真板为准。 但是在k3板子上用v扩展到速度就快得多
root@starry:/root # ./llama_cli_vector_extention -m story.gguf -t 1
Loading model...
▄▄ ▄▄
██ ██
██ ██ ▀▀█▄ ███▄███▄ ▀▀█▄ ▄████ ████▄ ████▄
██ ██ ▄█▀██ ██ ██ ██ ▄█▀██ ██ ██ ██ ██ ██
██ ██ ▀█▄██ ██ ██ ██ ▀█▄██ ██ ▀████ ████▀ ████▀
██ ██
▀▀ ▀▀
build : b9845-d9df11006
model : story.gguf
modalities : text
available commands:
/exit or Ctrl+C stop or exit
/regen regenerate the last response
/clear clear the chat history
/read <file> add a text file
/glob <pattern> add text files using globbing pattern
> hi
It was a popular place. All the other boats were there too. They were all different colors and had bright, round faces on their sails.
The other boats saw the popular boats and started to sail away.
They sailed fast and fast across the waters. All around them were so much fun to see!
Soon it was time to go home. The boats were going too fast and the boats were going faster and faster.
The boats got frustrated. They couldn't move and soon they were stuck in the same spot.
The boats were too fast and they couldn't stop. They crashed into the boat and it exploded.
The boats were stuck in the same spot. They were stuck and could not move anymore.
The boats were stuck forever and never moved again. Once upon a time, there was a little girl called Lily. She liked to play with her toys all around her room. She had a big toy box with many toys.
One day, Lily was playing with her toys and she noticed that one of them
[ Prompt: 197.5 t/s | Generation: 59.3 t/s ]
>
Exiting...
GMAC 驱动推进
本周继续推进 K3 GMAC 网卡驱动。该驱动对后续模型、日志和测试文件传输很有价值,但驱动涉及 MAC、DMA descriptor、PHY/link 状态和 cache 同步等多个环节,本周尚未完成。
当前结论是:GMAC 仍处于开发中状态,短期内真板复现仍主要依赖 UFS/rootfs、串口和手动拷贝方式。后续会继续推进 GMAC,使开发板具备更方便的网络调试和文件传输能力。
这份镜像用于配合 K3 真板启动和 AI runtime 相关模块验证。具体刷写方式仍取决于开发板当前分区和启动介质,复现文档中会继续说明 rootfs 分区、fastboot 和 UFS 相关注意事项。
本周问题与判断
- 平台侧工作耗时超出预期:最初预期 K3 平台侧适配已有其他人接手,但实际 AI runtime 要上真板,必须临时补齐 UFS、串口、V 扩展、DMA cache 等基础能力。
- V 扩展是 IME backend 前置条件:不补上下文保存恢复,A100/X100 IME 路径无法在真实多任务环境中安全使用。
后续工作
- 继续推进 GMAC 驱动,争取让 K3 真板具备网络调试和文件传输能力。
- 将
k3_ggml_bridge从测试版推进到真实 ggml backend 接入点。 - 将 A100 IME MatMul 探针路径收敛到正式 backend candidate。
- 整理 rootfs 镜像和真板复现步骤,保证
root_fs.img与文档说明一致。
第五周周报(7.20-7.26)
本周工作集中在 k3_kernel_backend 一侧的算子补全上:以 YOLO26x 推理所需的算子集合为目标,把 YOLO 计算图实际走到的所有算子在用户态 backend 中实现,并补齐它们在 RISC-V V 扩展下的实现与量化支持。算子库本身仍以 host 端 native 代码和 QEMU 上的真实算子调用作为正确性验证手段。
注意: 周报这里提及的API不代表后续API接口一定不变(至少下次周报更新之前不会变动),请以实际代码为准.
本周工作概览
本周主要完成和推进了五件事:
- 用 ONNX 解析 + 大模型计算图分析的方式确认 YOLO26x 推理所需的最小算子集合,并据此安排补全顺序。
- 在
k3_kernel_backend中实现并补全transform(Tensor 搬运、索引与 shape 变换算子)一组算子,部分算法在 RISC-V V 扩展下走 RVV 向量实现。底层向量原语集中收敛在rvv.rs。 - 补齐归约、池化与模型常用 NN 算子(Softmax、RMSNorm、RoPE、GLU/SwiGLU、MaxPool、ReduceMax、TopK),其中 Softmax / RMSNorm / RoPE / MaxPool / ReduceMax 的内部 hot loop 在向量 target 下走 RVV。
- 在
matmul算子上补完量化支持:I8/U8 → I32 走 IMEvmadot(X100/A100),ggml Q8_0 / Q3_K / IQ4_NL × F32/F16 → F32 走 dequantize + CPU matmul;F16 × F16 → F16/F32 在 A100 上通过a100-fp16-imefeature 走smt.vfwmadot。 - 实现二维卷积算子(
conv2d):F32、F16、I8/U8 三种 dtype 路径,覆盖 im2col + matmul 复用 matmul 引擎,int8 走 IME vmadot、F16 在 A100 上走流式 im2col +smt.vfwmadot。
本周问题与判断
- 量化支持补全只覆盖 ggml 量化块 + I8/U8 的 LHS:matmul 现在能处理 Q8_0 / Q3_K / IQ4_NL × F32/F16 的 LHS 量化场景,但 RHS 量化、
Q4_0、K-quant 全家桶等还没接上,ggml 端如果 weight 用 Q4_0 / Q4_K 等格式需要先把 Q4 系列 dequantize 补完。 - A100 FP16 IME 当前不默认开:feature
a100-fp16-ime仍受MCPM.BF16控制约束,conv2d / matmul 在该 feature 未开时 F16 走 CPU 标量路径,性能上不去;接入到真实 LLM 推理之前需要先把MCPM.BF16的控制路径打通。 - ggml backend 接入完整 LLM 模型失败:当前对 LLM 推理整条管线理解不足,无法快速定位卡点。下一步要么先把 ONNX/ggml 算子集合在 K3 上做一次完整对照(看哪些 ONNX 节点没接到 bridge),要么用更小的子图(例如只跑 token embedding + 1 层 transformer)来分阶段定位。
YOLO26x 算子集合探测
YOLO26x 本身是一组 Ultralytics 官方 ONNX 图,常见 backbone + neck + detect head 的组合在 K3 端的运行需要 backend 提供一组相对完整的算子集合。本周先做“算子集合探测“再决定补全顺序:
- 通过 ONNX 解析读取节点类型、输入/输出 shape、属性,把 YOLO26x 的节点表 dump 出来。
- 把这张节点表交给大模型,让它按 ONNX 语义归纳“YOLO26x 推理实际调用到的算子集合 + 这些算子互相之间是否能拆解或合并“,并给出最小集。
- 按最小集对照当前
k3_kernel_backend已有算子,列出缺口,按“上游依赖 → 下游依赖“的顺序安排补全。
Transform:Tensor 搬运、索引与 shape 变换算子
transform.rs 这一组算子是后面所有算子读 / 写带 stride 输出的基础,因此本周先补齐。实现位于 k3_kernel_backend/src/transform.rs,分发入口在 k3_run_kernel 中按 KernelOp 路由:
Concat:按指定 axis 拼接多个输入,输出连续后写回可能带 stride 的 output。Transpose:按perm重排维度,输出 shape 与 perm 一一对应。Gather/GatherElements:ONNX 语义下的两种 gather,支持负数 index 自动归一化。GetRows/SetRows:GGML 风格的 embedding lookup 与 KV cache row 写回。GetRows额外支持 data 为 Q8_0 / IQ4_NL / Q3_K 量化块、输出升精度到 F32/F16。Copy:通用 tensor 拷贝 / materialize contiguous。Cast:覆盖 F32 ↔ F16、F32 ↔ I32 等常见组合;I32 ↔ F32 在向量 target 下走 RVV。Resize:ONNX 2D resize,支持 nearest / linear、half_pixel / asymmetric / align_corners 三种 coordinate mode,linear 模式下双线性插值在向量 target 下走 RVV 二元算子。Expand/Tile:ONNX 的 broadcast expand 和 repeats tile,统一收敛为单次 indexed gather。
RVV 下的实现
实现上,几条“逐元素 + 按 byte 偏移搬移“的路径在向量 target(PREFER_X100 / PREFER_A100)下都收敛到 rvv.rs 里的向量原语:
copy_bytes、gather_bytes:按 byte 偏移做固定宽度元素 gather。RVV 路径下用 vle8 / vse8 + indexed load 写,RVV 不可用时回退到copy_from_slice。cast_i32_to_f32/cast_f32_to_i32:I32 ↔ F32 的向量 cast,RVV 路径下用vfcvt系列指令。
所有 RVV 内联汇编都集中在 rvv.rs 里,硬件路径使用 vsetvli + vle*.v / vse*.v 的 VLA 形式。其他 target 走同语义的标量 / slice 镜像,便于 host 端单测。
归约、池化与模型常用 NN 算子
nn.rs 一组算子集中在 k3_kernel_backend/src/nn.rs,覆盖 Transformer / 检测头里常用的几类算子:
Softmax:数值稳定版exp(x - max),按任意 axis 展开,inner/outer 维度按 broadcast 处理。支持可选 mask 输入(broadcast 到 input)。在向量 target 下,shifted / exp / scale 三个步骤都走 RVV:affine_f32、exp_f32、reduce_max_f32、reduce_sum_f32。RMSNorm:标准x * rsqrt(mean(x²) + eps) * weight公式,weight 缺省时退化为单位权重。在向量 target 下平方、求和、缩放都走 RVV。RoPE:BSHD dense/strided 张量,支持 GPT-J / NeoX 两种 mode、frequency_base / frequency_scale / attn_factor 等参数;position 可由外部positionstensor 给出。sin/cos 系数按 position 算好之后,旋转乘加统一在 RVV 下做。GLU:当前 v1 仅支持OP_SWIGLU,同时支持 split(输入 axis 0 一半左一半右)和两路独立输入两种形式。MaxPool:NCHW 2D 最大池化,支持 kernel / stride / dilation / padding / ceil_mode,可选第二个 I64 indices 输出。在向量 target 下窗口最大值归约走rvv::reduce_max_f32。ReduceMax:多 axis 归约,支持keepdims和noop_with_empty_axes两个 flag。TopK:当前保留 CPU 实现,largest=true 时按值降序、相等时按下标升序,保证 tie-breaking 稳定。
这几条算子的 dtype 当前都收敛在 F32 / F16 上。
矩阵乘法算子与量化支持补全
matmul.rs 是算子库的核心,量化支持补全主要落在这一块。dtype 分发在 matmul_caller 中按 (input0_dtype, input1_dtype, output_dtype) 路由到具体实现(k3_kernel_backend/src/matmul.rs:144):
| LHS | RHS | OUT | 计算落点 |
|---|---|---|---|
| F32 | F32 | F32 | CPU 软件 matmul(IME F32 matmul 尚未实现) |
| F16 | F16 | F16 / F32 | CPU 软件 matmul;A100 上 a100-fp16-ime feature 启用 smt.vfwmadot |
| F16 | F32 | F32 | CPU 标量 matmul(F16 → F32 单次解码) |
| I8 / U8 | I8 / U8 | I32 | CPU 软件 matmul;X100 / A100 走 IME vmadot,按 (I8/U8, I8/U8) 自动选 4 种符号变体 |
| ggml quant(Q8_0 / Q3_K / IQ4_NL) | F32 | F32 | quant.rs dequantize + CPU matmul |
| ggml quant(Q8_0 / Q3_K / IQ4_NL) | F16 | F32 | quant.rs dequantize + CPU matmul |
几个关键点:
- I8/U8 输入按 byte 切片直接交给 IME
vmadot指令,不强制 LHS / RHS 同号;符号组合由signedness_for根据左右 dtype 推VmadotSignedness。 - 量化块的 dequantize 走
k3_kernel_backend/src/quant.rs:Q8_0(block 34B)、IQ4_NL(block 18B + 非线性查找表)、Q3_K(block 110B + 6bit scale + 高位 hmask)三套都按 ggml 规范实现。 - A100 FP16 IME 当前默认不开,需要
a100-fp16-imefeature 并在 caller 中显式控住MCPM.BF16=0;否则返回BackendErr::UnsupportedOp。 - X100 / A100 int8 tile 尺寸当前按实测
M=4, K=8, N=4选(与 A60 一致),与 A100 手册的M=8, K=16, N=8暂时不一致的取舍写在源码注释里。
二维卷积算子
conv2d.rs 走 im2col + matmul 的标准套路:权重视作 [Cout, Cin*KH*KW] 矩阵,im2col 把输入每个输出点的感受野展开成 [Cin*KH*KW, Hout*Wout] 矩阵,二者相乘得 [Cout, Hout*Wout] 输出。dtype 分发(conv2d_caller,k3_kernel_backend/src/conv2d.rs:142):
| input | weight | output | 计算落点 |
|---|---|---|---|
| F32 | F32 | F32 | im2col + CPU F32 matmul |
| F16 | F16 | F16 | im2col + matmul;A100 上 a100-fp16-ime 走流式 im2col + smt.vfwmadot |
| I8 / U8 | I8 / U8 | I32 | im2col + IME vmadot(X100 / A100) |
支持的属性:NCHW 输入/输出 layout、groups(深度可分离卷积)、dilation、stride、padding、可选 bias。当前 backend 层不做 layout 转换,调用方需要把 NCHW 准备好。
ONNX 二元 elementwise 算子
binary.rs 实现 ADD / MUL / SUB / DIV / MOD 五种 ONNX 二元 elementwise 算子,语义由 KernelOp 区分。ADD / MUL / SUB / DIV 在向量 target 下统一走 rvv::binary_f32(vfadd.vv / vfmul.vv / vfsub.vv / vfdiv.vv),支持 ONNX 的右对齐 broadcast 规则;MOD 按约定保留 CPU 实现(不支持向量)。
unary.rs 的 SILU / SIGMOID / SCALE 与 binary 共用 broadcast 体系,但属于单输入 elementwise,不是本周 outline 里的“二元“,因此单独放在 unary 一侧。SILU / SIGMOID 走 RVV 下的 affine_f32 + exp_f32 + 倒数。算子库内 / k3_test 的 dispatch 中这两类算子的入口独立。
测试
单算子正确性测试
算子库内部每个模块(rvv.rs / transform.rs / nn.rs / binary.rs / unary.rs / matmul.rs / conv2d.rs / quant.rs)都附了独立 #[cfg(test)] mod tests,覆盖 happy path、边界条件、与参考实现的数值一致性。
k3_test(位于 k3x-HERA-RT 仓库根目录的 k3_test/ crate,其集成测试入口在 k3_test/src/main.rs)的 host / QEMU 集成测试在 QEMU 上把每个算子通过 k3_run_kernel 真实跑一遍,方式是:
- 给定同样的输入。
- 一份用
k3_kernel_backend实际算子调用执行。 - 一份用 Python 的 numpy / 标准参考实现执行(量化测试的参考在
k3_test/scripts/host_quant_ref.py)。 - 对比输出,结果完全一致则通过。
k3_test 当前覆盖的算子包括 binary (ADD / SUB / MUL / DIV / MOD)、unary (SILU / SIGMOID / SCALE)、conv2d (F32 sum / F32 depthwise+bias / int8 sum)、nn (Softmax / RMSNorm / RoPE / SwiGLU / MaxPool / ReduceMax / TopK)、transform (Concat / Transpose / Gather / GetRows / SetRows / Copy / Cast / Resize / Expand / Tile)、rvv (RVV binary mul / affine)、matmul (CPU int8)、以及量化 (Q8_0 get_rows / Q8_0 matmul / IQ4_NL matmul / Q3_K matmul)。test_quantized_ops 在跑集成测试之前单独验证 ggml 量化块的 dequantize + matmul 路径。
ggml backend 接入测试
尝试把算子库接入 ggml backend,跑 tinystories.gguf 这种小模型做完整数据通路验证。具体做法是利用 AI 把 k3_ggml_bridge(基于现有 C ABI bridge)接到 ggml backend 上,让 F32 MatMul 请求转成 K3 graph 提交。
结果:失败。在相同的 seed / temperature / 输入 token 下,模型输出与预期不一致。中间某一步少东西,但具体卡在哪一步目前没有完全定位。
排查的初步判断:当前对 LLM 大模型推理的整条流水线理解还比较弱,无法立刻锁定是 prompt tokenization、position embedding、KV cache、sampling 还是某个算子语义的问题。怀疑是中间少了一个或几个 ggml 节点(例如某个隐式的 Reshape、Slice、或 group_norm 类的算子)没有接到 bridge 上。
数据通路测试改用本地测试集
在 ggml 接入未能跑通完整模型之前,把数据通路测试改回 k3_test 内部的端到端测试集:把上面列出的所有算子按“上游 → 下游“顺序串成多算子 graph(matmul → activation → reshape → …),用与单算子测试同样的 host 端参考实现做对比。这部分对应仓库里 k3_test/src/main.rs 中的 run_binary_tests / run_unary_tests / run_conv2d_tests / run_nn_tests / run_transform_tests / run_rvv_tests 这一组集成函数,以及 test.rs 里的 test_quantized_ops / test_cow_live 两组量化与共享内存保活测试。
这条路径覆盖了 YOLO26x 当前能跑到的所有算子类型(除了 GGML 接入这一段),可以保证算子库本身的算子语义和数据通路是自洽的。
第六周周报(8.2-8.8)
本周暂缓 K3 AI core 驱动开发。当前影响后续工作的主要问题不是 AI core 驱动本身,而是底层基础设施仍不完善。因此,本周工作重点转向补齐 K3 的 USB、DMA/cache 一致性和中断平台支持,为后续 AI runtime 和上层设备驱动提供稳定的运行基础。
本周工作概览
本周主要完成和推进了三项基础设施工作:
- 为 K3 接入 DWC3 兼容层,为上层
crabusb驱动提供可靠的 DWC3 控制器支持。 - 基于 RISC-V Zicbom 扩展为 K3 实现缓存一致性工具,并在 UFS 驱动中使用,修复 UFS 驱动中的 cache 不一致问题;同时打通 UFS 链路,并在 NOP OUT 成功后建立高速通信链路。
- 将郑昱实现的 APLIC 及其他中断平台驱动接入 Starry,补齐 K3 平台中断控制相关的基础支持。
K3 DWC3 兼容层
本周为 K3 接入 DWC3 兼容层,目标是把 K3 实际的 USB 控制器能力适配到上层通用的 DWC3 驱动接口,为 crabusb 提供稳定的控制器访问路径。
这项工作主要解决了平台控制器和上层 USB 驱动之间的适配问题,使上层驱动不需要直接依赖 K3 的平台细节。完成兼容层接入后,后续可以在相对统一的 DWC3 控制器模型上继续调试 USB host、设备枚举和传输流程。
当前 USB 设备枚举链路仍存在问题,设备还不能稳定完成完整枚举。问题正在进一步排查,后续需要结合控制器初始化、端口状态变化、枚举请求和传输完成状态逐段定位。 应用
不同板子的具体区别
│ ├─ U盘驱动 / HID鼠标 / UVC摄像头 / USB串口 │ ↑ │ 基本通用 │ ├─ USB core │ 枚举、descriptor、endpoint、control transfer │ ↑ │ 基本通用 │ ├─ Host Controller Driver │ xHCI / EHCI / OHCI / DWC2 … │ ↑ │ 看控制器类型 │ ├─ SoC platform glue │ clock / reset / IRQ / DMA / power / syscon │ ↑ │ SoC差异巨大 │ ├─ PHY │ USB2 PHY / USB3 PHY │ ↑ │ SoC差异巨大 │ └─ USB物理接口
APLIC 与中断平台驱动接入 Starry
本周将郑昱实现的 APLIC 以及其他中断平台驱动接入 Starry,补齐 K3 平台的中断控制和平台中断分发支持。
这部分工作为后续设备驱动提供了必要的中断基础。USB 控制器、UFS 控制器以及其他外设都依赖正确的中断路由和处理流程,APLIC 接入后,Starry 可以进一步在统一的平台中断框架下承接这些设备的中断事件。
本周问题与判断
- USB 设备枚举链路存在问题:DWC3 兼容层已经接入,但 USB 设备枚举尚未稳定完成。目前正在从控制器初始化、端口状态、枚举请求和传输完成状态等环节逐段排查。
- K3 的 non-coherent DMA 需要显式维护 cache 一致性:本周 UFS 问题表明,DMA cache 操作是 K3 平台驱动正常工作的基础设施,而不是某个单独驱动的局部细节。后续新接入的 DMA 设备都需要明确 cache clean/invalidate 的边界。
- AI core 驱动暂缓推进:在 USB、DMA/cache 和中断等基础设施尚未稳定之前,继续推进 AI core 驱动会增加联调成本。因此本周先集中补齐平台基础能力,待底层运行环境更可靠后再恢复 AI core 驱动开发。
后续工作
- 继续排查 USB 设备枚举失败问题,确认 DWC3 控制器初始化、端口状态变化和控制传输链路是否符合预期。
- 继续完善 K3 non-coherent DMA 的使用规范,将 Zicbom cache 同步工具推广到 USB、GMAC 等其他 DMA 设备驱动。
- 基于已经接入的 APLIC 和平台中断驱动,继续验证 USB、UFS 等设备的中断处理路径。
- 待基础设施稳定后,恢复 K3 AI core 驱动开发,并继续推进 AI runtime 的真板验证。
第七周周报(8.9-8.15)
本周工作主要集中在 K3 官方 Runtime 调度行为的黑盒实验、PMU 观测基础,以及 USB 驱动的 DMA/cache 一致性问题上。AI Runtime 方面暂时不直接修改 Scheduler,而是先在 K3 Ubuntu 环境下使用官方 ONNX Runtime + SpaceMIT Execution Provider 跑真实推理,通过 E0-E3 对照实验观察 Runtime 对外部负载和内部任务状态的响应;USB 方面则继续解决上一周遗留的枚举问题,最终通过 Svpbmt 处理控制器频繁访问的 DMA ring 和相关结构体,使上层 crabusb 链路跑通。
本周工作概览
本周主要完成和推进了三项工作:
- 在 K3 Ubuntu 上使用
onnxruntime_perf_test、SpaceMIT Execution Provider 和量化 YOLOv8n 模型搭建 Runtime 黑盒调度实验,按 E0-E3 四组场景区分 Runtime 内部负载和 Runtime 外部硬件负载。 - 使用 Linux
perf对 CPU8-15 的instructions/cycles做周期采样,并整理 K3 PMU Raw Event 的使用和映射,形成 K3 RawPerfEvent 映射文档。 - 修复 K3 USB 驱动的 DMA/cache 一致性问题。对 USB 控制器会频繁读写的 ring 区和相关 DMA 常驻结构使用 Svpbmt 提供合适的内存属性,修复此前控制器和 CPU 看到的数据不一致问题;修复后上层
crabusb已可以正常继续枚举和传输流程。
K3 Runtime 黑盒调度实验
目前 K3 官方 Runtime 的具体 Scheduler 实现仍然不完全透明,因此本周先不假设它内部究竟使用了队列长度、CPU 利用率还是其他指标,而是从外部构造不同负载组合,观察 Runtime 最终把推理工作放到哪些核,以及对应的吞吐和延迟如何变化。
测试环境使用 K3 Ubuntu,推理侧使用官方 ONNX Runtime 的 SpaceMIT Execution Provider,模型为量化后的 YOLOv8n:
onnxruntime_perf_test
yolov8n_no_dfl.q.onnx
-e spacemit
SPACEMIT_EP_INTRA_THREAD_NUM=1
SPACEMIT_EP_INTER_THREAD_NUM=1
同时使用 perf stat -I 对 CPU8-15 周期采样 instructions 和 cycles,把 Runtime 的实际执行位置和外部负载放在同一条时间线上观察。
E0-E3 实验设计
| 编号 | 实验场景 | Runtime 内部负载 | 外部硬件负载 | 主要观察点 |
|---|---|---|---|---|
| E0 | Baseline:只运行单个 ONNX 推理任务 | 低 | 低 | 记录无干扰时的默认执行位置、吞吐和延迟 |
| E1 | External hog:Runtime 外单独启动负载,并逐核移动 | 低 | 高 | 看 Runtime 是否能感知自身队列之外的硬件占用,以及执行位置是否随外部负载变化 |
| E2 | Runtime workload:通过 Runtime 自身持续提交更多推理任务 | 高 | 高 | 区分 Runtime 已知的内部任务压力和真实硬件忙碌程度 |
| E3 | Waiting workload:在 Runtime 内形成等待任务,同时尽量保持硬件低负载 | 高 | 低 | 看 Runtime 能否区分“队列很长”和“硬件真的很忙” |
这组实验的核心不是单纯把 CPU 打满,而是把“Runtime 自己知道多少任务”和“硬件实际上有多忙”拆开。后续如果要修改 Scheduler,就可以先判断现有策略到底缺的是队列信息、外部负载信息,还是更细的任务特征信息。
当前 E0 / E1 结果
E0 无外部干扰时,100 次推理的平均延迟约为 52.68 ms,吞吐约为 18.98 inference/s,可以作为当前官方 Runtime 的基准。
E1 中把一个 Runtime 外部的负载进程固定到 CPU8-15,并在 8 个 round 中逐核移动。当前结果里最明显的一点是:外部负载位置变化后,推理侧的活跃核分布和性能会随之变化,并不是始终固定在同一个执行位置。以外部负载位于 CPU8 的一轮为例,平均推理延迟上升到约 107.41 ms,吞吐下降到约 9.31 inference/s;当外部负载移动到其余核后,多数组合又回到约 53 ms、18.6-18.8 inference/s 的范围。
这说明当前官方 Scheduler 至少存在对 Runtime 外部硬件负载产生响应的能力。目前仍不能仅靠黑盒数据确认它内部具体读取的是 CPU utilization、某种 cluster 状态、Runtime 统计信息还是其他指标,因此这里暂时不对实现机制下结论。
这个结果也修正了后续工作的方向:后面没有必要从“Scheduler 完全看不到外部负载”这个假设重新做一套检测机制,而应该进一步确认它现有感知能力的粒度和缺口。下一步更值得测的是:
- 同样的负载率下,计算密集和内存密集任务是否会被 Scheduler 区分;
- 外部负载位于同 cluster 和不同 cluster 时,对推理延迟的影响是否有稳定差异;
- PMU 的 stall、cache / memory 等指标能否比单纯的 busy/idle 更早反映资源竞争;
- 如果现有 Scheduler 只能看到“忙不忙”,是否可以在此基础上增加 workload 类型和干扰强度信息。
目前计算密集 / 内存密集的细分对照还没有完成,因此现阶段只能确认“存在外部负载响应”,还不能说明 Scheduler 已经具备 workload-aware 或 PMU-aware 的调度能力。
K3 PMU 与 Raw Event 整理
为了让后续实验不只依赖 htop 或最终推理时间,本周继续整理 K3 上可以稳定读取的 PMU 事件,并把验证结果写入 K3 RawPerfEvent 映射文档。
当前在 K3 Ubuntu 上已经可以通过 Linux perf 对指定核做周期采样,并用微基准交叉验证部分 raw event。现阶段确认 cpu/event=0x03/、cpu/event=0x04/ 与 stalled-cycles-frontend、stalled-cycles-backend 的统计行为能够对应,后续会继续补 cache、memory 和其他可能与资源竞争有关的事件。
这部分工作的目的不是单独做 PMU benchmark,而是给后续 Scheduler 实验提供统一的数据来源:先用 E0-E3 把调度行为分出来,再观察同一时间窗口内 PMU 是否出现稳定差异,最后再决定哪些事件值得真正进入调度策略。
USB:使用 Svpbmt 修复频繁 DMA 访问结构的一致性问题
上一周 USB 已经完成 DWC3 / Host Controller 相关兼容层接入,但枚举链路仍然会在控制器和 CPU 共享的数据结构上出现问题。本周继续排查后,问题集中到 USB 控制器频繁访问的 DMA ring 和相关结构体。
这类内存和普通的一次性 DMA buffer 不太一样:ring、context 等结构会长期存在,并且 CPU 和设备都会频繁读写。如果完全依赖软件在每次所有权变化时做 cache clean / invalidate,很容易遗漏某个同步点。
本周针对这部分常驻 DMA 结构使用 Svpbmt 设置合适的内存属性,使控制器和 CPU 对 ring / context 的观察保持一致。修复后,之前 USB host 在枚举过程中出现的卡死问题消失,上层 crabusb 可以继续完成设备枚举和后续控制传输流程。
目前 USB 软件栈已经从“控制器能检测设备变化”推进到上层 crabusb 可以实际跑通枚举链路。下一步计划通过 USB 接口控制小车,但这部分本周还没有进行实际尝试。
本周问题与判断
- 官方 Scheduler 并不是完全只看 Runtime 自己的任务队列:E1 的外部负载实验已经能观察到调度行为随外部占用变化。后续重点应从“有没有外部负载感知”转到“感知粒度够不够”。
- 当前实验还不能区分 workload 类型:现阶段 external hog 主要用于制造确定的占用,还没有完成计算密集、内存密集等更细的干扰分类,因此不能直接判断现有 Scheduler 是否已经考虑 cache / memory contention。
- PMU 可以作为下一阶段的补充信号,但需要继续校准:目前已经建立基本的
perf采样和 raw event 映射,后续需要先确认事件稳定性、采样窗口和 multiplexing 影响,再考虑放进调度决策。 - USB 的 DMA 内存不能全部按同一种方式处理:一次性流式 buffer 可以继续使用显式 cache 同步,但 controller ring、context 等高频共享结构更适合通过 Svpbmt 明确内存属性。两类 DMA 场景需要分开处理。
后续工作
- 在 E0-E3 框架上继续增加计算密集、内存密集 workload,验证现有 Scheduler 是否只能感知 busy/idle,还是能够识别更细的资源竞争。
- 继续完善 K3 PMU 事件表,重点寻找 cache miss、memory stall、pipeline stall 等对异构调度有实际价值的指标,并测量采样开销和稳定性。
- 根据实验结果重新确定 Runtime Scheduler 的修改位置,优先补现有策略缺失的信息,而不是重复实现已经存在的外部负载检测。
- 在 USB 枚举链路已经跑通的基础上继续验证实际设备传输,并尝试通过 USB 接口驱动小车。
关于 K3 异构 AI Runtime 调度的一些调研和想法
这篇文档整理了我最近对 K3 异构 AI Runtime 的调研和一些实验想法。最后一部分是我对 SpineRuntime / X100 Runtime 调度相关源码的开放建议。
资料核对日期:2026 年 8 月 11 日。
我想研究什么
我目前在进迭时空 K3 平台上做异构 AI Runtime 和动态调度实验。目前最关心的问题是:
在沿用 K3 官方 Tile-SPMD / A100 Task 执行模型的前提下,Runtime 能不能结合 A100 的队列和资源状态、PMU / Trace 反馈、OS 提供的资源信息,为多模型、多进程 workload 更灵活地分配 A100 计算资源?
简单来说,我想看 Runtime 在“当前哪个核更空闲”之外,能否知道“当前哪个核更适合这个任务”。
AI workload
↓
SpineRuntime / X100 Runtime
↓
A100 计算资源
↑
Queue 状态 + PMU / Trace + OS 资源信息
当前困难
K3 AI 软件栈中与任务调度相关的实现和源码暂未公开。由于缺少 Task、Scheduler 和资源管理的内部接口,我在 StarryOS 上开展的工作暂时难以完整接入 K3 官方开发生态。
目前如果不公开的思路
我会继续使用自研算子库和 Runtime 推进实验,先跑通现有执行链路,再引入 PMU 数据,研究 queue-aware、PMU-aware 等动态调度策略。后续如果官方开放相关源码或扩展接口,再逐步适配 K3 官方 Runtime。
从公开资料里看到的 K3 Runtime
K3 论文里的调度方式
进迭时空的 K3 公开论文《SpacemiT K3: A RVA23 RISC-V AI CPU with 60 TOPS AI Compute》 对软件栈写得很清楚。ONNX Runtime 私有后端和 tile-based Triton 编译器最后会共用 Runtime、线程和内存优化体系。X100 Runtime 负责把产生的 tile-level task 送到 A100 执行。
论文公开版本里用了一个直观的策略:把 task 发给当前负载较低的 A100 cluster thread group。论文还提到了后续的 topology-aware scheduling。
这个策略可以作为我实验里的官方 baseline。它反映的是论文当时的实现。当前 libspert 里的算法可能已经有了变化,这一点还需要官方确认。
在 SpineRuntime / X100 Runtime 源码尚未公开的情况下,我准备先做一组黑盒实验,观察 Runtime 是怎样判断“核心负载”的。它可能只看自己的 workload 和队列深度,也可能会读取 Linux 报告的 CPU 利用率。更理想的情况是,Runtime 能识别计算型、内存型等任务特征,并结合 PMU 信息选择更合适的核心或 cluster。
| 编号 | 实验场景 | Runtime 内部负载 | 外部硬件负载 | 主要观察点 |
|---|---|---|---|---|
| E0 | Baseline:Runtime 和硬件都空闲 | 低 | 低 | 记录官方策略在无干扰时的基准行为 |
| E1 | External hog:用 Runtime 之外的任务占用硬件 | 低 | 高 | 看 Runtime 能否感知队列之外的实际硬件压力 |
| E2 | Runtime workload:通过 Runtime 提交并持续运行任务 | 高 | 高 | 看 Runtime 怎样记录已提交任务和实际 CPU 占用 |
| E3 | Waiting workload:在 Runtime 里堆积等待任务,尽量保持硬件空闲 | 高 | 低 | 看 Runtime 能否区分“队列很长”和“硬件很忙” |
目前已经知道SpineRuntime 已经公开了的能力
最新公开的 SpineRuntime 仓库和中文文档 已经给出了一套完整度很高的编程模型:
| 公开概念 | 我对它的理解 |
|---|---|
BackendHandle | 代表一个硬件 Backend,可以把 K3 和 generic/qemu 等环境分开 |
Stream | Runtime 分配多核资源和做资源隔离的主要单位 |
StreamConfig::core_ids | 应用可以提交偏好的物理核 ID |
Grid → Tiles | 把一次计算拆成多个 Tile 执行 |
Future | launch() 返回的异步完成标记 |
Barrier / Event / spawn / join / yield | Tile 可以等待、唤醒、创建子任务和协作式让出计算核 |
| Core Coordinator | 在多个 Stream 和多个进程之间分配计算核 |
runtime_stats() | 获取 Runtime 当前的资源快照,适合调试和测试 |
spert_abi.h | 给编译器、MLIR 等工具使用的 C ABI |
SpineRuntime 的资源竞争调度文档 还给了一个很具体的 FIFO 例子。一个先到的 4 核申请会继续等待,后到的 2 核申请即使碰巧有 2 个空闲核,也不会越过前面的申请。
如果试验确认除了非e3猜想再看看PMU是否能不能帮上忙(提供给我的数据能用到)
两组核的队列长度可能一样,实际压力却差得很多。例如,一组 workload 正在大量访问内存,另一组主要做计算。只看队列长度,Runtime 看不出这种差异。
我准备先让每类 task 单独运行,记下正常执行时间和可用的 PMU 数据。接着让不同 task 并发运行,看它们变慢了多少,同时观察 PMU 变化。如果这些信号确实能提前反映干扰,就可以尝试用它们预测任务执行时间,然后帮助 Runtime 选核。
已有工作中,Caladan 研究了微秒尺度的干扰检测和资源分配,OSML 使用 IPC、cache miss 和 memory footprint 等信息调整共置服务的资源。这些研究说明了这条路值得尝试,具体效果仍需要在 K3 上测出来。
PMU 数据也不能直接拿来就用。硬件 counter 数量有限,同时监测的事件太多时会发生 multiplexing。采样窗口太短也容易被 cache eviction 和 context switch 这类瞬时影响干扰。Linux perf_event_open(2) 专门提供了 time_enabled / time_running 来辅助估算 multiplexed event;OSDI 2025 的 Tintin 也专门讨论了计数器复用误差和数据归属的不确定性。
我会先把采样间隔、数据归一化、置信度和采样开销测清楚,避免用一次 PMU 差值直接决定任务去哪里执行。
K3 公开论文已经确认 X100 和 A100 都有独立的 RISC-V Trace encoder,支持 N-Trace 和 ownership event message。K3 / X100 的 Linux perf 目前也能读取部分 PMU 事件。不过,进迭论坛里的 PMU 事件映射讨论 显示,部分通用事件存在映射问题,详细 PMU 事件对照表也还没有对外提供。所以在实验前,需要先确认哪些 cache、memory、pipeline 或 vector event 真的可用。
X100 / A100 之间的迁移要考虑上下文兼容性
X100 和 A100 都属于 64-bit RISC-V 软件体系。这里主要需要处理 VLEN 和 ISA capability 差异。X100 的 VLEN 是 256,A100 的 VLEN 是 1024,它们对 Hypervisor 等扩展的支持也不完全相同。K3 论文明确提到,不同 VLEN 带来的 vector context 差异会限制跨核迁移。
RISC-V Vector 规范 也提到,带有 active vector state 的线程上下文,通常无法在 VLEN 或 ELEN 不同的 hart 之间执行中迁移。
我准备从约束更清楚的场景开始:
- 在 task / tile 开始前选好兼容的执行域;
- 调整尚未执行的 work descriptor 的位置;
- 在无活跃 vector state、显式 safe point 或 task boundary 上尝试跨域继续执行。
这样能先把 task placement 的基本问题测清楚,也可以避开 active RVV thread 直接迁移带来的硬件上下文限制。
希望进迭时空开放的内容
进迭时空团队您好:
我希望尽量在 K3 官方 task / runtime model 上做调度实验。这样可以直接复用已有的任务执行、同步和内存管理能力,也能让实验结果和官方软件栈保持兼容。
以下内容和 A100 Task 调度直接相关,对我的实验帮助最大:
libspert中spacemit-k3Backend 和 Runtime Scheduler 相关源码;- A100 Tile / Task 的 descriptor、内部状态和生命周期,包括 ready、running、waiting、completed 和 cancelled;
- Stream 创建、A100 compute-core grant / release,以及多 Stream / 多进程 Core Coordinator;
- Tile enqueue / dequeue、worker dispatch、core / resource selection、Future completion,以及 Barrier / Event /
spawn/join的调度逻辑; - Scheduler 用来判断 A100 load、availability、task placement 和公平性的状态与接口;
- 和安全调度有关的 scratchpad / TCM、memory dependency、AI-DMA 及其他资源约束接口;
- 如果条件允许,也希望公开 X100 / A100 上适合 Runtime profiling 和资源干扰分析的 PMU 事件定义、编码和已知限制;
- 让上述修改可以重新编译、链接和部署的必要源码、构建脚本、依赖接口和工具链说明。
最后这一项很重要。开放的调度代码需要形成可编译的闭环,这样才能把修改后的 Runtime 放回实验环境做真实验证。
完整 Runtime 如果暂时不方便开放,单独开放 spacemit-k3 Backend、Task model、Core Coordinator 和一个 reference scheduler,已经可以支持大部分调度实验。
我可以回馈哪些内容
实验主要会在 StarryOS 上完成,运行环境与 Linux / Bianbu 有差异。测试依然使用真实 K3 硬件和官方 Task 模型,可以为 Runtime 调度、PMU 观测和多 workload 竞争提供实机参考。结果中会清楚标注实验环境和适用范围。
我计划回馈以下内容:
- 可重现的 Benchmark、PMU / Trace 分析和调度策略对比;
- queue-aware、PMU-aware 等 Scheduler 原型和 StarryOS 适配经验;
- 可公开的实现、文档和实验结论。
相关成果会尽量回馈到进迭时空软件生态。同时,我也会将通用的 OS 机制、K3 适配和使用文档贡献给 StarryOS 社区。
最后
如果完整 Runtime 开源还需要时间,Scheduler extension point、Task / Resource headers、reference scheduler 和 PMU 事件定义中的任意一部分,都会对这项实验有很大帮助。
感谢阅读。
第八周周报(8.31-9.6)
本周工作集中在 ONNX Runtime K3 Execution Provider 推理链路、K3 Runtime 调度器和 USB 串口支持。推理侧先跑通纯 CPU 版本,再通过 Rust ort 库接入带 K3 EP 的 ONNX Runtime,使 YOLOv5n 节点可以进入 K3 Runtime 和自研 K3 backend 执行;Runtime 侧补充零拷贝 tensor、常驻 worker 和条件等待;USB 侧完成 QEMU 真机设备转发验证和通用 CDC ACM 虚拟串口驱动。
本周工作概览
- 使用 Rust
ort库跑通 YOLOv5n 的 CPU 推理、输出解析和检测框绘制,并接入带 K3 EP 的 ONNX Runtime,验证 K3 backend 可以执行模型节点。 - 为用户态 Runtime 加入 ORT tensor 零拷贝视图,修复 graph worker 完成后 kernel alias 未释放的问题;调度器改为每核常驻 worker,通过等待队列睡眠和唤醒。
- 优化连续 tensor 的 transform 和 concat 路径,减少逐元素地址换算和中间数据搬运。
- 在 QEMU 中完成 Linux Host USB 设备转发验证,实现 CH340 与通用 CDC ACM 虚拟串口设备驱动,分别控制机械臂和底盘车轮。
ONNX Runtime K3 EP 与 YOLOv5n
本周先使用纯 CPU Execution Provider 跑通 ort_learn 测试程序,确认图片缩放、NCHW 输入构造、模型加载、输出 tensor 解析、置信度筛选和 class-aware NMS 流程正确。随后通过 OrtSessionOptionsAppendExecutionProvider_K3 将 K3 EP 注册到 Rust ort 创建的 Session 中,使支持的 ONNX 节点通过 K3 Runtime 提交到 K3 backend 执行,并通过已执行节点计数确认 K3 路径实际生效。
当前测试使用 YOLOv5n,输入图片缩放到 640×640,输出按 [1, 25200, 85] 解析,最终生成带检测框的图片:
这次测试打通了 Rust ort -> ONNX Runtime K3 EP -> K3 Runtime -> Scheduler -> K3 backend 的完整调用路径,为后续增加算子覆盖和对比 CPU/K3 性能提供了可复用程序。
Runtime 零拷贝与调度器
ORT 传入的连续 tensor 现在可以建立非拥有的借用视图,直接把原始用户态 buffer 写入 tensor descriptor。graph 提交时由内核固定用户页面并建立 kernel alias,worker 完成计算后释放本次 graph 的全部 alias,再发送 completion,使调用方可以安全复用或释放原 buffer。这一调整减少了输入输出 staging copy,同时修复了 worker 结束后 alias 页面未释放导致的内核内存泄漏。
调度器进一步拆出每核常驻 worker。每个实际 CPU core 拥有独立 scheduler、ready queue 和 worker;提交任务后通过 notify_one 唤醒对应 worker,无任务时 worker 使用 wait_until 进入等待。StarryOS 侧同步完成等待队列适配,把 Runtime 的等待与唤醒接口接到内核调度能力上。
K3 backend 的 transform 路径也增加了连续内存快速处理:连续 tensor 可以直接复制逻辑字节,concat 可以按 axis 两侧的连续 block 搬运,保留非连续 stride tensor 的通用路径。
USB 串口进展
在已有 xHCI Host 枚举和 EP0 控制传输基础上,本周为 QEMU 打开 USB 支持,并通过 usb-host 转发 Linux Host 上的真实 USB 设备,完成 CH340 设备识别和串口通信验证。
CH340 设备的 VID/PID 为 1a86:7523,数据接口为 vendor-specific 0xff/0x01/0x02。当前 usb-serial 已能从 descriptor 中匹配该设备和 Bulk IN/OUT endpoint,并实现 CH341 vendor control IN/OUT、芯片版本读取、SERIAL_INIT、波特率分频和新版本 LCR 配置。StarryOS 目前提供 /dev/ttyUSB0,应用打开节点时匹配设备、claim interface 并初始化串口。该设备对应机械臂控制。
同时完成通用 CDC ACM 串口驱动。驱动解析 communication interface、data interface 及 Bulk IN/OUT endpoint,在打开设备时分别 claim 控制接口和数据接口,通过 SET_LINE_CODING 设置串口参数,再进入统一的串口收发路径。StarryOS 提供 /dev/ttyACM0,该设备对应底盘车轮控制。机械臂和底盘已经可以分别得到控制,并在 QEMU USB 转发环境中完成验证。
目前还缺少通用 UVC 摄像头驱动。待支持设备为 1e45:8022 Suyin HD Camera,Linux 侧由 uvcvideo 驱动处理,设备包含两个 Video interface:Interface 0 和 Interface 1。
本周问题与判断
- K3 EP 已能通过真实 YOLO 模型进入 backend,后续还需要继续扩大算子覆盖,并对 CPU/K3 的结果和性能做稳定对照。
- 零拷贝 tensor 的生命周期必须覆盖 graph completion;alias 释放必须发生在 worker 停止访问 tensor 之后、completion 发出之前。
- CH34x 和 CDC ACM 的识别、接口占用、串口初始化及基础收发已经打通,后续继续完善设备状态处理和机械臂、底盘控制协议。
后续工作
- 完善 ORT K3 EP 的算子覆盖、错误诊断和 CPU/K3 对照测试。
- 继续验证多核 worker、等待唤醒和异常完成路径,观察调度开销与内存释放行为。
- 参照 SG2002 UVC 实现和 Linux
uvcvideo驱动,完成1e45:8022 Suyin HD Camera的通用 UVC 驱动,覆盖两个 Video interface、视频格式协商、控制请求和视频流接收。 - 完善 CH34x 与 CDC ACM 的状态处理和多设备索引,继续测试机械臂和底盘控制命令。
第九周周报(9.7-9.12)
本周工作集中在 USB 设备自动匹配和 UVC 摄像头发现链路。USB host 在完成设备枚举、读取设备和配置描述符后,现在可以生成统一的 device/interface 描述对象,使用注册的 USB ID 表匹配驱动,并在 probe 成功后记录 interface 的逻辑认领状态。基于这条链路,为板上的 Suyin HD Camera 增加了一个名为 uvcvideo 的薄驱动,用于验证 UVC 设备的自动发现和匹配。
本周工作概览
- 在
crab-usb中增加统一的 USB interface driver binding 机制。 - 将 VID/PID、interface class、subclass 和 protocol 封装为
UsbId匹配规则,None表示通配符。 - 增加
UsbDevice、UsbInterface、UsbDriver、UsbIdEntry和UsbDriverRegistry,串起枚举、匹配、probe、claim 和 disconnect 生命周期。 - 在
ax-driver中增加uvcvideo薄驱动,精确匹配1e45:8022的 Video Control 和 Video Streaming interface。 - 调整 QEMU RISC-V 配置,保留 QEMU monitor socket,便于 USB 测试和调试。
- 在 K3 板上验证 Suyin HD Camera 的端口连接、USB enumeration、两个 Video interface 匹配和逻辑认领。
USB 自动 probe 设计
USB host 端已经存在 xHCI 端口变化检测和设备枚举流程。本周没有改动 xHCI 的底层端口检测,而是把 driver binding 接到通用 USBHost::probe_changes() 入口,使 xHCI、DWC2、EHCI 和其他 host backend 可以复用同一套匹配逻辑。
当前调用链如下:
xHCI 检测 port connect
↓
USB enumeration
↓
AddressDevice / GET_DESCRIPTOR / SET_CONFIGURATION
↓
生成 UsbDevice 和 UsbInterface
↓
遍历 USB driver registry
↓
UsbId::matches()
↓
UsbDriver::probe(interface)
↓
probe 成功后 interface 记录 driver
UsbId 只保留当前最需要的字段:VID、PID、interface class、subclass 和 protocol。设备级字段从父级 UsbDevice 读取,class 相关字段从 UsbInterface 读取。这样既可以表达 UVC 的 class 匹配,也可以表达 CH340 一类的 VID/PID 匹配。
UsbDriverRegistry 使用扁平的 UsbIdEntry 列表保存 ID 到 driver 的关系。匹配成功并不立即认领,必须先执行 probe();如果 probe 返回错误,USB core 会继续尝试下一个匹配项。只有 probe 返回成功后,interface 才会记录绑定的 driver。设备断开时,host 根据设备逻辑 ID 找到已绑定的 interface,并调用 driver 的 disconnect 生命周期。
uvcvideo 薄驱动
本周在 ax-driver/src/usb/uvcvideo.rs 中加入了用于验证发现链路的薄驱动,driver 名称为 uvcvideo,ID 表覆盖该设备的两个 Video interface:
VID = 0x1e45
PID = 0x8022
Interface = 0x0e Video
Subclass = 0x01 Video Control
Protocol = wildcard
它在 USB host 创建时注册到 USBHost,因此首次拓扑扫描前就已经具备匹配规则。probe() 目前只输出设备 ID、interface 编号、alternate setting 和 endpoint 数量,然后完成逻辑 claim;它不会打开 live Device、不会直接 claim 底层 endpoint,也不会启动视频流。
现有 drivers/usb/usb-device/uvc 中的 crab-uvc 可以继续作为通用 UVC host-side 协议和视频流实现使用。它的 UvcDevice::new() 需要异步打开设备并取得独占 Device,同时要管理 Video Control 和 Video Streaming 两个 interface,因此不能直接塞入当前同步的 UsbDriver::probe(&UsbInterface) callback。后续需要单独设计 async probe、live device ownership、VC/VS 多 interface 管理、格式协商和 isochronous streaming 生命周期。
板端测试结果
在 K3 板上插入 Suyin HD Camera 后,USB host 检测到端口 4 的连接变化,完成 debounce、reset 和 high-speed device setup。随后两个 Video interface 都被 uvcvideo 匹配并逻辑认领:
root@starry:/root # [137.356351 0:40 crab_usb::backend::kmod::hub::device:173] Port 4 connection changed: true
[137.363140 0:40 crab_usb::backend::kmod::hub::device:188] Port 4 connection changed: connected=true, enabled=false
[137.374792 0:40 crab_usb::backend::kmod::hub::device:706] Handling connection on port 4, speed: Full
[137.385371 0:40 crab_usb::backend::kmod::hub::device:605] Starting debounce on port 4 (expected_connected: true)
[137.497377 0:40 crab_usb::backend::kmod::hub::device:627] Port 4 debounce stable (connected: true)
[137.504790 0:40 crab_usb::backend::kmod::hub::device:661] Resetting port 4
[137.613629 0:40 crab_usb::backend::kmod::hub::device:684] Port 4 reset complete
[137.619458 0:40 crab_usb::backend::kmod::hub::device:767] Port 4 enabled after 1 checks
[137.628813 0:40 crab_usb::backend::kmod::hub::device:726] Port 4 device ready: speed=High, enabled=true
[137.696570 0:40 crab_usb::driver:210] usb: interface 0 alt 0 matched driver uvcvideo
[137.702763 0:40 ax_driver::usb::uvcvideo:44] uvcvideo: logically claimed 1e45:8022 interface 0 alt 0 endpoints=1
[137.714402 0:40 crab_usb::driver:227] usb: interface 0 alt 0 claimed by uvcvideo
[137.723218 0:40 crab_usb::driver:210] usb: interface 1 alt 0 matched driver uvcvideo
[137.732385 0:40 ax_driver::usb::uvcvideo:44] uvcvideo: logically claimed 1e45:8022 interface 1 alt 0 endpoints=0
[137.744042 0:40 crab_usb::driver:227] usb: interface 1 alt 0 claimed by uvcvideo
[137.752851 0:40 starry_kernel::pseudofs::usbfs::manager:747] [usb-hotplug] bus=1 device=5 logical_id=4 state=connected kind=device vid=1e45 pid=8022 class=0xef
这组日志证明了端口连接、枚举、描述符获取、interface 生成、ID 匹配、probe 和逻辑 claim 的链路已经贯通。class=0xef 是设备级 composite class,真正用于本次匹配的是两个 interface 的 Video class/subclass。
当前结果还不代表摄像头视频采集已经完成,下一阶段需要继续完成:
- 将异步 live
Deviceownership 接入 UVC driver 生命周期。 - 同时管理 Video Control 和 Video Streaming interface 的底层 claim。
- 解析 UVC format/frame descriptor,完成视频格式协商。
- 配置 isochronous endpoint,接收 USB payload 并组装视频帧。
验证情况
cargo test -p crab-usb --lib:42 个测试通过。cargo test -p ax-driver --lib --features usb:2 个测试通过。cargo xtask clippy --package ax-driver:59 个 feature 组合全部通过。cargo fmt --all --check和git diff --check通过。
下周计划
- 继续设计 UVC class driver 与 live USB
Device之间的 ownership 边界。 - 解析 Suyin 摄像头的完整 UVC descriptors,确认 VC/VS interface 和 isochronous endpoint 参数。
- 在不破坏 usbfs interface ownership 的前提下,完成最小视频格式协商和单帧接收测试。
- 继续完善 USB 多设备断开、重新连接和 driver disconnect 路径。
第九周 Bug 发现:SpacemiT K3 A100 偶发产生非法 stval
2026 年 9 月 18 日确认与复盘:此前将该现象归因为 K3 板端硬件错误的结论不成立,根因在软件。软件使执行地址跳出 Sv39 的可表示范围;
sepc(EPC)被截断,而stval依照规范记录了完整的 faulting virtual address,才造成了两者高位不一致的表象。这是一次低级的排查错误。发现异常地址后,没有在 QEMU 与 K3 板上对同一地址和同一场景做真实对比,而是一味假定是板端错误;还误以为 QEMU 的实现正确,因此没有参考价值、不能帮助反映 K3 的问题。实际上,QEMU 的正确行为正应作为对照基线。此前的排查思路有误,以下原始复现记录和采样证据保留,末尾结论已据此更正。
完整原始日志见:exception.md
相关源码快捷跳转:
复现步骤
EFI:target/starry-grub/spacemitk3-com260kit/starryos.efi。
对应的调试符号表压缩包为 target/riscv64gc-unknown-none-elf/release/starryos.xz。使用 JTAG/GDB 前解压:
xz -dk target/riscv64gc-unknown-none-elf/release/starryos.xz
解压得到的 target/riscv64gc-unknown-none-elf/release/starryos 即为这份 EFI 对应的 ELF 符号表。
上传时直接指定该 EFI:
python3 board_script/k3com260kit/sync_kernel.py \
--kernel target/starry-grub/spacemitk3-com260kit/starryos.efi \
<板子 IP>
对应 release ELF 的函数断点地址如下:
| 符号 | 地址 |
|---|---|
riscv64_raw_entry | 0xffffffff80001000 |
someboot::arch::entry::kernel_entry | 0xffffffff8035d700 |
someboot::arch::entry::enter_from_efi | 0xffffffff8035d748 |
someboot::arch::entry::mmu_entry | 0xffffffff8035d810 |
someboot::arch::entry::mmu_entry_rust | 0xffffffff80360078 |
someboot::arch::entry::primary_entry_from_efi | 0xffffffff8036015a |
trap_vector_base | 0xffffffff8036a09c |
riscv_trap_handler | 0xffffffff8036ac84 |
ax_cpu::riscv::trap::handle_page_fault | 0xffffffff8036a5d8 |
starry_kernel::mm::access::handle_page_fault | 0xffffffff8013713e |
trap_vector_base 是 trap 汇编入口。trap.S/trap_tls.S 会先读取 stval、scause、sepc 和 sstatus,再跳转到 riscv_trap_handler;调试时使用上面这份 ELF 执行 file 或设置符号断点即可。
复现教程
前置条件
- K3 开发板能够启动一个同时具备 GRUB、SSH 登录和正常网络连接的系统;
- 已知开发板的 IP 地址及
root用户密码。
部署 StarryOS 内核
在主机上克隆 integer-k3-board-support 分支并进入仓库:
git clone --branch integer-k3-board-support --single-branch \
https://github.com/Dirinkbottle/tgoskits.git
cd tgoskits
确保开发板已启动到上述可通过 SSH 访问的系统后,运行同步脚本(将 <板子 IP> 替换为实际地址):
python3 board_script/k3com260kit/sync_kernel.py \
--kernel target/starry-grub/spacemitk3-com260kit/starryos.efi \
<板子 IP>
需要确保脚本中的BOARD_ROOT_DEVICE = “/dev/sda3“和BOARD_ESP_DEVICE = “/dev/sda1“对应的分区准确无误,如有不对请手动调整
脚本执行过程中会要求输入开发板 root 用户的密码。同步完成后,StarryOS 内核会被加入开发板的 GRUB 菜单。
触发异常
-
重启开发板,并在 GRUB 菜单中选择 StarryOS 启动。
-
进入 StarryOS shell 后执行:
echo 1 > /proc/set_ai_thread此操作会将当前进程切换到 A100 核心 8(CPU8);在本次复现环境中,首次执行可确认运行在 core 8。
-
随后执行一个会触发指令缺页的命令,例如:
ls或者sync # 或其他能触发指令缺页的命令
预期结果
StarryOS 会通过 error! 输出观察到的异常 stval != sepc 情况。典型日志中,stval 的低位与 sepc 一致,但 stval 带有不符合 Sv39 canonical address 规则的高位,例如:
Instruction page fault: stval=0xffffff0000c68dfc, sepc=0xc68dfc
取指跨页时 stval 与 sepc 不同本身可以是正常现象;本复现关注的是上例这种 stval 高位异常、且不是合法 Sv39 canonical 地址的情况。
原始日志(exception.md 节选)
以下内容直接截取自完整日志,异常发生在 SpacemiT K3 的 A100 核心 CPU8 上:
root@starry:/root # echo 1 > /proc/set_ai_thread
root@starry:/root # ls
[ 58.494400 8:122 starry_kernel::task::user:70] Enter user space: ip=0xf481c, sp=0x3fffff970
[ 58.939963 8:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WUNTRACED)
[ 59.040106 8:122 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0xffffff0000c68dfc, sepc=0xc68dfc
[ 59.048726 8:122 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0xffffff0000c13400, sepc=0xc13400
[ 59.059760 8:122 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0xffffff0000c0a8aa, sepc=0xc0a8aa
[ 59.071088 8:122 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0xffffff0000bdd5e6, sepc=0xbdd5e6
spacemit-toolchain-linux-glibc-x86_6[ 59.104138 8:122 starry_kernel::task::ops:398] Task(122, "ls") exit with code: 0
4-v1.2.4.tar.xz
同一份日志中,ort_learn 还捕获到了正常的跨页取指异常:
[ 81.622547 8:124 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0x29000, sepc=0x28ffe
[ 81.660874 8:124 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0xffffff0000171ffc, sepc=0x171ffc
[ 81.679713 8:124 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0x5c3000, sepc=0x5c2ffe
[ 81.704560 8:124 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0x5b2000, sepc=0x5b1ffe
[ 81.728771 8:124 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0x5c6000, sepc=0x5c5ffe
其中第一条是合理的跨页场景;第二条仍然是非 canonical stval,但它的低位地址与 sepc 相同。
现象
在 SpacemiT K3 的 A100 核心(CPU8)上运行 StarryOS 时,用户态程序发生 Instruction Page Fault 后,硬件 stval CSR 偶发返回非 Sv39 canonical 地址。
异常值具有以下特征:
stval的低 39 位与实际 faulting virtual address 一致;stval的高位被填充为0xffffff...,但低地址的 bit38 为 0,因此不满足 Sv39 canonical address 规则;sepc仍保持正常的低地址形式;- 同一 CPU8 上既能复现异常值,也能捕获符合规范的跨页取指异常。
典型异常值为:
stval = 0xffffff0000c68dfc
sepc = 0x0000000000c68dfc
scause = 0xc
同一程序在 CPU8 上可反复出现类似结果:
stval=0xffffff0000c68dfc, sepc=0xc68dfc
stval=0xffffff0000c13400, sepc=0xc13400
stval=0xffffff0000c0a8aa, sepc=0xc0a8aa
stval=0xffffff0000bdd5e6, sepc=0xbdd5e6
影响
StarryOS 原本直接使用 stval 查找用户 VMA。因此,同一异常可能出现以下结果:
stval = 0xffffff0000bcb26a
sepc = 0x0000000000bcb26a
find_area(stval) = false
find_area(sepc) = true
本来应该由 demand paging 处理的缺页被误判为非法地址,最终产生 SIGSEGV。将异常 stval 按 Sv39 规则重新 canonicalize 后,程序可以继续执行并正常退出。
规范判断
Sv39 使用 39 位虚拟地址。对于 RV64,合法 Sv39 虚拟地址必须满足:
VA[63:39] = {25{VA[38]}}
也就是:
bit38 = 0 => bits[63:39] 必须全部为 0
bit38 = 1 => bits[63:39] 必须全部为 1
因此:
0x0000000000c68dfc
是合法的 Sv39 低地址,而:
0xffffff0000c68dfc
不是合法的 Sv39 canonical address:它的 bit38 为 0,但 bits[63:39] 并非全 0。
对于 Instruction Page Fault,sepc 保存发生异常的指令起始地址;在实现支持有效 trap value 时,stval 应保存导致异常的 faulting virtual address。
变长指令跨页时,二者可以不同。例如:
sepc = 0x28ffe
stval = 0x29000
这表示指令从 0x28ffe 开始,指令后半部分位于下一页,并在 0x29000 处发生取指异常。这种差异符合规范。
但以下情况不存在跨页关系:
sepc = 0x0000000000c68dfc
stval = 0xffffff0000c68dfc
stval 本身还是非法 Sv39 地址,因此不能用正常的 instruction page fault 语义解释。
证据
1. trap.S 在 trap entry 直接读取硬件 CSR
以下是 trap.S 中的原始代码:
.Ltrap_saved:
csrr t3, stval
csrr t4, scause
csrr t5, sepc
csrr t2, sstatus
STR t5, sp, 32 // tf.sepc
STR t2, sp, 33 // tf.sstatus
STR t3, sp, 34 // tf.stval
STR t4, sp, 35 // tf.scause
// Kernel Rust always sees the psABI global pointer, trusted kernel tp, and
// canonical sscratch=0.
csrw sscratch, zero
.option push
.option norelax
lla gp, __global_pointer$
.option pop
andi t2, t2, 1 << 8 // sstatus.SPP == 1
beqz t2, .Lexit_user
mv a0, sp
la ra, .Ltrap_return
j riscv_trap_handler
这里 csrr t3, stval、csrr t5, sepc 在进入 Rust handler 之前执行,并立即写入 trap frame。该路径没有对 stval 做高位拼接或地址转换,因此可以作为硬件 CSR 值的第一手采样点。
2. trap_tls.S 的另一条 trap entry 路径采用相同的 CSR 保存方式
以下是 trap_tls.S 中的原始代码:
.Ltrap_saved:
csrr t3, stval
csrr t4, scause
csrr t5, sepc
csrr t2, sstatus
STR t5, sp, 32
STR t2, sp, 33
STR t3, sp, 34
STR t4, sp, 35
csrw sscratch, t0
.option push
.option norelax
lla gp, __global_pointer$
.option pop
andi t2, t2, 1 << 8
beqz t2, .Lexit_user
mv a0, sp
la ra, .Ltrap_return
j riscv_trap_handler
这个配置下仍然是先读取 stval/scause/sepc,再将它们分别保存到 trap frame 的固定位置。两种配置的 CSR 采样和保存逻辑一致,因此至少可以排除“某一份汇编在保存 stval 时额外拼接了高位”这一类原因;当前日志中的异常是在该保存路径上观察到的。
3. context.rs 中的 trap frame 字段顺序与保存位置对应
源码:查看 context.rs 第 15–52 行 和 第 327–341 行
以下是 context.rs 中的原始代码:
#![allow(unused)]
fn main() {
/// General registers of RISC-V.
#[allow(missing_docs)]
#[repr(C)]
#[derive(Debug, Default, Clone, Copy)]
pub struct GeneralRegisters {
pub zero: usize,
pub ra: usize,
pub sp: usize,
pub gp: usize,
pub tp: usize,
pub t0: usize,
pub t1: usize,
pub t2: usize,
pub s0: usize,
pub s1: usize,
pub a0: usize,
pub a1: usize,
pub a2: usize,
pub a3: usize,
pub a4: usize,
pub a5: usize,
pub a6: usize,
pub a7: usize,
pub s2: usize,
pub s3: usize,
pub s4: usize,
pub s5: usize,
pub s6: usize,
pub s7: usize,
pub s8: usize,
pub s9: usize,
pub s10: usize,
pub s11: usize,
pub t3: usize,
pub t4: usize,
pub t5: usize,
pub t6: usize,
}
}
#![allow(unused)]
fn main() {
/// Saved registers when a trap (interrupt or exception) occurs.
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct TrapFrame {
/// All general registers.
pub regs: GeneralRegisters,
/// Supervisor Exception Program Counter.
pub sepc: usize,
/// Supervisor Status Register.
pub sstatus: sstatus::Sstatus,
/// Supervisor Trap Value captured at trap entry.
pub stval: usize,
/// Supervisor Cause captured at trap entry.
pub scause: usize,
}
}
GeneralRegisters 恰好包含 32 个机器字,因此在 RV64 下:
trap frame index 32 -> sepc
trap frame index 33 -> sstatus
trap frame index 34 -> stval
trap frame index 35 -> scause
这与两个 trap entry 文件中的 STR 位置完全对应,说明当前观察到的高位异常不是由于 TrapFrame 字段顺序或 stval/sepc 槽位错位造成的。
排查结论
经 9 月 18 日重新确认,根因是软件而非 A100 硬件 erratum:软件使地址跳出 Sv39 的表示范围,sepc(EPC)又被截断;相对地,stval 按规范保留了完整的 faulting virtual address。因此日志中看到的高位不一致并非 K3 错误写回 stval。
此前虽然确认了 trap entry 会直接采样 CSR、trap frame 字段未错位,也观察到了跨页取指场景,但没有把异常地址在 QEMU 与 K3 板上进行同条件的真实对比,过早地将问题归因为板端。QEMU 的正确实现应当作为行为基线,而不是被排除在参考之外。后续排查此类异常时,应先对比两端的完整地址、sepc/stval 语义和地址截断路径,再判断是否存在硬件问题。
第九周 Bug 原始异常日志
PROGRESS CODE: V03040002 I0 PROGRESS CODE: V03040003 I0 PROGRESS CODE: V03040002 I0 PROGRESS CODE: V03040003 I0 PROGRESS CODE: V03040002 I0 PROGRESS CODE: V03040003 I0 PROGRESS CODE: V03040002 I0 PROGRESS CODE: V03040003 I0 PROGRESS CODE: V03040002 I0 PROGRESS CODE: V03040003 I0 PROGRESS CODE: V03040002 I0 PROGRESS CODE: V03040003 I0 PROGRESS CODE: V03040002 I0 PROGRESS CODE: V03040003 I0 PROGRESS CODE: V03040002 I0 PROGRESS CODE: V03040003 I0 PROGRESS CODE: V03040002 I0 PROGRESS CODE: V03040003 I0 PROGRESS CODE: V03040002 I0 PROGRESS CODE: V03040003 I0 PROGRESS CODE: V03040002 I0 PROGRESS CODE: V03040003 I0 PROGRESS CODE: V03040002 I0 PROGRESS CODE: V03040003 I0 PROGRESS CODE: V03040002 I0 PROGRESS CODE: V03040003 I0 PROGRESS CODE: V03040002 I0 PROGRESS CODE: V03040003 I0 PROGRESS CODE: V03040002 I0 PROGRESS CODE: V03040003 I0 PROGRESS CODE: V03040002 I0 PROGRESS CODE: V03040003 I0 PROGRESS CODE: V03040002 I0 PROGRESS CODE: V03040003 I0 PROGRESS CODE: V03040002 I0 PROGRESS CODE: V03040003 I0 PROGRESS CODE: V03040002 I0 PROGRESS CODE: V03040003 I0 PROGRESS CODE: V03040002 I0 PROGRESS CODE: V03040003 I0 PROGRESS CODE: V03040002 I0 PROGRESS CODE: V03040003 I0 PROGRESS CODE: V03040002 I0 PROGRESS CODE: V03040003 I0 PROGRESS CODE: V03040002 I0 PROGRESS CODE: V03040003 I0 PROGRESS CODE: V03040002 I0 PROGRESS CODE: V03040003 I0 PROGRESS CODE: V03040002 I0 PROGRESS CODE: V03040003 I0 PROGRESS CODE: V03040002 I0 PROGRESS CODE: V03040003 I0 PROGRESS CODE: V03040002 I0 PROGRESS CODE: V03040003 I0 PROGRESS CODE: V03040002 I0 PROGRESS CODE: V03040003 I0 PROGRESS CODE: V03040002 I0 PROGRESS CODE: V03040003 I0
PROGRESS CODE: V02070000 I0 PROGRESS CODE: V02070003 I0 PROGRESS CODE: V02070004 I0 PROGRESS CODE: V02020000 I0 PROGRESS CODE: V02020004 I0
GNU GRUB version 2.14
UEFI application started. UEFI console ok. Found FDT at address: 0x2fddbe000 No ACPI RSDP found in UEFI config tables. RISC-V UEFI boot hart ID: 0. RISC-V64 UEFI kernel entry. Exiting UEFI boot services… PROGRESS CODE: V03101019 I0 Exited boot services, memory map obtained. console=ttyS0,115200 earlycon=sbi root=PARTLABEL=writable bootfs=PARTUUID=3ae56870-fdf8-4df5-acc0-6d0edc70637a rw VM Load @PA:0x2f6e07000 VM Load Offset: 0x376e07000 Memory Map: MMIO 0x000000b8000000 - 0x000000b8d00000 (13 MiB) MMIO 0x000000d420c000 - 0x000000d420d000 (4 KiB) Rsv 0x00000100000000 - 0x00000100100000 (1 MiB) Free 0x00000100100000 - 0x00000100200000 (1 MiB) Rsv 0x00000100200000 - 0x00000100700000 (5 MiB) Free 0x00000100700000 - 0x00000100800000 (1 MiB) Rsv 0x00000100800000 - 0x00000100e04000 (6.02 MiB) Free 0x00000100e04000 - 0x000002f6e07000 (7.84 GiB) KImg 0x000002f6e07000 - 0x000002f944b000 (38.27 MiB) Free 0x000002f944b000 - 0x000002fddbe000 (73.45 MiB) Rsv 0x000002fddbe000 - 0x000002fdde6000 (160 KiB) Free 0x000002fdde6000 - 0x000002ffe3d000 (32.34 MiB) Rsv 0x000002ffe3d000 - 0x000002fffff000 (1.76 MiB) Free 0x000002fffff000 - 0x00000300000000 (4 KiB) Initialize RAM allocator: 0x100e04000..0x2f6e07000 Reserving CPU-local areas CPU-local area stride: 0x41000 bytes Total CPU-local allocation: 0x410000 bytes (16 CPUs) Flushed RAM used range to memory map: 0x100e04000..0x100e2c000, current: 0x100e2c000 Flushed RAM used range to memory map: 0x100e2c000..0x10123c000, current: 0x10123c000 CPU-local areas allocated at 0x100e2c000 - 0x10123c000 Mapping early memory regions… Ram : [0x0000000100000000, 0x0000000300000000) -> [0x0000000100000000, 0x0000000300000000) (8 GiB) Ram : [0xffffffc100000000, 0xffffffc300000000) -> [0x0000000100000000, 0x0000000300000000) (8 GiB) KImage : [0xffffffff80000000, 0xffffffff82644000) -> [0x00000002f6e07000, 0x00000002f944b000) (38.27 MiB) PerCpu : [0xffffffe100e2c000, 0xffffffe10123c000) -> [0x0000000100e2c000, 0x000000010123c000) (4.06 MiB) Boot page table at physical address: 0x10123c000 MMU Entry point at physical address: 0x2f7164810 Enabling MMU… MMU enabled, jumping to 0xffffffff8035d810, sp=0xffffffe100e6d000 Trap vector at 0xffffffff8035c8c4 Memory Map: MMIO 0x000000b8000000 - 0x000000b8d00000 (13 MiB) MMIO 0x000000d420c000 - 0x000000d420d000 (4 KiB) Rsv 0x00000100000000 - 0x00000100100000 (1 MiB) Free 0x00000100100000 - 0x00000100200000 (1 MiB) Rsv 0x00000100200000 - 0x00000100700000 (5 MiB) Free 0x00000100700000 - 0x00000100800000 (1 MiB) Rsv 0x00000100800000 - 0x00000100e2c000 (6.17 MiB) PerCPU 0x00000100e2c000 - 0x0000010123c000 (4.06 MiB) Rsv 0x0000010123c000 - 0x00000103266000 (32.16 MiB) Free 0x00000103266000 - 0x000002f6e07000 (7.81 GiB) KImg 0x000002f6e07000 - 0x000002f944b000 (38.27 MiB) Free 0x000002f944b000 - 0x000002fddbe000 (73.45 MiB) Rsv 0x000002fddbe000 - 0x000002fdde6000 (160 KiB) Free 0x000002fdde6000 - 0x000002ffe3d000 (32.34 MiB) Rsv 0x000002ffe3d000 - 0x000002fffff000 (1.76 MiB) Free 0x000002fffff000 - 0x00000300000000 (4 KiB) Jumping to main entry point at 0xffffffff8034a4a0 with SP 0xffffffe100e6d000
d8888 .d88888b. .d8888b.
d88888 d88P" "Y88b d88P Y88b
d88P888 888 888 Y88b.
d88P 888 888d888 .d8888b .d88b. 888 888 "Y888b.
d88P 888 888P“ d88P“ d8P Y8b 888 888 “Y88b. d88P 888 888 888 88888888 888 888 “888 d8888888888 888 Y88b. Y8b. Y88b. .d88P Y88b d88P d88P 888 888 “Y8888P “Y8888 “Y88888P” “Y8888P”
arch = riscv64 platform = SpacemiT K3 Com260 IFX target = riscv64gc-unknown-none-elf build_mode = log_level = info backtrace = false smp = 16
[ 11.737761 ax_runtime:219] Logging is enabled. [ 11.743578 ax_runtime:220] Primary CPU 0 started, arg = 0x100e04000. [ 11.751336 ax_runtime:222] Found physcial memory regions: [ 11.758136 ax_runtime:224] [PA:0xb8000000, PA:0xb8d00000) mmio (READ | WRITE | DEVICE | RESERVED) [ 11.768616 ax_runtime:224] [PA:0xd420c000, PA:0xd420d000) mmio (READ | WRITE | DEVICE | RESERVED) [ 11.779107 ax_runtime:224] [PA:0x100000000, PA:0x100100000) reserved (READ | WRITE | EXECUTE | RESERVED) [ 11.790215 ax_runtime:224] [PA:0x100100000, PA:0x100200000) free memory (READ | WRITE | FREE) [ 11.800354 ax_runtime:224] [PA:0x100200000, PA:0x100700000) reserved (READ | WRITE | EXECUTE | RESERVED) [ 11.811463 ax_runtime:224] [PA:0x100700000, PA:0x100800000) free memory (READ | WRITE | FREE) [ 11.821601 ax_runtime:224] [PA:0x100800000, PA:0x100e2c000) reserved (READ | WRITE | EXECUTE | RESERVED) [ 11.832710 ax_runtime:224] [PA:0x100e2c000, PA:0x10123c000) reserved (READ | WRITE | EXECUTE | RESERVED) [ 11.843818 ax_runtime:224] [PA:0x10123c000, PA:0x103266000) reserved (READ | WRITE | EXECUTE | RESERVED) [ 11.854926 ax_runtime:224] [PA:0x103266000, PA:0x2f6e07000) free memory (READ | WRITE | FREE) [ 11.865065 ax_runtime:224] [PA:0x2f6e07000, PA:0x2f944b000) reserved (READ | WRITE | EXECUTE | RESERVED) [ 11.876174 ax_runtime:224] [PA:0x2f944b000, PA:0x2fddbe000) free memory (READ | WRITE | FREE) [ 11.886312 ax_runtime:224] [PA:0x2fddbe000, PA:0x2fdde6000) reserved (READ | WRITE | EXECUTE | RESERVED) [ 11.897420 ax_runtime:224] [PA:0x2fdde6000, PA:0x2ffe3d000) free memory (READ | WRITE | FREE) [ 11.907559 ax_runtime:224] [PA:0x2ffe3d000, PA:0x2fffff000) reserved (READ | WRITE | EXECUTE | RESERVED) [ 11.918667 ax_runtime:224] [PA:0x2fffff000, PA:0x300000000) free memory (READ | WRITE | FREE) [ 11.928806 ax_runtime:372] Initialize global memory allocator… [ 11.936212 ax_runtime:373] use buddy-slab-allocator allocator. [ 11.943618 ax_alloc::buddy_slab:158] Initialize global memory allocator, start_vaddr: 0xffffffc103266000, size: 0x1f3ba1000 [ 11.959033 ax_alloc::buddy_slab:410] global allocator initialized [ 11.963719 ax_alloc::buddy_slab:168] Add memory region, start_vaddr: 0xffffffc100100000, size: 0x100000 [ 11.974562 buddy_slab_allocator::global:143] GlobalAllocator: skip region 0xffffffc100100000+0x100000, no allocator-visible memory after 2097152 alignment [ 11.989902 ax_alloc::buddy_slab:168] Add memory region, start_vaddr: 0xffffffc100700000, size: 0x100000 [ 12.000746 buddy_slab_allocator::global:143] GlobalAllocator: skip region 0xffffffc100700000+0x100000, no allocator-visible memory after 2097152 alignment [ 12.016086 ax_alloc::buddy_slab:168] Add memory region, start_vaddr: 0xffffffc2f944b000, size: 0x4973000 [ 12.027045 ax_alloc::buddy_slab:168] Add memory region, start_vaddr: 0xffffffc2fdde6000, size: 0x2057000 [ 12.037963 ax_alloc::buddy_slab:168] Add memory region, start_vaddr: 0xffffffc2fffff000, size: 0x1000 [ 12.048618 buddy_slab_allocator::global:143] GlobalAllocator: skip region 0xffffffc2fffff000+0x1000, no allocator-visible memory after 2097152 alignment [ 12.063783 ax_runtime:259] kernel aspace: [VA:0xffffffc000000000, VA:0xffffffffffffffff) [ 12.073304 ax_mm:103] Initialize virtual memory management… [ 12.300304 ax_runtime:271] Initialize platform devices… [ 12.321639 somehal::driver:5] Initializing rdrive with FDT at 0xffffffc100e04000 [ 12.379682 somehal::arch::imsic_aplic:169] IMSIC probed: base=0xe0400000 hart_bits=4 guest_bits=6 num_ids=511 [ 12.388089 somehal::arch::imsic_aplic:192] IMSIC MSI provider registered [ 12.401458 somehal::arch::imsic_aplic:251] APLIC probed: num_sources=512, MSI mode configured [ 12.408464 ax_task::api:149] Initialize scheduling… [ 12.415046 ax_task::api:157] use Round-robin scheduler. [ 12.421661 ax_runtime:297] Initialize interrupt handlers… [ 12.428653 ax_runtime::devices:2] Probe platform devices… [ 12.442835 ax_driver::serial::k3::pxa_uart:31] Probing K3 PXA UART serial device: serial@d4017000 [ 12.450180 ax_driver::serial::k3::pxa_uart:46] K3 PXA UART at 0xd4017000 (size 0x100), clock=14700000 Hz [ 12.461124 ax_driver::serial::k3::pxa_uart:55] K3 PXA UART serial@0xffffffc0d4017000 registered successfully [ 12.492270 ax_driver::soc::k3::pinctrl:381] k3-pinctrl: registered (pad=0xd401e000, io_pd=0xd401e800, apbc=0xd4015000+0x50) [ 12.554307 ax_driver::block::k3_ufs:64] [k3-ufs] ============================================ [ 12.561297 ax_driver::block::k3_ufs:65] [k3-ufs] Probing SpacemiT K3 UFS controller [ 12.570380 ax_driver::block::k3_ufs:75] [k3-ufs] MMIO: base=0xc0e00000, size=0x40000 [ 12.579567 ax_driver::block::k3_ufs:82] [k3-ufs] IRQ: 135 [ 12.586347 ax_driver::block::k3_ufs:98] [k3-ufs] lanes-per-direction: 2 [ 12.594356 ax_driver::block::k3_ufs::init:139] [k3-ufs] Initializing host controller… [ 12.603787 ax_driver::block::k3_ufs::init:147] [k3-ufs] CAP: 0x0587021f, VER: 0x00000210 [ 12.615309 ax_driver::block::k3_ufs::init:161] [k3-ufs] Host controller enabled [ 12.622036 ax_driver::block::k3_ufs::init:81] [k3-ufs] Initializing MPHY… [ 12.633914 ax_driver::block::k3_ufs::init:113] [k3-ufs] MPHY init completed [ 12.639308 ax_driver::block::k3_ufs::init:191] [k3-ufs] Initializing UNIPRO v1.6… [ 12.648424 ax_driver::block::k3_ufs::init:248] [k3-ufs] UNIPRO v1.6 init completed [ 12.657382 ax_driver::block::k3_ufs::init:179] [k3-ufs] SYS1CLK_1US=0x1eb, TX_SYMBOL_CLK=0x800 [ 12.667431 ax_driver::block::k3_ufs::init:254] [k3-ufs] Starting UFS link… [ 12.694534 ax_driver::block::k3_ufs::init:266] [k3-ufs] Link active, device present. Status=0x0000000f [ 12.702314 ax_driver::block::k3_ufs::init:298] [k3-ufs] Connected TX data lanes: 2 [ 12.711300 ax_driver::block::k3_ufs::init:312] [k3-ufs] Link startup post processing completed [ 12.721351 ax_driver::block::k3_ufs::init:591] [k3-ufs] Register dump: [ 12.729291 ax_driver::block::k3_ufs::init:592] CAP: 0x0587021f [ 12.737039 ax_driver::block::k3_ufs::init:596] VER: 0x00000210 [ 12.744802 ax_driver::block::k3_ufs::init:597] HCS: 0x0000000f [ 12.752560 ax_driver::block::k3_ufs::init:598] HCE: 0x00000001 [ 12.760319 ax_driver::block::k3_ufs::transfer:52] [k3-ufs] CAP=0x0587021f, nutrs=32, reserved_slot=31 [ 12.771081 ax_driver::block::k3_ufs::transfer:87] [k3-ufs] DMA layout: utrd_base=0x2f5bb7000, utmrd_base=0x2f5c5c000, ucd_base=0x2f5da0000, ucd_slot_size=3072 [ 12.786682 ax_driver::block::k3_ufs::transfer:98] [k3-ufs] Transfer lists configured (Linux sequence) [ 12.797347 ax_driver::block::k3_ufs:136] [k3-ufs] Starting device initialization chain [ 12.806692 ax_driver::block::k3_ufs::transfer:610] [k3-ufs] Sending NOP OUT… [ 12.816445 ax_driver::block::k3_ufs::transfer:619] [k3-ufs] NOP IN received [ 12.823707 ax_driver::block::k3_ufs::transfer:666] [k3-ufs] Setting fDeviceInit flag… [ 12.834859 ax_driver::block::k3_ufs::transfer:679] [k3-ufs] Polling fDeviceInit completion… [ 12.844212 ax_driver::block::k3_ufs::transfer:683] [k3-ufs] fDeviceInit cleared by device [ 12.852712 ax_driver::block::k3_ufs::init:322] [k3-ufs] Applying device quirks… [ 12.861623 ax_driver::block::k3_ufs::init:333] [k3-ufs] Device quirks applied [ 12.870170 ax_driver::block::k3_ufs::init:379] [k3-ufs] RX connected lanes: 2 [ 12.878722 ax_driver::block::k3_ufs::init:379] [k3-ufs] TX connected lanes: 2 [ 12.888171 ax_driver::block::k3_ufs::init:356] [k3-ufs] Device pwr caps: gear_rx=3, gear_tx=3, lanes=2, pwr_rx=1, pwr_tx=1 [ 12.899812 ax_driver::block::k3_ufs::init:478] [k3-ufs] Post-change HCS=0x0000000f, UPMCRS=0 [ 12.909666 ax_driver::block::k3_ufs::init:545] [k3-ufs] Link upgraded to HS-G3 (2 lanes, rate 2) [ 12.919893 ax_driver::block::k3_ufs::scsi:501] [k3-ufs] Sending REPORT_LUNS… [ 12.928945 ax_driver::block::k3_ufs::scsi:531] [k3-ufs] REPORT_LUNS entry: scsi_lun=0x0, upiu_lun=0x00 [ 12.939296 ax_driver::block::k3_ufs::scsi:544] [k3-ufs] Probing SCSI LUN 0x0 as UPIU LUN 0x00 [ 12.949250 ax_driver::block::k3_ufs::scsi:343] [k3-ufs] Sending SCSI INQUIRY on UPIU LUN 0x00… [ 12.959988 ax_driver::block::k3_ufs::scsi:369] [k3-ufs] LUN 0x00 device: KINGSTON TY7B-128 [ 12.969880 ax_driver::block::k3_ufs::scsi:303] [k3-ufs] Sending TEST_UNIT_READY on UPIU LUN 0x00… [ 12.980479 ax_driver::block::k3_ufs::scsi:174] [k3-ufs] TEST_UNIT_READY failed: rsp=0x21, response=0x01, status=0x02, flags=0x00, data_seg_len=20, sense_len=18, rsp[0..64]=[21, 00, 00, 02, 00, 00, 01, 02, 00, 00, 00, 14, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 12, 70, 00, 06, 00, 00, 00, 00, 0a, 00, 00, 00, 00, 29, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00] [ 13.019868 ax_driver::block::k3_ufs::scsi:189] [k3-ufs] TEST_UNIT_READY sense in UPIU: [70, 00, 06, 00, 00, 00, 00, 0a, 00, 00, 00, 00, 29, 00, 00, 00, 00, 00] [ 13.035648 ax_driver::block::k3_ufs::scsi:195] [k3-ufs] TEST_UNIT_READY sense decoded: key=0x06, asc=0x29, ascq=0x00 [ 13.047641 ax_driver::block::k3_ufs::scsi:323] [k3-ufs] TEST_UNIT_READY retry 1 due to sense key=0x06, asc=0x29, ascq=0x00 [ 13.160365 ax_driver::block::k3_ufs::scsi:313] [k3-ufs] TEST_UNIT_READY OK [ 13.165665 ax_driver::block::k3_ufs::scsi:430] [k3-ufs] Sending READ_CAPACITY(10) on UPIU LUN 0x00… [ 13.176648 ax_driver::block::k3_ufs::scsi:438] [k3-ufs] READ_CAPACITY(10): 31266816 blocks x 4096 bytes [ 13.187525 ax_driver::block::k3_ufs::scsi:604] [k3-ufs] LUN 0x0 GPT header signature at LBA1: [45, 46, 49, 20, 50, 41, 52, 54] [ 13.200053 ax_driver::block::k3_ufs::scsi:616] [k3-ufs] LUN 0x0 LBA0[0..64]=[00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00], MBR sig=[55, aa] [ 13.232672 ax_driver::block::k3_ufs::scsi:624] [k3-ufs] Selecting LUN 0x0 as block device [ 13.242292 ax_driver::block::k3_ufs:163] [k3-ufs] Block device registered [ 13.250481 ax_driver::block::k3_ufs:164] [k3-ufs] *** DEVICE READY: SCSI LUN 0x0, 31266816 blocks x 4096 bytes *** [ 13.262295 ax_driver::block::k3_ufs:168] [k3-ufs] ============================================ [ 13.272636 ax_driver::usb::k3com260kit:121] [k3-usb] DWC3 probe: host node=usb3@81400000 [ 13.281877 ax_driver::usb::k3com260kit:133] [k3-usb] DWC3 clock configured: reg=0x00000ff0, enabled=true [ 13.292805 ax_driver::usb::k3com260kit:150] [k3-usb] DWC3 reset released: reg=0x00000ff0, released=true [ 13.303651 ax_driver::usb::k3com260kit:164] [k3-usb] xHCI registers: CAPLENGTH=0x20, MAX_SLOTS=64, USBSTS=0x00000001 [ 13.315840 ax_driver::usb::k3com260kit:328] [k3-usb] USB2 PHY PLL configured: DIV_CFG=0x0000bec4 [ 13.325860 ax_driver::usb::k3com260kit:341] [k3-usb] USB2 PHY PLL lock: RST_MODE_CTRL=0x000060e9 [ 13.336086 ax_driver::usb::k3com260kit:357] [k3-usb] USB2 PHY reset released: RST_MODE_CTRL=0x000060ef [ 13.346842 ax_driver::usb::k3com260kit:366] [k3-usb] USB2 PHY TX path enabled: HSTXP_HW_CTRL=0x0000001c [ 13.357686 ax_driver::usb::k3com260kit:377] [k3-usb] USB2 PHY disconnect auto-clear configured: TX_HOST_CTRL=0x00000015, enabled=true [ 13.371190 ax_driver::usb::k3com260kit:416] [k3-usb] USB3 PHY PLL lock: already initialized, CLK_CFG=0x01800979 [ 13.382724 ax_driver::usb::k3com260kit:180] [k3-usb] temporary PORTSC polling: op_base=0x20, ports=2 [ 13.393303 ax_driver::usb::k3com260kit:187] [k3-usb] PORTSC1 @ 0x420 for bit 0 = 1 [ 13.402384 ax_driver::usb::k3com260kit:187] [k3-usb] PORTSC2 @ 0x430 for bit 0 = 0 [ 14.411468 crab_usb::backend::kmod::xhci::host:101] xHCI: Addressing Capability (AC64) = true (64-bit addressing) [ 14.420839 rdrive:216] Probe failed for [fdt]: other error: [usb2@c0a00000] has no phy-names entry for usb3-phy [ 14.431874 ax_runtime::serial:464] serial runtime PXA UART ready: cpu=0, irq=Some(Source(FdtInterrupt(FdtIrqSpec { controller: 1138, cells: [42, 4] }))), polling=false Boot at 1970-01-01 00:00:14.448253958 UTC
[ 14.452563 ax_fs_ng::block::runtime::hctx:173] block hctx 0 bound to CPU 0 with hardware depth 1 [ 14.486563 ax_fs_ng::root:348] partition 1 name=Some(“esp”) fs=None lba 3072..28672 [ 14.493285 ax_fs_ng::root:348] partition 2 name=Some(“cidata”) fs=None lba 28672..45056 [ 14.502970 ax_fs_ng::root:348] partition 3 name=Some(“writable”) fs=Some(Ext4) lba 45056..31266783 [ 14.513562 ax_fs_ng::root:364] block device 0 (k3-ufs) has Gpt partition table with 3 partitions [ 14.523975 ax_fs_ng::root:462] matched root by PARTLABEL on disk0 partition 3 (writable, fs=ext4, lba 45056..31266783) [ 14.536311 ax_fs_ng:86] Initialize filesystem subsystem… [ 14.543181 ax_fs_ng:87] selected root device: disk0 partition 3 (writable, fs=ext4, lba 45056..31266783) [ 14.566346 rsext4::ext4::mount:327] /lost+found exists (superblock hint inode=11) [ 14.572758 rsext4::ext4::mount:462] Ext4 filesystem mounted [ 14.579232 rsext4::ext4::mount:463] - block size: 4096 bytes [ 14.586455 rsext4::ext4::mount:464] - total blocks: 31221727 [ 14.593689 rsext4::ext4::mount:465] - free blocks: 28052297 [ 14.600830 rsext4::ext4::mount:466] - total inodes: 7791728 [ 14.607967 rsext4::ext4::mount:467] - free inodes: 7622946 [ 14.615024 rsext4::ext4::sync:13] Syncing filesystem… [ 14.634289 rsext4::ext4::mount:546] Ext4 filesystem mounted [ 14.638276 ax_fs_ng:99] filesystem type: “ext4” [ 14.644852 ax_net:192] Initialize network subsystem… [ 14.651071 ax_net:204] No network device found! [ 14.656967 ax_net:295] Device: lo [ 14.664062 ax_runtime::mp:79] Secondary CPU 1 started. [ 14.666432 ax_runtime::mp:79] Secondary CPU 2 started. [ 14.668290 ax_runtime::mp:110] Secondary CPU 1 init OK. [ 14.678243 ax_runtime::mp:79] Secondary CPU 7 started. [ 14.685295 ax_runtime::mp:79] Secondary CPU 10 started. [ 14.687947 ax_runtime::mp:110] Secondary CPU 7 init OK. [ 14.668813 ax_runtime::mp:79] Secondary CPU 3 started. [ 14.697041 ax_runtime:345] Primary CPU 0 init OK. [ 14.673542 ax_runtime::mp:79] Secondary CPU 5 started. [ 14.694696 ax_runtime::mp:79] Secondary CPU 14 started. [ 14.720294 ax_runtime::mp:110] Secondary CPU 5 init OK. [ 14.726910 ax_runtime::mp:110] Secondary CPU e init OK. [ 14.694560 ax_runtime::mp:110] Secondary CPU a init OK. [ 14.690008 ax_runtime::mp:79] Secondary CPU 12 started. [ 14.707687 ax_runtime::mp:110] Secondary CPU 3 init OK. [ 14.753356 ax_runtime::mp:110] Secondary CPU c init OK. [ 14.680613 ax_runtime::mp:79] Secondary CPU 8 started. [ 14.682957 ax_runtime::mp:79] Secondary CPU 9 started. [ 14.674864 ax_runtime::mp:110] Secondary CPU 2 init OK. [ 14.697041 ax_runtime::mp:79] Secondary CPU 15 started. [ 14.779679 ax_runtime::mp:110] Secondary CPU 9 init OK. [ 14.792905 ax_runtime::mp:110] Secondary CPU f init OK. [ 14.773162 ax_runtime::mp:110] Secondary CPU 8 init OK. [ 14.671203 ax_runtime::mp:79] Secondary CPU 4 started. [ 14.675903 ax_runtime::mp:79] Secondary CPU 6 started. [ 14.819267 ax_runtime::mp:110] Secondary CPU 4 init OK. [ 14.687639 ax_runtime::mp:79] Secondary CPU 11 started. [ 14.825789 ax_runtime::mp:110] Secondary CPU 6 init OK. [ 14.839015 ax_runtime::mp:110] Secondary CPU b init OK. [ 14.692355 ax_runtime::mp:79] Secondary CPU 13 started. [ 14.858850 ax_runtime::mp:110] Secondary CPU d init OK. [ 14.865390 0:2 ax_fs_ng::block::runtime::lifecycle::device:369] block device k3-ufs online with 1 hctxs across 16 CPUs [ 14.877476 0:2 ktracepoint:282] tracepoint_data_start: 0xffffffff804e55d0, tracepoint_data_end: 0xffffffff804e5630 [ 14.889274 0:2 ktracepoint:297] tracepoint_data_len: 6 [ 14.895791 0:2 ktracepoint:314] tracepoint registered: sched:sched_process_exit [ 14.904527 0:2 ktracepoint:314] tracepoint registered: sched:sched_process_fork [ 14.913276 0:2 ktracepoint:314] tracepoint registered: sched:sched_switch [ 14.921450 0:2 ktracepoint:314] tracepoint registered: syscalls:sys_clone [ 14.929649 0:2 ktracepoint:314] tracepoint registered: syscalls:sys_enter_openat [ 14.938460 0:2 ktracepoint:314] tracepoint registered: syscalls:sys_mkdirat Initialized 6 tracepoints kmod subsystem initialized [ 14.951860 0:2 starry_kernel::pseudofs:86] Initialize pseudofs… [ 14.959497 0:2 starry_kernel::pseudofs::dev::tty::serial:258] ttyS0 registered: path=/soc/serial@d4017000, alias=Some(0), paddr=0xd4017000, irq=Some(Source(FdtInterrupt(FdtIrqSpec { controller: 1138, cells: [42, 4] }))) [ 14.980449 0:2 starry_kernel::pseudofs::dev::tty::serial:203] /dev/console bound to ttyS0 [ 14.990699 0:2 starry_kernel::pseudofs:80] Mounted devfs at /dev [ 14.997440 0:2 starry_kernel::pseudofs::usbfs:51] usbfs: initializing manager [ 15.006001 0:2 starry_kernel::pseudofs::usbfs::manager:1503] usbfs: preparing host 1133 as bus 1 [ 15.016240 0:2 starry_kernel::pseudofs::usbfs::manager:1552] usbfs: discovered 1 USB host(s) [ 15.026109 0:2 starry_kernel::pseudofs::usbfs::irq:92] usbfs: registering IRQ callback for IRQ IrqId { domain: IrqDomainId(9), hwirq: HwIrq(125) } (bus 1, host 1133) [ 15.042417 0:2 starry_kernel::pseudofs::usbfs::manager:1341] usbfs: initializing host on bus 1 [ 15.052747 0:2 crab_usb::backend::kmod::xhci::host:484] Running [ 15.259807 0:2 starry_kernel::pseudofs::usbfs::irq:238] usbfs: IRQ IrqId { domain: IrqDomainId(9), hwirq: HwIrq(125) } bus 1 host 1133: port change on port 2 [ 15.272450 0:2 starry_kernel::pseudofs::usbfs::manager:1385] usbfs: host on bus 1 initialized [ 15.282398 0:2 starry_kernel::pseudofs::usbfs::manager:1405] usbfs: 1 host(s) ready [ 15.291474 0:2 starry_kernel::pseudofs::usbfs:70] usbfs: spawning refresh task [ 15.300187 0:2 starry_kernel::pseudofs::usbfs:34] usbfs: creating filesystem instance [ 15.309411 0:2 starry_kernel::pseudofs:80] Mounted usbfs at /dev/bus/usb [ 15.317485 0:2 starry_kernel::pseudofs::usbfs::irq:238] usbfs: IRQ IrqId { domain: IrqDomainId(9), hwirq: HwIrq(125) } bus 1 host 1133: port change on port 1 [ 15.333116 0:2 starry_kernel::pseudofs:80] Mounted tmpfs at /dev/shm [ 15.345767 0:2 starry_kernel::pseudofs:80] Mounted tmpfs at /tmp [ 15.350215 0:2 starry_kernel::pseudofs:80] Mounted mqueue at /dev/mqueue [ 15.358461 0:2 starry_kernel::dyn_debug:61] debug_init: initializing dynamic debug sites [ 15.368129 0:2 starry_kernel::dyn_debug:64] debug_init: found 201 dynamic debug sites [ 15.377087 0:2 starry_kernel::pseudofs::proc:286] Read kallsyms, size: 1466KB [ 15.393118 0:2 starry_kernel::pseudofs:80] Mounted proc at /proc [ 15.397841 0:2 starry_kernel::pseudofs:80] Mounted sysfs at /sys [ 15.405085 0:2 starry_kernel::pseudofs:80] Mounted sysfs at /sys/bus/usb [ 15.413246 0:2 starry_kernel::pseudofs:80] Mounted debug at /sys/kernel/debug [ 15.421704 0:2 starry_kernel::task::timer:329] Initialize alarm… [ 15.455528 0:2 starry_kernel::entry:81] entry::init: attempting [ 15.462161 0:2 starry_kernel::entry:85] entry::init: bind_console_to succeeded [ 15.467975 0:43 starry_kernel::task::user:70] Enter user space: ip=0x60112100, sp=0x3fffff620 Welcome to Starry OS! [ 15.537021 0:44 starry_kernel::task::user:70] Enter user space: ip=0xf481c, sp=0x3fffff1e0 [ 15.662704 0:40 crab_usb::backend::kmod::hub::device:173] Port 5 connection changed: true [ 15.669565 0:40 crab_usb::backend::kmod::hub::device:188] Port 5 connection changed: connected=true, enabled=false [ 15.681151 0:40 crab_usb::backend::kmod::hub::device:706] Handling connection on port 5, speed: High [ 15.691729 0:40 crab_usb::backend::kmod::hub::device:605] Starting debounce on port 5 (expected_connected: true) [ 15.804230 0:40 crab_usb::backend::kmod::hub::device:627] Port 5 debounce stable (connected: true) [ 15.811657 0:40 crab_usb::backend::kmod::hub::device:661] Resetting port 5 [ 15.870680 0:40 crab_usb::backend::kmod::hub::device:684] Port 5 reset complete [ 15.876762 0:40 crab_usb::backend::kmod::hub::device:767] Port 5 enabled after 1 checks [ 15.885867 0:40 crab_usb::backend::kmod::hub::device:726] Port 5 device ready: speed=High, enabled=true [ 15.903141 0:40 starry_kernel::pseudofs::usbfs::manager:747] [usb-hotplug] bus=1 device=2 logical_id=1 state=connected kind=hub vid=2109 pid=2817 class=0x09 [ 15.915679 0:40 starry_kernel::pseudofs::usbfs::manager:747] [usb-hotplug] bus=1 device=3 logical_id=2 state=connected kind=device vid=2109 pid=8817 class=0x11 [ 16.438496 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) USER=root HOSTNAME=starry HOME=/ro[ 16.580361 0:44 starry_kernel::task::ops:398] Task(44, “env”) exit with code: 0 [ 16.596964 0:44 starry_kernel::task::signal:605] Send signal SIGCHLD to process 1 [ 16.603062 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 16.614210 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WNOHANG) ot [ 16.627995 0:45 starry_kernel::task::user:70] Enter user space: ip=0xf481c, sp=0x3fffff1e0
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin PWD=/
Use apk to install packages.
[ 17.170104 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 17.293238 0:45 starry_kernel::task::ops:398] Task(45, “mkdir”) exit with code: 256 [ 17.307387 0:45 starry_kernel::task::signal:605] Send signal SIGCHLD to process 1 [ 17.313483 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 17.324637 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WNOHANG) [ 17.336554 0:46 starry_kernel::task::user:70] Enter user space: ip=0xf481c, sp=0x3fffff1e0 [ 17.874498 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 17.983657 0:46 starry_kernel::task::ops:398] Task(46, “mkdir”) exit with code: 256 [ 17.997897 0:46 starry_kernel::task::signal:605] Send signal SIGCHLD to process 1 [ 18.003887 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 18.015140 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WNOHANG) [ 18.027152 0:47 starry_kernel::task::user:70] Enter user space: ip=0xf481c, sp=0x3fffff1e0 [ 18.565528 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 18.679087 0:47 starry_kernel::task::ops:398] Task(47, “mkdir”) exit with code: 256 [ 18.693301 0:47 starry_kernel::task::signal:605] Send signal SIGCHLD to process 1 [ 18.699352 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 18.710559 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WNOHANG) [ 18.723555 0:48 starry_kernel::task::user:70] Enter user space: ip=0xf481c, sp=0x3fffff160 [ 19.260992 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 19.384533 0:48 starry_kernel::task::ops:398] Task(48, “touch”) exit with code: 0 [ 19.398556 0:48 starry_kernel::task::signal:605] Send signal SIGCHLD to process 1 [ 19.404550 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 19.415798 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WNOHANG) [ 19.427797 0:49 starry_kernel::task::user:70] Enter user space: ip=0xf481c, sp=0x3fffff160 [ 19.967284 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 20.095336 0:49 starry_kernel::task::ops:398] Task(49, “touch”) exit with code: 0 [ 20.109398 0:49 starry_kernel::task::signal:605] Send signal SIGCHLD to process 1 [ 20.115384 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 20.126638 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WNOHANG) [ 20.138934 0:50 starry_kernel::task::user:70] Enter user space: ip=0xf481c, sp=0x3fffff080 [ 20.676572 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 20.803678 0:50 starry_kernel::task::ops:398] Task(50, “touch”) exit with code: 0 [ 20.817743 0:50 starry_kernel::task::signal:605] Send signal SIGCHLD to process 1 [ 20.823737 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 20.834985 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WNOHANG) [ 20.847018 0:51 starry_kernel::task::user:70] Enter user space: ip=0xf481c, sp=0x3fffff080 [ 21.385036 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 21.510148 0:51 starry_kernel::task::ops:398] Task(51, “touch”) exit with code: 0 [ 21.524221 0:51 starry_kernel::task::signal:605] Send signal SIGCHLD to process 1 [ 21.530212 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 21.541460 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WNOHANG) [ 21.553499 0:52 starry_kernel::task::user:70] Enter user space: ip=0xf481c, sp=0x3fffff080 [ 22.091605 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 22.216411 0:52 starry_kernel::task::ops:398] Task(52, “touch”) exit with code: 0 [ 22.230486 0:52 starry_kernel::task::signal:605] Send signal SIGCHLD to process 1 [ 22.236470 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 22.247726 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WNOHANG) [ 22.259851 0:53 starry_kernel::task::user:70] Enter user space: ip=0xf481c, sp=0x3fffff080 [ 22.798284 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 22.920641 0:53 starry_kernel::task::ops:398] Task(53, “touch”) exit with code: 0 [ 22.934718 0:53 starry_kernel::task::signal:605] Send signal SIGCHLD to process 1 [ 22.940714 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 22.951963 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WNOHANG) [ 22.963999 0:54 starry_kernel::task::user:70] Enter user space: ip=0xf481c, sp=0x3fffff080 [ 23.501996 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 23.630940 0:54 starry_kernel::task::ops:398] Task(54, “touch”) exit with code: 0 [ 23.645039 0:54 starry_kernel::task::signal:605] Send signal SIGCHLD to process 1 [ 23.651036 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 23.662283 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WNOHANG) [ 23.674316 0:55 starry_kernel::task::user:70] Enter user space: ip=0xf481c, sp=0x3fffff080 [ 24.212821 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 24.337029 0:55 starry_kernel::task::ops:398] Task(55, “touch”) exit with code: 0 [ 24.351155 0:55 starry_kernel::task::signal:605] Send signal SIGCHLD to process 1 [ 24.357143 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 24.368398 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WNOHANG) [ 24.380435 0:56 starry_kernel::task::user:70] Enter user space: ip=0xf481c, sp=0x3fffff080 [ 24.918998 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 25.048499 0:56 starry_kernel::task::ops:398] Task(56, “touch”) exit with code: 0 [ 25.062594 0:56 starry_kernel::task::signal:605] Send signal SIGCHLD to process 1 [ 25.068584 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 25.079838 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WNOHANG) [ 25.091871 0:57 starry_kernel::task::user:70] Enter user space: ip=0xf481c, sp=0x3fffff080 [ 25.631344 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 25.757085 0:57 starry_kernel::task::ops:398] Task(57, “touch”) exit with code: 0 [ 25.771196 0:57 starry_kernel::task::signal:605] Send signal SIGCHLD to process 1 [ 25.777184 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 25.788439 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WNOHANG) [ 25.802506 0:58 starry_kernel::task::user:70] Enter user space: ip=0xf481c, sp=0x3fffff1e0 [ 26.338681 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 26.447692 0:58 starry_kernel::task::ops:398] Task(58, “cat”) exit with code: 0 [ 26.461650 0:58 starry_kernel::task::signal:605] Send signal SIGCHLD to process 1 [ 26.467634 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 26.478888 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WNOHANG) [ 26.516482 0:59 starry_kernel::task::user:70] Enter user space: ip=0xdd5b2, sp=0x3fffff460 [ 27.156465 0:59 starry_kernel::task::ops:398] Task(59, “id”) exit with code: 0 [ 27.170368 0:59 starry_kernel::task::signal:605] Send signal SIGCHLD to process 1 [ 27.176383 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WUNTRACED) [ 27.188140 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WNOHANG | WUNTRACED) [ 27.202076 0:60 starry_kernel::task::user:70] Enter user space: ip=0xdd5b2, sp=0x3fffff570 [ 27.245039 0:60 starry_kernel::task::ops:398] Task(60, “run-parts”) exit with code: 0 [ 27.252062 0:60 starry_kernel::task::signal:605] Send signal SIGCHLD to process 1 [ 27.260276 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WUNTRACED) [ 27.272056 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WNOHANG | WUNTRACED) [ 27.285942 0:61 starry_kernel::task::user:70] Enter user space: ip=0xdd5b2, sp=0x3ffffeec0 [ 27.316801 0:61 starry_kernel::task::ops:398] Task(61, “locale-check”) exit with code: 0 [ 27.323895 0:61 starry_kernel::task::signal:605] Send signal SIGCHLD to process 1 [ 27.332302 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WUNTRACED) [ 27.344092 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WNOHANG | WUNTRACED) [ 27.409420 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WUNTRACED) [ 27.418281 0:62 starry_kernel::task::user:70] Enter user space: ip=0xdd5b2, sp=0x3fffff090 [ 27.428502 0:63 starry_kernel::task::user:70] Enter user space: ip=0xdd5b2, sp=0x3fffff090 [ 27.464771 0:62 starry_kernel::task::ops:398] Task(62, “locale”) exit with code: 0 [ 27.474748 0:62 starry_kernel::task::signal:605] Send signal SIGCHLD to process 1 [ 27.480769 0:63 starry_kernel::task::ops:398] Task(63, “dash”) exit with code: 0 [ 27.489543 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WUNTRACED) [ 27.501333 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WUNTRACED) [ 27.513651 0:63 starry_kernel::task::signal:605] Send signal SIGCHLD to process 1 [ 27.522090 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WUNTRACED) [ 27.533858 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WNOHANG | WUNTRACED) [ 27.626881 0:64 starry_kernel::task::user:70] Enter user space: ip=0xdd5b2, sp=0x3ffffedc0 [ 27.635780 0:65 starry_kernel::task::user:70] Enter user space: ip=0xdd5b2, sp=0x3ffffec20 [ 27.645080 0:66 starry_kernel::task::user:70] Enter user space: ip=0xdd5b2, sp=0x3ffffec20 [ 27.654373 0:64 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 27.664449 0:67 starry_kernel::task::user:70] Enter user space: ip=0xdd5b2, sp=0x3ffffec20 [ 27.759032 0:65 starry_kernel::task::ops:398] Task(65, “find”) exit with code: 0 [ 27.766103 0:65 starry_kernel::task::signal:605] Send signal SIGCHLD to process 64 [ 27.774167 0:64 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 27.785186 0:64 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 27.821959 0:68 starry_kernel::task::user:70] Enter user space: ip=0xce5b2, sp=0x3fffff7e0 [ 28.940457 0:66 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 29.070621 0:68 starry_kernel::task::ops:398] Task(68, “cat”) exit with code: 0 [ 29.084549 0:68 starry_kernel::task::signal:605] Send signal SIGCHLD to process 66 [ 29.090927 0:66 starry_kernel::task::ops:398] Task(66, “xargs”) exit with code: 0 [ 29.100319 0:66 starry_kernel::task::signal:605] Send signal SIGCHLD to process 64 [ 29.108658 0:64 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 29.119775 0:64 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 29.182306 0:67 starry_kernel::task::ops:398] Task(67, “tr”) exit with code: 0 [ 29.196203 0:67 starry_kernel::task::signal:605] Send signal SIGCHLD to process 64 [ 29.202276 0:64 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 29.213530 0:64 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WNOHANG) [ 29.225205 0:64 starry_kernel::task::ops:398] Task(64, “dash”) exit with code: 0 [ 29.234521 0:64 starry_kernel::task::signal:605] Send signal SIGCHLD to process 1 [ 29.242913 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WUNTRACED) [ 29.254689 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WNOHANG | WUNTRACED) [ 29.268338 0:69 starry_kernel::task::user:70] Enter user space: ip=0xdd5b2, sp=0x3ffffedc0 [ 29.280365 0:69 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 29.288704 0:70 starry_kernel::task::user:70] Enter user space: ip=0xdd5b2, sp=0x3ffffec20 [ 29.301155 0:71 starry_kernel::task::user:70] Enter user space: ip=0xdd5b2, sp=0x3ffffec20 [ 29.308484 0:72 starry_kernel::task::user:70] Enter user space: ip=0xdd5b2, sp=0x3ffffec20 [ 29.385103 0:70 starry_kernel::task::ops:398] Task(70, “find”) exit with code: 0 [ 29.393818 0:70 starry_kernel::task::signal:605] Send signal SIGCHLD to process 69 [ 29.400139 0:69 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 29.411252 0:69 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 29.440871 0:73 starry_kernel::task::user:70] Enter user space: ip=0xce5b2, sp=0x3fffff7b0 [ 30.630797 0:71 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 30.740971 0:73 starry_kernel::task::ops:398] Task(73, “cat”) exit with code: 0 [ 30.754871 0:73 starry_kernel::task::signal:605] Send signal SIGCHLD to process 71 [ 30.761121 0:71 starry_kernel::task::ops:398] Task(71, “xargs”) exit with code: 0 [ 30.770050 0:72 starry_kernel::task::ops:398] Task(72, “tr”) exit with code: 0 [ 30.779160 0:71 starry_kernel::task::signal:605] Send signal SIGCHLD to process 69 [ 30.795618 0:72 starry_kernel::task::signal:605] Send signal SIGCHLD to process 69 [ 30.801680 0:69 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 30.812941 0:69 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 30.824217 0:69 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WNOHANG) [ 30.835912 0:69 starry_kernel::task::ops:398] Task(69, “dash”) exit with code: 0 [ 30.845328 0:69 starry_kernel::task::signal:605] Send signal SIGCHLD to process 1 [ 30.853627 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WUNTRACED) [ 30.865389 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WNOHANG | WUNTRACED) [ 30.928498 0:74 starry_kernel::task::user:70] Enter user space: ip=0xdd5b2, sp=0x3ffffe240 [ 30.937314 0:75 starry_kernel::task::user:70] Enter user space: ip=0xdd5b2, sp=0x3ffffe120 [ 30.946300 0:74 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 30.956332 0:76 starry_kernel::task::user:70] Enter user space: ip=0xdd5b2, sp=0x3ffffe120 [ 31.031643 0:75 starry_kernel::task::ops:398] Task(75, “grep”) exit with code: 256 [ 31.038875 0:75 starry_kernel::task::signal:605] Send signal SIGCHLD to process 74 [ 31.046876 0:74 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 31.057965 0:74 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 31.704029 0:76 starry_kernel::task::ops:398] Task(76, “head”) exit with code: 0 [ 31.718119 0:76 starry_kernel::task::signal:605] Send signal SIGCHLD to process 74 [ 31.724200 0:74 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 31.735454 0:74 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WNOHANG) [ 31.747132 0:74 starry_kernel::task::ops:398] Task(74, “dash”) exit with code: 0 [ 31.756451 0:74 starry_kernel::task::signal:605] Send signal SIGCHLD to process 1 [ 31.764852 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WUNTRACED) [ 31.776614 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WNOHANG | WUNTRACED) [ 31.790183 0:77 starry_kernel::task::user:70] Enter user space: ip=0xdd5b2, sp=0x3ffffe2c0 [ 31.801295 0:77 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 31.810298 0:78 starry_kernel::task::user:70] Enter user space: ip=0xdd5b2, sp=0x3ffffe1a0 [ 31.822652 0:79 starry_kernel::task::user:70] Enter user space: ip=0xdd5b2, sp=0x3ffffe1a0 [ 31.878954 0:78 starry_kernel::task::ops:398] Task(78, “grep”) exit with code: 256 [ 31.886222 0:78 starry_kernel::task::signal:605] Send signal SIGCHLD to process 77 [ 31.894261 0:77 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 31.905283 0:77 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 32.547656 0:79 starry_kernel::task::ops:398] Task(79, “head”) exit with code: 0 [ 32.561763 0:79 starry_kernel::task::signal:605] Send signal SIGCHLD to process 77 [ 32.567859 0:77 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 32.579092 0:77 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WNOHANG) [ 32.590771 0:77 starry_kernel::task::ops:398] Task(77, “dash”) exit with code: 0 [ 32.600062 0:77 starry_kernel::task::signal:605] Send signal SIGCHLD to process 1 [ 32.608477 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WUNTRACED) [ 32.620252 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WNOHANG | WUNTRACED) [ 32.633855 0:80 starry_kernel::task::user:70] Enter user space: ip=0xdd5b2, sp=0x3ffffe240 [ 32.644922 0:80 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 32.653937 0:81 starry_kernel::task::user:70] Enter user space: ip=0xdd5b2, sp=0x3ffffe120 [ 32.666292 0:82 starry_kernel::task::user:70] Enter user space: ip=0xdd5b2, sp=0x3ffffe120 [ 32.726863 0:81 starry_kernel::task::ops:398] Task(81, “grep”) exit with code: 256 [ 32.734062 0:81 starry_kernel::task::signal:605] Send signal SIGCHLD to process 80 [ 32.742130 0:80 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 32.753188 0:80 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 33.393597 0:82 starry_kernel::task::ops:398] Task(82, “head”) exit with code: 0 [ 33.407678 0:82 starry_kernel::task::signal:605] Send signal SIGCHLD to process 80 [ 33.413755 0:80 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 33.425006 0:80 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WNOHANG) [ 33.436688 0:80 starry_kernel::task::ops:398] Task(80, “dash”) exit with code: 0 [ 33.446055 0:80 starry_kernel::task::signal:605] Send signal SIGCHLD to process 1 [ 33.454397 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WUNTRACED) [ 33.466166 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WNOHANG | WUNTRACED) [ 33.479770 0:83 starry_kernel::task::user:70] Enter user space: ip=0xdd5b2, sp=0x3ffffe2c0 [ 33.490861 0:83 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 33.499873 0:84 starry_kernel::task::user:70] Enter user space: ip=0xdd5b2, sp=0x3ffffe1a0 [ 33.512225 0:85 starry_kernel::task::user:70] Enter user space: ip=0xdd5b2, sp=0x3ffffe1a0 [ 33.571522 0:84 starry_kernel::task::ops:398] Task(84, “grep”) exit with code: 256 [ 33.578713 0:84 starry_kernel::task::signal:605] Send signal SIGCHLD to process 83 [ 33.586812 0:83 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 33.597850 0:83 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 34.240772 0:85 starry_kernel::task::ops:398] Task(85, “head”) exit with code: 0 [ 34.254850 0:85 starry_kernel::task::signal:605] Send signal SIGCHLD to process 83 [ 34.260926 0:83 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 34.272180 0:83 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WNOHANG) [ 34.283863 0:83 starry_kernel::task::ops:398] Task(83, “dash”) exit with code: 0 [ 34.293245 0:83 starry_kernel::task::signal:605] Send signal SIGCHLD to process 1 [ 34.301571 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WUNTRACED) [ 34.313339 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WNOHANG | WUNTRACED) [ 34.326987 0:86 starry_kernel::task::user:70] Enter user space: ip=0xdd5b2, sp=0x3ffffe2c0 [ 34.338019 0:86 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 34.347046 0:87 starry_kernel::task::user:70] Enter user space: ip=0xdd5b2, sp=0x3ffffe1a0 [ 34.359399 0:88 starry_kernel::task::user:70] Enter user space: ip=0xdd5b2, sp=0x3ffffe1a0 [ 34.417240 0:87 starry_kernel::task::ops:398] Task(87, “grep”) exit with code: 256 [ 34.424421 0:87 starry_kernel::task::signal:605] Send signal SIGCHLD to process 86 [ 34.432513 0:86 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 34.443569 0:86 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 35.089458 0:88 starry_kernel::task::ops:398] Task(88, “head”) exit with code: 0 [ 35.103559 0:88 starry_kernel::task::signal:605] Send signal SIGCHLD to process 86 [ 35.109634 0:86 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 35.120891 0:86 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WNOHANG) [ 35.132566 0:86 starry_kernel::task::ops:398] Task(86, “dash”) exit with code: 0 [ 35.141931 0:86 starry_kernel::task::signal:605] Send signal SIGCHLD to process 1 [ 35.150278 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WUNTRACED) [ 35.162048 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WNOHANG | WUNTRACED) [ 35.175643 0:89 starry_kernel::task::user:70] Enter user space: ip=0xdd5b2, sp=0x3ffffe340 [ 35.186749 0:89 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 35.195756 0:90 starry_kernel::task::user:70] Enter user space: ip=0xdd5b2, sp=0x3ffffe220 [ 35.208104 0:91 starry_kernel::task::user:70] Enter user space: ip=0xdd5b2, sp=0x3ffffe220 [ 35.264458 0:90 starry_kernel::task::ops:398] Task(90, “grep”) exit with code: 256 [ 35.271644 0:90 starry_kernel::task::signal:605] Send signal SIGCHLD to process 89 [ 35.279731 0:89 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 35.290786 0:89 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 35.934346 0:91 starry_kernel::task::ops:398] Task(91, “head”) exit with code: 0 [ 35.948432 0:91 starry_kernel::task::signal:605] Send signal SIGCHLD to process 89 [ 35.954506 0:89 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 35.965760 0:89 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WNOHANG) [ 35.977443 0:89 starry_kernel::task::ops:398] Task(89, “dash”) exit with code: 0 [ 35.986806 0:89 starry_kernel::task::signal:605] Send signal SIGCHLD to process 1 [ 35.995153 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WUNTRACED) [ 36.006921 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WNOHANG | WUNTRACED) [ 36.020577 0:92 starry_kernel::task::user:70] Enter user space: ip=0xdd5b2, sp=0x3ffffe340 [ 36.031627 0:92 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 36.040629 0:93 starry_kernel::task::user:70] Enter user space: ip=0xdd5b2, sp=0x3ffffe220 [ 36.052988 0:94 starry_kernel::task::user:70] Enter user space: ip=0xdd5b2, sp=0x3ffffe220 [ 36.113840 0:93 starry_kernel::task::ops:398] Task(93, “grep”) exit with code: 256 [ 36.121043 0:93 starry_kernel::task::signal:605] Send signal SIGCHLD to process 92 [ 36.129128 0:92 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 36.140165 0:92 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 36.781201 0:94 starry_kernel::task::ops:398] Task(94, “head”) exit with code: 0 [ 36.795299 0:94 starry_kernel::task::signal:605] Send signal SIGCHLD to process 92 [ 36.801374 0:92 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 36.812626 0:92 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WNOHANG) [ 36.824308 0:92 starry_kernel::task::ops:398] Task(92, “dash”) exit with code: 0 [ 36.833704 0:92 starry_kernel::task::signal:605] Send signal SIGCHLD to process 1 [ 36.842018 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WUNTRACED) [ 36.853786 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WNOHANG | WUNTRACED) [ 36.867375 0:95 starry_kernel::task::user:70] Enter user space: ip=0xdd5b2, sp=0x3ffffe3c0 [ 36.878515 0:95 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 36.887492 0:96 starry_kernel::task::user:70] Enter user space: ip=0xdd5b2, sp=0x3ffffe2a0 [ 36.899854 0:97 starry_kernel::task::user:70] Enter user space: ip=0xdd5b2, sp=0x3ffffe2a0 [ 36.958959 0:96 starry_kernel::task::ops:398] Task(96, “grep”) exit with code: 256 [ 36.966132 0:96 starry_kernel::task::signal:605] Send signal SIGCHLD to process 95 [ 36.974227 0:95 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 36.985286 0:95 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 37.628720 0:97 starry_kernel::task::ops:398] Task(97, “head”) exit with code: 0 [ 37.642865 0:97 starry_kernel::task::signal:605] Send signal SIGCHLD to process 95 [ 37.648943 0:95 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 37.660197 0:95 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WNOHANG) [ 37.671880 0:95 starry_kernel::task::ops:398] Task(95, “dash”) exit with code: 0 [ 37.681239 0:95 starry_kernel::task::signal:605] Send signal SIGCHLD to process 1 [ 37.689587 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WUNTRACED) [ 37.701357 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WNOHANG | WUNTRACED) [ 37.715003 0:98 starry_kernel::task::user:70] Enter user space: ip=0xdd5b2, sp=0x3ffffe3c0 [ 37.726033 0:98 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 37.735067 0:99 starry_kernel::task::user:70] Enter user space: ip=0xdd5b2, sp=0x3ffffe2a0 [ 37.747397 0:100 starry_kernel::task::user:70] Enter user space: ip=0xdd5b2, sp=0x3ffffe2a0 [ 37.805319 0:99 starry_kernel::task::ops:398] Task(99, “grep”) exit with code: 256 [ 37.812505 0:99 starry_kernel::task::signal:605] Send signal SIGCHLD to process 98 [ 37.820592 0:98 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 37.831648 0:98 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 38.477669 0:100 starry_kernel::task::ops:398] Task(100, “head”) exit with code: 0 [ 38.491964 0:100 starry_kernel::task::signal:605] Send signal SIGCHLD to process 98 [ 38.498122 0:98 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 38.509386 0:98 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WNOHANG) [ 38.521060 0:98 starry_kernel::task::ops:398] Task(98, “dash”) exit with code: 0 [ 38.530424 0:98 starry_kernel::task::signal:605] Send signal SIGCHLD to process 1 [ 38.538772 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WUNTRACED) [ 38.550541 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WNOHANG | WUNTRACED) [ 38.564176 0:101 starry_kernel::task::user:70] Enter user space: ip=0xdd5b2, sp=0x3ffffe440 [ 38.575320 0:101 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 38.584425 0:102 starry_kernel::task::user:70] Enter user space: ip=0xdd5b2, sp=0x3ffffe320 [ 38.596847 0:103 starry_kernel::task::user:70] Enter user space: ip=0xdd5b2, sp=0x3ffffe320 [ 38.653222 0:102 starry_kernel::task::ops:398] Task(102, “grep”) exit with code: 256 [ 38.660579 0:102 starry_kernel::task::signal:605] Send signal SIGCHLD to process 101 [ 38.668861 0:101 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 38.679985 0:101 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 39.322820 0:103 starry_kernel::task::ops:398] Task(103, “head”) exit with code: 0 [ 39.337094 0:103 starry_kernel::task::signal:605] Send signal SIGCHLD to process 101 [ 39.343345 0:101 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 39.354686 0:101 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WNOHANG) [ 39.366458 0:101 starry_kernel::task::ops:398] Task(101, “dash”) exit with code: 0 [ 39.376023 0:101 starry_kernel::task::signal:605] Send signal SIGCHLD to process 1 [ 39.384430 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WUNTRACED) [ 39.396199 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WNOHANG | WUNTRACED) [ 39.409831 0:104 starry_kernel::task::user:70] Enter user space: ip=0xdd5b2, sp=0x3ffffe440 [ 39.420984 0:104 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 39.430082 0:105 starry_kernel::task::user:70] Enter user space: ip=0xdd5b2, sp=0x3ffffe320 [ 39.442503 0:106 starry_kernel::task::user:70] Enter user space: ip=0xdd5b2, sp=0x3ffffe320 [ 39.502835 0:105 starry_kernel::task::ops:398] Task(105, “grep”) exit with code: 256 [ 39.510183 0:105 starry_kernel::task::signal:605] Send signal SIGCHLD to process 104 [ 39.518450 0:104 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 39.529604 0:104 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 40.170549 0:106 starry_kernel::task::ops:398] Task(106, “head”) exit with code: 0 [ 40.184872 0:106 starry_kernel::task::signal:605] Send signal SIGCHLD to process 104 [ 40.191127 0:104 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 40.202468 0:104 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WNOHANG) [ 40.214240 0:104 starry_kernel::task::ops:398] Task(104, “dash”) exit with code: 0 [ 40.223776 0:104 starry_kernel::task::signal:605] Send signal SIGCHLD to process 1 [ 40.232212 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WUNTRACED) [ 40.243981 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WNOHANG | WUNTRACED) [ 40.257574 0:107 starry_kernel::task::user:70] Enter user space: ip=0xdd5b2, sp=0x3ffffe4c0 [ 40.268804 0:107 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 40.277866 0:108 starry_kernel::task::user:70] Enter user space: ip=0xdd5b2, sp=0x3ffffe3a0 [ 40.290297 0:109 starry_kernel::task::user:70] Enter user space: ip=0xdd5b2, sp=0x3ffffe3a0 [ 40.349446 0:108 starry_kernel::task::ops:398] Task(108, “grep”) exit with code: 256 [ 40.356782 0:108 starry_kernel::task::signal:605] Send signal SIGCHLD to process 107 [ 40.365067 0:107 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 40.376211 0:107 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 41.019336 0:109 starry_kernel::task::ops:398] Task(109, “head”) exit with code: 0 [ 41.033663 0:109 starry_kernel::task::signal:605] Send signal SIGCHLD to process 107 [ 41.039916 0:107 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 41.051261 0:107 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WNOHANG) [ 41.063026 0:107 starry_kernel::task::ops:398] Task(107, “dash”) exit with code: 0 [ 41.072568 0:107 starry_kernel::task::signal:605] Send signal SIGCHLD to process 1 [ 41.080999 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WUNTRACED) [ 41.092768 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WNOHANG | WUNTRACED) [ 41.106424 0:110 starry_kernel::task::user:70] Enter user space: ip=0xdd5b2, sp=0x3ffffe4c0 [ 41.117538 0:110 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 41.126651 0:111 starry_kernel::task::user:70] Enter user space: ip=0xdd5b2, sp=0x3ffffe3a0 [ 41.139088 0:112 starry_kernel::task::user:70] Enter user space: ip=0xdd5b2, sp=0x3ffffe3a0 [ 41.196761 0:111 starry_kernel::task::ops:398] Task(111, “grep”) exit with code: 256 [ 41.204102 0:111 starry_kernel::task::signal:605] Send signal SIGCHLD to process 110 [ 41.212406 0:110 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 41.223527 0:110 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 41.869409 0:112 starry_kernel::task::ops:398] Task(112, “head”) exit with code: 0 [ 41.883717 0:112 starry_kernel::task::signal:605] Send signal SIGCHLD to process 110 [ 41.889971 0:110 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 41.901318 0:110 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WNOHANG) [ 41.913083 0:110 starry_kernel::task::ops:398] Task(110, “dash”) exit with code: 0 [ 41.922647 0:110 starry_kernel::task::signal:605] Send signal SIGCHLD to process 1 [ 41.931056 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WUNTRACED) [ 41.942825 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WNOHANG | WUNTRACED) [ 41.956420 0:113 starry_kernel::task::user:70] Enter user space: ip=0xdd5b2, sp=0x3ffffe540 [ 41.967631 0:113 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 41.976710 0:114 starry_kernel::task::user:70] Enter user space: ip=0xdd5b2, sp=0x3ffffe420 [ 41.989146 0:115 starry_kernel::task::user:70] Enter user space: ip=0xdd5b2, sp=0x3ffffe420 [ 42.045824 0:114 starry_kernel::task::ops:398] Task(114, “grep”) exit with code: 256 [ 42.053159 0:114 starry_kernel::task::signal:605] Send signal SIGCHLD to process 113 [ 42.061445 0:113 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 42.072588 0:113 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 42.716945 0:115 starry_kernel::task::ops:398] Task(115, “head”) exit with code: 0 [ 42.731264 0:115 starry_kernel::task::signal:605] Send signal SIGCHLD to process 113 [ 42.737510 0:113 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(0x0) [ 42.748858 0:113 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WNOHANG) [ 42.760629 0:113 starry_kernel::task::ops:398] Task(113, “dash”) exit with code: 0 [ 42.770170 0:113 starry_kernel::task::signal:605] Send signal SIGCHLD to process 1 [ 42.778593 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WUNTRACED) [ 42.790371 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WNOHANG | WUNTRACED) [ 42.804101 0:116 starry_kernel::task::user:70] Enter user space: ip=0xdd5b2, sp=0x3ffffea00 [ 43.445370 0:116 starry_kernel::task::ops:398] Task(116, “id”) exit with code: 0 [ 43.459504 0:116 starry_kernel::task::signal:605] Send signal SIGCHLD to process 1 [ 43.465584 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WUNTRACED) [ 43.477362 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WNOHANG | WUNTRACED) [ 43.490377 0:117 starry_kernel::task::user:70] Enter user space: ip=0xf481c, sp=0x3ffffe610 [ 43.502273 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WUNTRACED) [ 43.774898 0:117 starry_kernel::task::ops:398] Task(117, “systemd-cat”) exit with code: 256 [ 43.787066 0:117 starry_kernel::task::signal:605] Send signal SIGCHLD to process 1 [ 43.793601 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WUNTRACED) [ 43.805297 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WNOHANG | WUNTRACED)
[ 43.821129 0:118 starry_kernel::task::user:70] Enter user space: ip=0xf481c, sp=0x3ffffe610 [ 43.829578 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WUNTRACED) [ 43.970205 0:118 starry_kernel::task::ops:398] Task(118, “systemd-cat”) exit with code: 256 [ 43.979678 0:118 starry_kernel::task::signal:605] Send signal SIGCHLD to process 1 [ 43.986102 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WUNTRACED) [ 43.997858 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WNOHANG | WUNTRACED) [ 44.010935 0:119 starry_kernel::task::user:70] Enter user space: ip=0xf481c, sp=0x3ffffe410 1;31mFailed to cr[ 44.022252 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WUNTRACED) eate stream fd: No such file or directory [ 44.161984 0:119 starry_kernel::task::ops:398] Task(119, “systemd-cat”) exit with code: 256 [ 44.171467 0:119 starry_kernel::task::signal:605] Send signal SIGCHLD to process 1 [ 44.177882 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WUNTRACED) [ 44.189632 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WNOHANG | WUNTRACED) Failed to create stream fd: No such file or directory root@starry:/root # ls [ 46.406168 0:120 starry_kernel::task::user:70] Enter user space: ip=0xf481c, sp=0x3fffff970 [ 46.942884 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WUNTRACED) [ 47.055938 0:120 starry_kernel::task::ops:398] Task(120, “ls”) exit with code: 0 [ 47.070191 0:120 starry_kernel::task::signal:605] Send signal SIGCHLD to process 1 [ 47.076297 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WUNTRACED) [ 47.088052 0:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WNOHANG | WUNTRACED) spacemit-toolchain-linux-glibc-x86_64-v1.2.4.tar.xz root@starry:/root # echo 1 > /proc/set_ai_thread root@starry:/root # ls [ 58.494400 8:122 starry_kernel::task::user:70] Enter user space: ip=0xf481c, sp=0x3fffff970 [ 58.939963 8:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WUNTRACED) [ 59.040106 8:122 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0xffffff0000c68dfc, sepc=0xc68dfc [ 59.048726 8:122 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0xffffff0000c13400, sepc=0xc13400 [ 59.059760 8:122 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0xffffff0000c0a8aa, sepc=0xc0a8aa [ 59.071088 8:122 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0xffffff0000bdd5e6, sepc=0xbdd5e6 spacemit-toolchain-linux-glibc-x86_6[ 59.104138 8:122 starry_kernel::task::ops:398] Task(122, “ls”) exit with code: 0 4-v1.2.4.tar.xz [ 59.122395 8:122 starry_kernel::task::signal:605] Send signal SIGCHLD to process 1 [ 59.128487 8:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WUNTRACED) [ 59.140257 8:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WNOHANG | WUNTRACED) root@starry:/root # cd /home/ubuntu root@starry:/home/ubuntu # cd /clean /bin/sh: 5: cd: can’t cd to /clean root@starry:/home/ubuntu # cd clean root@starry:/home/ubuntu/clean # ls [ 76.977590 8:123 starry_kernel::task::user:70] Enter user space: ip=0xf481c, sp=0x3fffff970 [ 77.420725 8:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WUNTRACED) [ 77.516607 8:123 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0xffffff0000c68dfc, sepc=0xc68dfc [ 77.524998 8:123 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0xffffff0000ab6416, sepc=0xab6416 [ 77.536483 8:123 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0xffffff0000c0a8aa, sepc=0xc0a8aa [ 77.547584 8:123 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0xffffff0000bdd5e6, sepc=0xbdd5e6 pycache bus.png concat.onnx d[ 77.582070 8:123 starry_kernel::task::ops:398] Task(123, “ls”) exit with code: 0 etected.png ort_learn profile.json_1970-01-01_00-01-06_097.json profile.json_1970-01-01_00-01-12_654.jso[ 77.600325 8:123 starry_kernel::task::signal:605] Send signal SIGCHLD to process 1 [ 77.609318 8:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WUNTRACED) [ 77.621088 8:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WNOHANG | WUNTRACED) n profile.json_1970-01-01_00-01-20_254.json profile.json_1970-01-01_00-01-21_788.json profile.json_1970-01-01_00-01-28_740.json profile.json_1970-01-01_00-01-35_361.json profile.json_1970-01-01_00-01-56_156.json profile.json_1970-01-01_00-02-12_264.json profile.json_1970-01-01_00-02-16_972.json profile.json_1970-01-01_00-04-28_412.json profile.json_1970-01-01_00-07-05_718.json profile.json_1970-01-01_00-11-00_322.json riscv_arm riscv_car spacemit-toolchain-linux-musl-x86_64-oh-20260630 starry.jpg uvc yolov5n.onnx root@starry:/home/ubuntu/clean # ./ort_learn [ 81.586451 8:124 starry_kernel::task::user:70] Enter user space: ip=0xf481c, sp=0x3fffff970 [ 81.597615 8:43 starry_kernel::syscall::task::wait:245] sys_waitpid <= pid: -1, options: WaitPidOptions(WUNTRACED) [ 81.622547 8:124 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0x29000, sepc=0x28ffe [ 81.660874 8:124 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0xffffff0000171ffc, sepc=0x171ffc [ 81.679713 8:124 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0x5c3000, sepc=0x5c2ffe [ 81.704560 8:124 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0x5b2000, sepc=0x5b1ffe [ 81.728771 8:124 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0x5c6000, sepc=0x5c5ffe [ 81.752217 8:124 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0x5d2000, sepc=0x5d1ffe [ 81.764221 8:124 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0x5b9000, sepc=0x5b8ffe [ 81.815773 8:124 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0x4bb000, sepc=0x4baffe [ 81.841922 8:124 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0x457000, sepc=0x456ffe [ 81.868162 8:124 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0x45a000, sepc=0x459ffe [ 81.889577 8:124 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0x48d000, sepc=0x48cffe [ 81.901784 8:124 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0x43a000, sepc=0x439ffe [ 81.930034 8:124 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0x48e000, sepc=0x48dffe [ 81.954205 8:124 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0xffffff0000119b48, sepc=0x119b48 [ 81.963149 8:124 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0xffffff0000d50f30, sepc=0xd50f30 [ 81.975460 8:124 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0xffffff0000d52d18, sepc=0xd52d18 [ 81.990449 8:124 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0xffffff00001f6f2c, sepc=0x1f6f2c [ 82.012516 8:124 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0xffffff000003711c, sepc=0x3711c [ 82.027242 8:124 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0xffffff000005c3b0, sepc=0x5c3b0 [ 82.035691 8:124 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0xffffff000006ff0a, sepc=0x6ff0a [ 82.054582 8:124 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0xffffff000009760c, sepc=0x9760c [ 82.065373 8:124 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0xffffff000008191c, sepc=0x8191c image load success [ 85.492060 8:124 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0xffffff000040f09e, sepc=0x40f09e [ 85.559385 8:124 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0x72a000, sepc=0x729ffe [ 85.566906 8:124 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0x72c000, sepc=0x72bffe [ 85.577174 8:124 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0x72d000, sepc=0x72cffe [ 85.590103 8:124 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0x730000, sepc=0x72fffe [ 85.618528 8:124 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0xa0b000, sepc=0xa0affe [ 85.644479 8:124 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0x776000, sepc=0x775ffe [ 85.652553 8:124 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0x90a000, sepc=0x909ffe [ 85.668919 8:124 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0x723000, sepc=0x722ffe [ 85.677217 8:124 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0xa7c000, sepc=0xa7bffe [ 85.689672 8:124 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0x720000, sepc=0x71fffe [ 85.699896 8:124 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0x33a000, sepc=0x339ffe [ 85.722273 8:124 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0x6bf000, sepc=0x6beffe [ 85.734063 8:124 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0x9a3000, sepc=0x9a2ffe [ 85.748361 8:124 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0x7d3000, sepc=0x7d2ffe [ 85.757197 8:124 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0x81c000, sepc=0x81bffe [ 85.770840 8:124 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0xcb0000, sepc=0xcafffe [ 85.781133 8:124 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0xb80000, sepc=0xb7fffe [ 85.793540 8:124 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0xb26000, sepc=0xb25ffe [ 85.827471 8:124 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0x65d000, sepc=0x65cffe [ 85.837276 8:124 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0xc5c000, sepc=0xc5bffe [ 85.853944 8:124 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0xffffff0000310a2a, sepc=0x310a2a [ 85.890696 8:124 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0x64c000, sepc=0x64bffe [ 85.941604 8:124 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0xffffff0000251d50, sepc=0x251d50 [ 86.016607 8:124 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0x67d000, sepc=0x67cffe [ 86.035488 8:124 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0x60d000, sepc=0x60cffe [ 86.127620 8:124 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0xc0e000, sepc=0xc0dffe model load success [ 86.197912 8:124 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0x566000, sepc=0x565ffe [ 86.206603 8:124 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0x579000, sepc=0x578ffe [ 86.236648 8:124 ax_cpu::riscv::uspace:144] Instruction page fault: stval=0xffffff00009c5c44, sepc=0x9c5c44 [ 86.250257 8:124 starry_kernel::pseudofs::dev::accelerator::k3AiCore::device:640] k3_airunner: SUBMIT_GRAPH node pid=124, token=1261637632, node_id=0, op=KernelOp(9) (CONV2D), target_hint=AiTargetHint(0), input_count=3, output_count=1
阶段性工作总结
本阶段完成 K3 AI 从 ONNX Runtime 调用入口、用户态运行时、内核设备通道到 FP16 算子后端的首轮贯通,并已完成一次 YOLOv5 FP16 推理与图片标注验证。
阶段成果
已建立从 ONNX 节点到 K3 内核任务的执行链路:Execution Provider 将可支持的节点转交给 K3
runtime,runtime 将节点描述和 tensor 元数据组织为图请求,通过 K3 AI runner 字符设备提交给
内核;内核调度器随后将任务派发到 k3_kernel_backend。提交、完成等待和资源回收均通过统一的
通道对象管理。
端到端链路已经完成一次 YOLOv5 FP16 推理与图片标注验证。输入图片经预处理后进入 ONNX Runtime 的 K3 Execution Provider;图任务在板端执行完成后,用户态完成输出解码、NMS 和标注图片生成。 该结果确认模型接入、任务提交、完成等待、结果回收和标注输出能够形成闭环。
后端现在以 FP16 为数值计算主路径,并按统一的静态入口分发。公共调用层仍将 AUTO target
归一化为 PREFER_A100,避免各算子对默认 target 作出不同解释;PREFER_CPU 用于软件参考实现。
但为 A100 bring-up,k3_kernel_backend/src/lib.rs 中的 k3_run_kernel 当前有一处临时 patch:
它忽略调度器传入的 target hint,统一改为 PREFER_A100,旁边已保留恢复原始 hint 的 TODO。
该 patch 用于让当前 FP16 模型默认在 A100 上执行,而不是验证 X100 路由;它不是长期的多 target
调度策略。完成 X100 路由和 target-specific dispatch 后,应恢复对调度器 target hint 的透传。
用户态运行时与 ABI
k3_aiRuntime/src/fronted/kd_uring.rs是用户态提交入口。build_channel建立共享内存和设备 通道,submit_graph提交图描述,wait_graph_complete等待完成事件;阅读调度链路时可从这 三个函数开始。k3_aiUabi/src/desc.rs、k3_aiUabi/src/kernel.rs和k3_aiUabi/src/kernelattr.rs定义内核与 用户态共用的描述符、属性、target hint 及 ioctl 相关 ABI。ABI 源码变更会反映到版本哈希,避免 新旧结构体混用造成静默错误。k3_aiRuntime/src/ort_ffi.rs是 ONNX Runtime K3 EP 与 runtime 的桥接层。它校验操作码、执行 目标、tensor 个数、shape、连续 stride 和字节数,再将请求转换为AiGraphNode。FFI 可传递 dense、连续的 tensor 元数据;但进入当前 backend 的数值 tensor 必须为 F16,不满足条件的请求 会在 backend 返回错误。ort_test提供端到端验证程序,可通过带 K3 EP 的 ONNX Runtime 执行 FP16 YOLOv5 推理并完成 图片标注。构建、交叉编译和部署说明见ort_test/README.md;本地 ONNX Runtime checkout 及其 CMake 产物不纳入版本控制。
ONNX Runtime 的 CPU EP 仍可承接 K3 EP 未声明支持的节点;但节点一旦已分配给 K3,执行期错误会 直接返回失败,不能将该节点作为失败重试再交回 CPU。因此排障时需要同时核对提交节点的操作码、 节点编号、target 和 backend 错误码。
算子后端
k3_kernel_backend/src/lib.rs 保留 C ABI 顶层入口,并定义 ComputeKernel。入口按 KernelOp
静态调用对应 marker 的 ComputeKernel::call;各 marker 再按 FP16 与 target 路由到具体实现,
不使用动态注册表。k3_kernel_backend/src/call.rs 集中处理通用 ABI、dense/strided 元数据、属性
读取、target 归一化和 F16 typed view 校验。
主要实现位于 binary.rs、unary.rs、matmul.rs、conv2d.rs、nn.rs 和 transform.rs;
rvv.rs 提供 FP16 路由所需的向量原语。A100 的 IME 只用于矩阵乘的 smt.vfwmadot:固定
8×8×8 tile,以 FP16 相乘、FP32 累加。IME 没有通用逐元素、exp、仿射或 sigmoid 指令,因此
可由 IME 替代的矩阵计算优先走 IME,其余密集 FP16 数值计算走 RVV。具体覆盖范围如下:
| 类别 | 已接入算子或能力 | 当前执行落点 |
|---|---|---|
| 矩阵乘 | MAT_MUL | F16 CPU reference 或 A100 FP16 IME smt.vfwmadot;X100 明确返回不支持 |
| 卷积 | CONV2D,含 group/depthwise 和可选 bias | 通用 im2col 后复用 MAT_MUL 的 A100 IME 路径。padding、stride、dilation、group 等通用几何关系不能由 IME slide 指令的固定偏移表示,因此不单独用 slide 指令替换 im2col |
| 逐元素与归一化 | ADD、SUB、MUL、DIV、SIGMOID、SILU、SCALE、RMS_NORM、ROPE | F16 decode → F32 RVV compute → F16 encode;CPU 保留 reference。SIGMOID、SILU 和 SCALE 也已使用 RVV,不再落到 CPU |
| 逐元素与归一化 | MOD | F16 decode → F32 scalar fmod → F16 encode;广播由 BroadcastPlan 校验 |
| 张量与布局变换 | CONCAT、TRANSPOSE、GATHER、GATHER_ELEMENTS、COPY、CAST、RESIZE、EXPAND、TILE | 连续搬运和索引访问优先使用 RVV copy/gather;布局、axis 和 shape 控制保持标量实现。数值数据使用 F16,Gather 索引支持 I32/I64,必要的 Cast 限制在 F16、I32 和 I64 |
| 常用网络算子 | MAX_POOL、REDUCE_MAX、TOP_K、SOFTMAX、GLU | 密集数值计算复用 RVV primitive;TopK 的选择/排序控制保持标量实现,TopK 和可选 MaxPool indices 输出为 I64 |
RVV 内联汇编中,vsetvli 写入的 VL 输出统一使用 out(reg),确保该输出不会与后续向量 load/store
使用的指针寄存器重叠,避免 f16_sigmoid_work 等路径因指针被 VL 覆盖而访问错误地址。
当前入口的 A100 临时 patch 会让模型中的 MatMul 和 Conv2D 稳定落到上述 A100 IME 路径,而不是
路由到 X100。恢复 scheduler target hint 后,PREFER_X100 仍只覆盖已有的 FP16 RVV 算子;其
MatMul 和 Conv2D 不会静默回退到 CPU,而是返回 UnsupportedOp,从而暴露尚未补齐的 X100 实现。
数值计算 tensor 只接受 F16。F32、BF16、I8、U8 及 ggml 量化 dtype 到达 backend 时返回
UnsupportedDtype;内部允许以 F32 完成累加或参考计算,但不构成 F32 tensor 执行路径。整数仅
保留给 Gather/GatherElements 的索引、TopK 与可选 MaxPool 的 indices 输出,以及受限的 Cast。
量化 ABI 仅保留兼容表面:AiQuantDesc、AiTensorDesc.quant、AiTensorLayout::GGML_QUANT、
量化 dtype 编号和 TensorManager::alloc_ggml_quant_tensor 继续保留,避免破坏外部结构布局与已有
分配接口。backend 已删除 ggml 执行、反量化、量化 MatMul、量化广播和行访问实现;GET_ROWS 与
SET_ROWS 已从属性、分发与实现中移除,操作码 25/26 保留为空洞。k3_kernel_backend/src/quant.rs
以及 LLaMA/ggml 相关测试和参考脚本已移除。
当前算子 backend 的职责是验证执行链路,并不是项目的长期核心。后续可直接切换到 K3 提供的计算 API;需要持续演进的核心仍是图任务、通道、worker、完成事件和核心绑定组成的调度系统。
内核设备与调度
板端支持仓库中的 os/StarryOS/kernel/src/pseudofs/dev/accelerator 新增 K3 AI runner 字符设备。
用户态通过 BUILD_CHANNEL 和 SUBMIT_GRAPH 两类 ioctl 建立通道并提交图;内核侧验证共享区、
登记图任务、唤醒调度器,并在完成后向用户态返回事件。调度日志保留 pid、token、节点编号及映射
后的算子名称,便于把用户态请求与内核执行结果对应起来。
K3 专属调度器以每个 A100 核心对应一个 worker 的方式组织任务。图执行完成、失败或被取消时会 更新节点状态、释放注册资源并通知等待方。与此同时,针对板端用户态取指异常和 cluster CPU 范围 补充了适配,减少跨 cluster 调度和页故障地址处理带来的不确定性。
USB 与 UVC 驱动
USB host 增加了类似 Linux USB ID table 的 interface 到驱动自动匹配机制,核心实现位于板端支持
仓库的 drivers/usb/usb-host/src/driver.rs。枚举完成后,USB core 根据 VID/PID、interface class、
subclass 和 protocol 生成匹配项,依次执行 driver probe;只有 probe 成功后才记录 interface 的
逻辑认领,并在设备断开时调用对应的 disconnect 生命周期。
基于该机制,uvcvideo 薄驱动已能发现并逻辑认领测试摄像头的 Video Control 和 Video Streaming
interface。摄像头的端口连接、描述符读取、interface 匹配和配置协商已验证;伪文件系统也已提供
video0 设备节点和基础 fd 操作接口。当前尚未得到完整视频帧,异步 live device ownership、
VC/VS 双 interface 管理、UVC format/frame descriptor 解析、等时 endpoint 配置和 payload 组帧
尚未接入完整生命周期。
第十周周报(9.13-9.19)
本周因整体计划暂时停滞,未推进新的开发、测试或板端验证工作。
本周记录
- 9 月 18 日复核了第九周记录的
stval异常,并完成原因更正:问题由软件导致,并非 SpacemiT K3 A100 的硬件错误。 - 软件使地址跳出 Sv39 的可表示范围,
sepc(EPC)被截断;stval则依照规范记录完整的 faulting virtual address,因而出现了两者高位不一致的表象。 - 详细的原始现象、复现过程及更正后的结论见:第九周 Bug 发现:SpacemiT K3 A100 偶发产生非法
stval。
复盘
本次误判属于低级错误:面对异常地址时,没有在 QEMU 和 K3 板上对同一地址、同一场景进行真实对比,而是过早认定为板端问题;同时错误地认为 QEMU 的正确实现没有参考价值、不能反映 K3 的问题。事实上,QEMU 的正确行为应作为比对基线,用于检查两端完整地址、sepc/stval 语义以及地址截断路径。
后续安排
待整体计划恢复后,再继续推进后续开发与验证工作。