wyp-tg-rcore-tutorial-ch1-multicore-0.1.5 is not a library.
todo
- 整理文档
- 添加自旋锁练习
- 添加测试脚本
第一章扩展:多核启动演示
本项目在第一章(ch1)的基础上扩展多核支持,演示 RISC-V 多核启动和核间协调的基本原理。
🎯 项目特点:
- 📚 教育导向:配套完整的学习文档和调试记录
- 🔬 自包含实现:包含内建 M-mode SBI,无需外部依赖
- ⚡ 零开销:直接裸机启动,最小运行时
- 🛠️ 易于调试:详细的文档和常见问题解答
学习目标
通过本章的学习和实践,你将理解:
- HART(Hardware Thread):RISC-V 对"处理器核"的称呼
- mhartid CSR:每个核独有的 ID 寄存器
- 多核启动流程:Boot HART 与从核的启动时序
- WFI 指令:让从核进入低功耗停放状态
前置知识:建议先完成第一章(ch1)的学习,理解裸机启动、SBI 调用等基础概念。
项目结构
wyp-tg-rcore-tutorial-ch1-multicore/
├── .cargo/
│ └── config.toml # Cargo 配置:支持多核运行
├── .gitignore
├── doc
└── llvm
└── spec
└── somemd
├── build.rs # 构建脚本:生成链接脚本
├── Cargo.toml
├── README.md
├── run.sh # 运行脚本
├── rust-toolchain.toml
└── src/
└── main.rs # 内核源码:多核启动演示
编译与运行
编译
运行
方式一:使用脚本(推荐)
# 默认使用 2 核
# 指定核数
方式二:手动运行
# 单核模式
# 双核模式
# 四核模式
预期输出
单核模式(-smp 1):
[HART 0] Hello from core 0
[HART 0] I am the boot HART, shutting down...
双核模式(-smp 2):
[HART 0] Hello from core 0
[HART 1] Hello from core 1
[HART 0] I am the boot HART, shutting down...
[HART 1] Parking (entering WFI loop)...
注意:多核输出可能交错,这是正常现象。
核心概念
1. 核 ID 传递机制
重要发现:mhartid 是 M-mode 专用 CSR,S-mode 无权直接读取!
因此我们采用 M-mode 传递核 ID 到 S-mode 的方式:
# M-mode 入口 (_m_start)
csrr t0, mhartid # 读取核 ID
mv a0, t0 # 通过 a0 寄存器传递给 S-mode
mret # 切换到 S-mode
# S-mode 入口 (_start)
mv s0, a0 # 保存 M-mode 传递的核 ID
# ... 设置栈 ...
mv a0, s0 # 传递给 rust_main
j rust_main
Rust 接收参数:
extern "C" !
为什么这样做?
mhartidCSR 地址为0xF14,属于 M-mode 控制状态寄存器- S-mode 尝试读取会触发非法指令异常
- 使用 a0 寄存器传递参数符合 RISC-V 调用约定
2. 多核启动流程
┌─────────────────────────────────────────────────────────────┐
│ Step 1: 上电 │
│ 只有 Boot HART (通常是 HART 0) 先运行 OpenSBI │
├─────────────────────────────────────────────────────────────┤
│ Step 2: OpenSBI 初始化 │
│ 初始化硬件,唤醒其他核 │
├─────────────────────────────────────────────────────────────┤
│ Step 3: 跳转到内核 │
│ 所有核跳转到 _start (0x80200000) │
├─────────────────────────────────────────────────────────────┤
│ Step 4: 读取 mhartid │
│ 每个核读取自己的 ID,区分身份 │
├─────────────────────────────────────────────────────────────┤
│ Step 5: 分支执行 │
│ 主核继续执行,从核进入停放状态 │
└─────────────────────────────────────────────────────────────┘
3. WFI 指令
WFI(Wait For Interrupt)让处理器进入低功耗等待状态:
!
WFI 的特点:
- 不会阻塞程序执行,只是"建议"处理器暂停
- 有中断时,处理器会退出低功耗状态
- 使用循环确保持续处于等待状态
关键代码解析
1. 独立栈空间
每个核需要独立的栈空间,避免数据冲突:
// 在 _start 中:
// 栈顶 = STACK 基地址 + STACK_SIZE * (hart_id + 1)
// 每个核使用独立的 4KB 栈空间
2. 核角色判断
if hart_id == BOOT_HART_ID else
思考题
- 为什么每个核需要独立的栈空间? 如果共享栈会发生什么?
- 输出交错是 bug 吗? 如何解决输出交错问题?
- 如果想让从核后续执行任务,需要什么机制?
📚 完整文档
本项目提供完整的学习文档,帮助你深入理解多核编程:
核心文档
- 规范文档:OpenSpec 多核支持规范,定义能力、接口和验收标准
- 开发手册:完整的开发流程、设计决策和实现细节
- 调试记录:
mhartid特权级限制问题的完整调试过程 - Bug 分析报告:总结 4 个典型错误模式和解决方案
- 学习检查点:知识理解和概念确认问答
- 学习心得:学习收获、思考感悟和对后续学习者的建议
- 进阶:同步机制:多核输出交错问题的解决方案与实现 ⭐ 推荐
快速导航
| 文档 | 目标读者 | 预计时间 |
|---|---|---|
| 开发手册 | 想了解实现细节 | 30 分钟 |
| Bug 分析 | 遇到问题需要参考 | 20 分钟 |
| 检查点问答 | 巩固概念理解 | 15 分钟 |
| 学习心得 | 初学者入门指导 | 25 分钟 |
| 同步机制 | 进阶学习同步原理 | 40 分钟 |
关键 Bug 分析
在 S-mode 直接读取 mhartid 导致程序卡死,因为:
mhartid是 M-mode 专用 CSR- S-mode 无权访问,触发异常
- 解决方案:M-mode 读取后通过 a0 寄存器传递给 S-mode
参考资料
- RISC-V Privileged Architecture Specification
- RISC-V Reader 中文版
- rCore-Tutorial-Book 第三章:中断机制
下一步
本 crate 是多核扩展的第一阶段,下一阶段将实现:
- ch2 多核扩展:主核执行批处理应用,从核停放
- 核间中断(IPI):唤醒从核的机制
- 同步机制:自旋锁、原子操作等
Dependencies
本项目是自包含的,不需要外部依赖:
- ✅ 内建 M-mode SBI 实现(
src/sbi/) - ✅ 直接硬件访问(UART、CLINT)
- ✅ 无运行时依赖,最小化复杂度
适用人群
- 🎓 正在学习操作系统课程的学生
- 🔧 希望了解多核编程的开发者
- 📖 对 RISC-V 架构感兴趣的爱好者
- 🏫 教授操作系统课程的教师
参考项目
本项目基于以下项目开发:
- rCore-Tutorial - 操作系统教程
- wyp-tg-rcore-tutorial-ch1-clock - 时钟中断扩展参考
- tg-rcore-tutorial - 教程源码仓库
贡献
欢迎提交 Issue 和 Pull Request!
License
Licensed under GNU General Public License v3.0 or later (LICENSE).
致谢
本项目基于 rCore-Tutorial 开发,感谢 rCore 团队的开源贡献。