0%
2025春操作系统训练营四阶段报告
第一阶段 - Rust编程
- 这一阶段主要就是了解学习Rust的语法和特性, 以及完成所有的rustlings题目, 以及实现一些基础的数据结构和算法, 为之后的项目内容做准备.
- 我对rust的语法已经比较熟悉了, 其实rustlings之前也做过一遍, 所以很快, 但数据结构和算法的rust实现有点忘了, 这部分花了点时间
第二阶段 - OS设计实现
- 仓库连接: https://github.com/LearningOS/2025s-rcore-jizhaoqin
- 这一阶段花了挺多时间, 因为一个完整的os内核内容和代码真的很多
- chapter1 应用程序与基本执行环境
- 这一届内容比较少, 主要是关于如何实现一个最小内核, 以及RustSBI使用的一些问题
- chapter2 批处理系统:
- 由于我以前没有接触过risc-v指令集和汇编语言, 所以在理解汇编指令, 链接脚本, 还有特权级的切换方面花了很多时间, 最后也是能够理解实验里给的代码都有什么作用
- 另外, 我找了内容更多的v3版文档阅读前两章, 发现内容确实很详细, 但不适合做实验, 因为对我来说是在是太多了, 当个参考书挺好, 遇到camp文档疑惑的地方去查以下非常有用, 因为逻辑是一样的, 但是跟着v3文档一步一步写代码实在是很痛苦, 主要是进度太慢了, 没有反馈动力不足继续做下去了.
- 所以后来我就主要看camp文档了, 而且不再一步一步跟着自己实现, 主要是在每一章的练习部分, 在实现的过程中再去仔细理解每一个模块的作用, 这样会好很多对我来说, 理解地也很快.
- chapter3 多道程序与分时多任务
- 这一章实现了简单的抢占式任务调度, 主要内容是程序上文的保存和切换
- chapter4 地址空间:
- 这一章内存虚拟化是非常重要的内容, 之后内核态和用户态就会在内存映射上隔离, 区分更明显了, 同时对上下文切换的汇编代码进行了一些补充修改
- 这一章对多级页表的介绍其实不详细, 但是我以前实现过x86架构上一个简单的4级页表, 以及动态内存分配器, 所以整体理解没有问题, 但是需要了解更多关于SV39多级页表的一些细节
- chapter5 进程及进程管理:
- 介绍了进程的抽象的实现, 在这个实验里相对于内存虚拟化来说并不难理解
- 通过进程实现经典的sys_fork()和sys_exec()系统调用
- 而且从这一张开始有了一个简单的shell了
- chapter6 文件系统与I/O重定向:
- os的又一大关键功能, 提供文件抽象和接口
- 这一章是目前为止最费劲的一章, 因为抽象层数太多了, 实现系统调用的时候非常容易搞乱, 而且到这里代码已经很多了, 层数也很深, 花了非常多的时间去理解调用的每一层都干了什么事, 但一些没有直接用到的API没有多看. 好在最后实现完成后, 本地测试一遍就通过了, 还是挺好的.
- chapter7 进程间通信:
- 主要实现进程间管道通信, 这里基于文件抽象来实现
- 在shell里还实现了重定向符号
>, <
- chapter8
- 简单的笔记:
- 线程的用户态栈:确保在用户态的线程能正常执行函数调用;
- 线程的内核态栈:确保线程陷入内核后能正常执行函数调用;
- 线程的跳板页:确保线程能正确的进行用户态<–>内核态切换;
- 线程上下文:即线程用到的寄存器信息,用于线程切换。
- 线程抽象, 并发的要求, 锁的实现, (一般)信号量与实现, 条件变量
- 这一节还好, 对锁还算比较了解, 然后互斥锁是2元信号量, 也比较好理解, 就是条件变量不熟悉, 因为结尾的练习似乎不太需要, 对这一部分也没有改动.
第三阶段 - 组件化操作系统
- 仓库连接: https://github.com/LearningOS/2025s-arceos-jizhaoqin
- [print_with_color]:
- 可以使用ANSI转义序列, 修改终端输出的颜色
- 可以在用户层
println!
, axstd
的输出宏定义处, 或者axhal
处修改putchar
, 影响的范围也不同
- [support_hashmap]:
- 语言提供的
alloc
crate里中提供了一些常用的集合类型比如Vec
和BTreeMap
, 禁用标准库时只需要提供全局动态分配器就可以使用, 在Acreos里打开alloc
feature就行
- 但是
HashMap
除了分配器还需要提供随机数生成器, 所以不在alloc
crate里需要自己实现.
- [alt_alloc]:
- [ramfs_rename]:
- 文件系统相关的实现和API
- 对于rename来说, 其实就是在目录文件的数据块里删除一个条目, 同时新增一个条目, 但都指向相同的索引节点, 理论上也可以直接修改条目中的文件名, 但更复杂需要做出大量修改(因为现有条目储存用的是
BTreeMap
把文件名作为key不支持修改), 会引入额外的逻辑开销而且不会提升性能, 所以使用现有的删除和新增功能就好了
- [sys_mmap]:
- [simple_hv]:
第四阶段 - 项目三: 基于协程异步机制的操作系统/驱动
- 仓库连接: https://github.com/jizhaoqin/arceos/tree/dev-async-irq
- 汇报连接: https://docs.google.com/presentation/d/1VZuvpDa1Ot9joiWxl2y-eviw-mX34QQXLZYLFYfCR1c/edit?usp=sharing
- 选题方向:
- 主要目标是尝试对部分非实时中断异步化, 具体以uart串口通信为例, 实时意味着需要立即处理完毕, 非实时中断则不要求中断信息能马上处理完毕, 对这种中断我们可以将其放在后台运行而不阻塞当前逻辑, 比较适合将其转化为异步任务进行处理.
- 需要注意的是, 我们一般要求所有中断都要求立即返回, 但这并不意味着中断已经处理完毕, 比如网络包下载, 或者高负载串口通信, 有些信息处理比较耗时, 这时为了快速结束中断, 我们可以将未经处理的数据放入缓冲区队列, 然后在结束中断前通知异步任务进行处理.
- 另外由于目前Arceos对几乎所有外部设备都采用轮询方式, 所以在异步化之前, 先要将其改造为基于中断的方式.
- 过程:
- 架构和具体目标: aarch64 qemu virt platform的uart中断异步改造.
- 首先在
axhal
中给对应platform注册uart中断并启用, qemu将terminal的用户输入模拟为串口通信, 经测试arceos能够按照预期以中断的方式接收串口信号.
- 这一部分的难点在与梳理清楚arceos的中断架构, 注册和调用流程, 以及各架构
axhal
, axruntime
, axstd
, arceos_api
之间以及内部的代码和依赖结构.
- 之后尝试异步改造uart的中断处理函数. 如之前提到的, 我们将中断处理分为两个部分:
- 第一部分是同步的, 需要原封不动地接受所有信息并将其推送到缓冲区队列, 并发送信号表明有数据需要处理.
- 这一部分的难点在于如果处理程序是异步的, 我们如何从同步的中断处理函数中发出合适的通知信号.
- 第二部分是异步的, 为数据处理程序, 在这里我们采取异步的方式, 由一个异步运行时维护有多个中断第二部分数据处理程序的队列(由于目前只注册了一个中断, 队列中只有uart中断的异步处理任务), 并进行调度, 与内核线程调度不同的是, 这些处理任务都在同一个线程中.
- 这一部分的难点在与, 如何构建一个非标准库环境下的异步执行器, 来轮询和调度这些异步任务.
- 成果:
- 最终完成了aarch64 uart的中断注册,
- 实现了中断处理函数的异步改造,
- 构建一个内核异步运行时并进行调试, 以完成异步中断处理的执行和调度工作.
- 未来可能的方向:
- 整理代码结构, 符合arceos的规范, 形成良好的文档
- 尝试兼容更多中断类型, 用统一的异步中断处理异步运行时处理更多类型的非实时中断.
- 兼容更多架构
- 优化异步运行时的调度逻辑, 以及实现优先级调度等功能.
- 将异步运行时替换为更成熟的embassy
- 实现过程中遇到的困难:
- 尝试注册键盘中断进行测试, 发现需要开启qemu graphic实现显示设备驱动, 而且兼容性差, 所以不搞键盘中断了, 直接搞串口中断, 目前arceos的实现都是轮询;
- x86_64 qemu q35 平台没查到COM1 uart的中断向量, 导致一直没能成功注册中断, 而且x86的x2apic架构比较复杂, 执行了irq映射难梳理, 最后花了很多时间也没搞明白中断向量到底是啥;
- 后来转向aarch64, 成功注册uart中断, 并测试表现良好符合预期;
- 尝试异步化改造中断处理, 查看embassy的实现有些复杂不好拆解, 最后决定从头手写一个简单的异步执行器, 花了好大力气才搞定, 测试能工作;
- 尝试把异步运行时和中断处理结合起来的时候总是有交叉依赖的问题, 最后把异步任务通知逻辑和执行逻辑分别放在
axhal
和axruntime
, 才最终解决交叉依赖.
- 执行器阻塞线程不主动yield, 直到一个周期后被抢占才切换到其他线程, 而其他线程正常yield, 这使得执行器线程占用了几乎所有CPU时间
- 最后又更改了中断处理流程, 添加了两个缓冲区才最终把逻辑跑通
- 其他:
- 为较大项目添加特性是一件很困难的事, 除了考虑本特性的实现, 还要嵌合进整个项目的组织框架和编译逻辑中, 不敢想象如果没有好的代码架构, 抽象以及解耦, 可以想象越到后来, 最终将达到一个极限, 使得这一工作几乎不可能完成.