Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 70 additions & 0 deletions .agents/skills/dragonos-general-development-workflow/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
---
name: dragonos-general-development-workflow
description: >
DragonOS 通用开发流程技能。
当任务涉及以下任一场景时使用:(1) 设计或修复 DragonOS 内核功能、系统调用、procfs/sysfs/devfs 行为;
(2) 审查 DragonOS 代码或 PR;(3) 对比 Linux 6.6 语义进行实现或验证;
(4) 分析或修复 gVisor 系统调用测试失败;(5) 添加 dunitest 内核单元测试覆盖;
(6) 在 QEMU nographic 模式下运行和交互 DragonOS。
---

# DragonOS 通用开发流程

## 核心规则

- DragonOS 应提供 Linux 兼容的用户可见行为,严格对照 Linux 6.6 源码语义。
- 用户需在任务开始时提供以下路径(如未提供则主动询问):
- **$LINUX_SRC**:本地 Linux 6.6 源码路径
- **$GVISOR_TESTS**(可选):gVisor 测试源码路径
- 如果用户未提供且任务涉及 Linux 语义对比或 gVisor 测试,**必须先询问路径再继续**。
- 代码审查注重内存安全、并发安全,尤其涉及系统调用、procfs、sysfs、devfs、VFS、调度器、信号、IPC、内存管理、网络和驱动可见行为。
- (可选)新回归测试优先使用 dunitest(自动化 CI 回归的一部分);不要仅在遗留的 `user/apps/c_unitest` 中添加新覆盖,除非用户明确要求或没有可行的 dunitest 路径。
- **不得使用 workaround 方法绕过失败的测试**:不得为通过特定测试而修改 gVisor 测试用例、不得用绕过方法掩盖根因、不得特化某个观察到的用例。用架构合理、向 Linux 6.6 源码语义对齐的方式在 DragonOS 中修复**根因**。
- 仅允许修改 DragonOS 仓库内的文件,除非用户明确要求修改全局配置或外部文件。
- 不得修改 `env.mk`。如果已被修改过,视为用户拥有的状态:不触碰、不还原、不纳入任何 git commit。
- 不得在公开产物(PR 描述、issue 评论等)中提及用户本地的已修改文件(如 `env.mk`),除非用户明确要求。
- 提交使用英文 Conventional Commits 格式(如 `fix(vfs): handle mount propagation edge case`),使用 `git commit -s` 签署。代码注释用中文描述修复的根因和改动的语义,并避免提及测试细节或用户本地状态。
- 灵活利用 subagent 并行拆解和分析问题,将研究结果汇总到主 agent,避免在主上下文中做深度推理。

## 参考路径

- DragonOS 仓库:当前工作目录
- Linux 参考源码:**$LINUX_SRC**(用户提供)
- (可选)gVisor 系统调用测试:**$GVISOR_TESTS**(用户提供,仅 gVisor 相关任务时询问)
- (可选)DragonOS dunitest 测试:在 DragonOS 树中搜索现有 dunitest 模式后再添加新测试。

## 强制开发循环

### 适用性判断
根据任务性质选择执行路径:

| 任务类型 | 典型触发语 | 执行路径 |
|---|---|---|
| **实现/修复** | "实现"、"修复"、"添加"、"改一下"、"卡死"、"fails" | 完整循环 Step 0-6 |
| **纯调查/问答** | "解释"、"分析"、"为什么"、"怎么实现的"、"看看" | 仅 Step 1(研究),然后直接回答 |
| **代码审查** | "审查"、"review"、"看看这段代码"、"对比" | Step 1(研究)+ Step 5(对照审查) |
| **混合/不确定** | 既有调查又有"然后修复"的意图 | 先完整执行 Step 1,确认意图后再决定是否进入 Step 2-6 |

当用户只要求调查、解释、分析代码行为时,**不要进入实施循环**。完成研究后直接报告发现即可。

### 循环步骤
0. **复现**(仅缺陷修复任务必做;纯新增功能跳过此步):在修复前的 DragonOS 内核上构建并运行相关复现程序/测试。优先通过 PTY 在 QEMU 中启动 DragonOS 并在 guest 内验证。复现后保留等效测试作为修复后验证。
1. **研究**:捕获用户可见的症状/失败测试/panic 日志。阅读相关的 DragonOS 实现及附近抽象。阅读 **$LINUX_SRC** 下对应的 Linux 6.6 源码实现(调用路径、数据结构不变量、锁/生命周期、返回值、errno、边界情况)。必要时阅读相关测试(gVisor 系统调用测试、现有 dunitest)。
2. **制定计划**(仅在该研究之后):阐明**根因**或**语义差距**。标识需要变更的 DragonOS 模块/文件及变更理由。描述要匹配的 Linux 行为和边界情况。包含验证步骤、预期测试覆盖和残余风险。计划必须符合核心规则(无 workaround、无测试特化)。制定计划时,加载 [references/plan-prompts.md](references/plan-prompts.md) 将模板嵌入任务提示。
3. **审查计划**:检查是否遵循 Linux 语义、适配 DragonOS 架构、保持并发和生命周期不变量。如果计划不完整或有风险,**先修订计划**。
4. **实施**(仅计划通过审查后):限定变更范围在计划中的文件。如果实施揭示了**不同的根因或架构问题**,**立即停止**并告知用户,然后马上回到 Step 2 重新制定计划。
5. **实施后再审查**:重新阅读 **$LINUX_SRC** 相关 Linux 源码,对比最终 DragonOS 行为、数据流、锁/生命周期、错误路径和边界情况。如发现语义不匹配,回到 Step 2。
6. **验证**:可以使用针对性的 dunitest 或 gVisor 覆盖。先运行 `make fmt` 进行代码格式化和 clippy 检查,再运行 `make kernel` 确保编译通过。对于影响内核/用户可见行为的变更,构建 DragonOS,通过 PTY 在 QEMU 中启动,在 guest 内验证(dunitest 路径:`/opt/tests/dunitest/bin/normal/`)。详细的 QEMU 操作步骤见 [references/qemu-operations.md](references/qemu-operations.md)。报告任何未能运行的验证及原因。当需要创建 PR 时,在根因修复已提交、推送并创建 PR 后任务完成。

## 相关技能

以下技能按场景分类,配合本通用开发流程使用:

### 代码审查
- **bug-hunter**:大规模 PR、复杂逻辑变更、安全敏感改动的多智能体并行缺陷检测。触发语:"用 bug-hunter 跑一遍"、"做深度bug检测"

### 测试分析与修复
- **dragonos-gvisor-test-analysis**:分析 gVisor 系统调用测试失败,对比 Linux/gVisor 参考实现,输出结构化修复文档。触发语:"gVisor 测试挂了"、"分析这个 gVisor 失败测例"

### 调试疑难问题
- **dragonos-atomic-snapshot-debug**:调试内核时序问题、Heisenbug、阻塞挂起、丢唤醒。触发语:"任务卡住了"、"CPU idle 但请求不返回"、"在线取证"
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# 必需的计划提示

在为 DragonOS 设计功能计划、实施计划、审查计划或缺陷修复/根因计划时,在提示或任务框架中嵌入以下指令:

```text
先结合 $LINUX_SRC 的 Linux 源码、问题现象 和 DragonOS 代码,深入研究,再制定 plan。

制定计划后先审查 plan 是否符合 Linux 源码语义、DragonOS 架构、并发/生命周期不变量、错误路径和边界条件,确认符合核心规则(无 workaround、无测试特化)后才实施代码变更。若审查发现计划不完整、有风险、或 DragonOS 现有架构有明显问题,必须重新分析 $LINUX_SRC 的 Linux 源码,重新修订计划,再审查,直到计划通过审查后才能实施代码变更。

代码变更后,必须再次结合 $LINUX_SRC 的 Linux 源码审查 DragonOS 实现。如果发现语义不一致、架构不合理、边界条件遗漏、并发/生命周期风险 或 workaround,必须回到 plan 阶段重新制定修复计划,再继续实施。

所有方案都要参考 Linux 源码、DragonOS 代码深入研究,并且制定正确、完善、无坑点、架构合理、功能正确的实现/根因修复计划。

Linux 源码路径:$LINUX_SRC
```

其中 `$LINUX_SRC` 替换为用户提供的 Linux 6.6 源码实际路径。
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# QEMU Nographic 模式运行 DragonOS

## 目录

- [命令选择](#命令选择)
- [成功信号](#成功信号)
- [交互流程](#交互流程)
- [命令投递规则](#命令投递规则)
- [sudo 处理](#sudo-处理)
- [失败分类](#失败分类)
- [实用注意事项](#实用注意事项)

## 命令选择

- 当用户需要正常运行路径时使用 `make run-nographic`:根据需要重建内核/用户程序,更新 rootfs/磁盘镜像,然后启动 QEMU。
- 当用户明确要求**跳过**重建内核且避免更新 rootfs,或已有最新镜像且任务仅需启动/交互时,使用 `make qemu-nographic`。
- 从 DragonOS 仓库根目录运行这些命令。

> 如果是 nix 用户,可以用 `nix run .#start-x86_64` 来等效替代 `make qemu-nographic`,用 `make kernel && nix run .#start-x86_64` 简单替代 `make run-nographic`(如需更新rootfs 需要先执行 `nix run .#rootfs-x86_64`)。
> 如需更多详情 先读 `docs/introduction/develop_nix.md`,确认文档仍然推荐使用以上命令。

## 成功信号

启动过程中重点盯以下日志,逐条确认:

- `Kernel Build Done.`
- `DragonOS release ...`
- `Successfully migrate rootfs to ext4!`
- `Boot with specified init process`
- `Please press Enter to activate this console.`
- `root@dragonos:~#` 或等价 shell prompt

如果看到 panic、init 启动失败、mount 失败、卡死在早期阶段,要把原始日志摘出来,而不是一直等待。

## 交互流程

1. 在支持 TTY 的终端会话中使用上述命令之一启动 QEMU。
- 必须使用交互式 PTY,否则后续无法和 QEMU 串口交互。
2. 等待启动日志到达 `Please press Enter to activate this console.`。
3. 向 PTY 写入换行符 `\n` 激活控制台(等同于按 Enter),等待 `root@dragonos:~#` prompt 出现。
4. 逐条输入命令(见下方[命令投递规则](#命令投递规则))。快速验证命令:

```sh
pwd
uname -a
ls /
```

5. 如果在目标模式下验证 dunitest 或 gVisor 测例时,在 guest 内运行相关的已安装测试二进制:

```sh
# dunitest
cd /opt/tests/dunitest/bin/normal/
./xxx_test
```
```
# gVisor
cd /opt/gvisor/tests/
./xxx_test
# 如果是特定测试的某些部分,可以通过正则表达式匹配,如:
./xxx_test --gtest_filter=*Process*:*Pid*
```

将 `xxx_test` 替换为变更对应的具体测试二进制,例如 `kill_test`。

6. 向 PTY 写入 `\x01x`(即 按 Ctrl-A 然后跟着按 x)退出 QEMU nographic 模式。

## 命令投递规则

- 一次只写一条命令,等 `root@dragonos:~#` prompt 回来后再发下一条。
- 不要把多条命令一次性塞给 guest(串口会吞字、错行、把后续命令打坏)。
- 不要把"命令执行了"误写成"功能通过了"——执行成功和结果正确是两回事。
- 如果 shell 卡住,先判断是否命令本身阻塞(如 `cat` 无输入等待),不要立即判成死锁。
- 如果写文件时报 `Function not implemented`、`Permission denied`、`No such file or directory`,要原样记录。

## sudo 处理

- `make qemu-nographic` 会直接使用现有的 `bin/kernel/kernel.elf` 和 `bin/disk-image-x86_64.img`,无需sudo。
- `make run-nographic` 可能需要宿主机权限,因为镜像更新路径会挂载/写入磁盘镜像。
- 若不是 root 用户,可以向用户索要密码。如果用户已经提供密码,用下面命令预热 sudo:

```bash
printf '%s\n' "$PASSWORD" | sudo -S -v
```

在同一个 PTY 会话中紧接着运行 `make run-nographic`,确保 sudo 时间戳在写盘阶段仍有效。

- 如果写盘耗时特别长(如首次构建大型 rootfs),sudo 可能过期。此时应告知用户,而不是自动启动 keepalive 循环。
- 如果看到 `sudo: The "no new privileges" flag is set`,说明是宿主机/沙箱权限边界,不是 DragonOS 回归;应改为在沙箱外执行同一命令。

## 失败分类

失败可能发生在不同阶段,不要跨阶段误判:

| 失败阶段 | 典型症状 | 正确判断 | 常见误判 |
|---|---|---|---|
| **编译** (make kernel) | `error[E...]`、linker error | 编译错误,返回首个真正报错点 | ❌ 不要误判为内核运行时 bug |
| **写盘** (rootfs/disk image) | `cp: cannot stat ...`、`write_diskimage` 失败、`Bad message` | 宿主机文件系统/镜像构建问题 | ❌ 不要误判为 guest 启动失败 |
| **sudo 提权** | `sudo: timed out`、`Permission denied` | 宿主机权限问题 | ❌ 不要误判为内核回归 |
| **QEMU 启动** | 串口无输出、kernel panic、卡在早期启动 | 内核/启动问题,保留串口日志第一处异常 | ❌ 不要误判为编译错误或未使用新编译的内核 |
| **guest 运行** | 命令返回错误、测试失败、shell 卡住 | guest 内功能问题,原样记录错误信息 | ❌ 不要把"命令执行了"当成"功能通过了" |

## 实用注意事项

- Nographic 串口输出也会写入 DragonOS 仓库根目录的 `serial_opt.txt`。当终端输出过长或有溢出上下文的风险时,使用有针对性的 `rg`/`grep`/`tail` 命令检查该文件,而不是读取整个终端缓冲区。

```sh
rg -n "Please press Enter|root@dragonos|ERROR|WARN|panic|Boot with specified init" serial_opt.txt
tail -n 200 serial_opt.txt
```

- 如果 `make run-nographic` 在写入磁盘镜像时失败,记录实际错误。纯交互测试的有效回退方案是 `make qemu-nographic`,但不要将其视为 rootfs 更新测试。
- 已观察到的一种非权限失败情况:在成功构建内核后,在 `bin/mnt/disk-image-x86_64` 下反复出现 `cp: cannot stat '.../bin/...': Bad message`,随后 `write_diskimage` 失败。在这种情况下,`qemu-nographic` 可能仍能用现有镜像启动,但完整的镜像更新路径未成功。
- 测试后避免在后台留下 QEMU 运行。始终用 `\x01x` 关闭,除非用户要求保持会话打开。
Loading