0%

前言

大家好,我是ACrazyShark(李卓恒)。今年2月,我和志同道合的同学们组队报名了全国大学生系统能力赛操作系统内核赛道,开启了操作系统开发的探索之旅。备赛过程中,我们有幸接触到由清华大学等高校打造的rcore训练营——这个以Rust语言重写Linux内核的实践项目,不仅帮助我们构建了从理论到落地的完整知识体系,更让我们在”通过开源学习开源”的理念中感受到系统级编程的魅力。

Read more »

阶段一

rustlings的练习还是比较基础的,实在想不起来某个知识点还可以去rust圣经翻翻文档。不过貌似后面的dsa部分对于rcore的练习基本没啥用处。

阶段二

之前有过自己搓内核(没有文件系统),以及做xv6 for riscv的lab的经验,实际到ch6为止都十分顺畅,ch6的部分实现参考了2023秋训练营的代码,ch8则是在线程的粒度上实现银行家算法,码量相对较少。

阶段三

配置环境的时候遇到点小插曲,qemu.mk指定bios为default,结果没有正确加载固件,后面指定固件加载路径解决了这个问题。

第三阶段的题目普遍简单,可能是框架基本搭好了所以实际工作量也减少了。此外arceos因为是unikernel架构,各个组件功能耦合较低,对应练习需要修改的地方也一目了然。

每日记录放在https://github.com/kangrali/oscamp-2025-blog

第一阶段

主要是语言学习,详细阅读了Rust Programming Language中文书,然后做练习。

因为有C++知识的积累没有遇到太大的问题

第二阶段

主要是阅读实验指导书,理解rCore整体的框架

个人任务需要理解的几个关键点:

  • trap上下文的保存与恢复,对应了用户特权级和内核特权级的切换
  • 任务上下文的保存与恢复,对应了任务(线程)的切换
  • 地址空间,内核态和用户态使用不同的页表

详细报告见二阶段仓库https://github.com/LearningOS/2025s-rcore-kangrali

第三阶段

这一阶段主要通过看课程视频完成,关键在于理解整个项目的代码架构,代码是如何组织到各个层次的crates中的。

至于完成的练习都难度不大,了解各模块的调用关系后,做简单修改或调用api就可完成。

前言

本人没有 408 基础,之前仅仅是有过 CRUD 的经验,但是对各种底层很感兴趣,最近考试结束正好有时间参加训练营。索性接受了大佬的邀约(毕竟以后也是要做的)。

Read more »

第一阶段

凭着已有的rust知识速通了,都是基础填空题没啥好说的。

第二阶段

应用填空题,多看几遍就会了,没什么工作量,主要是看。详细报告见二阶段仓库。
https://github.com/LearningOS/2025s-rcore-Vinci-hit

第三阶段

主要感觉还是重在看,只要多看几遍就知道怎么做了,而且有提示,还是填空题。

第一题要求实现HashMap,只需要实现一个HashMap即可,有些坑会自动出现。

第二题要求实现内存分配算法,但其实都已经实现好了只需要学会看懂后调用api即可。

之后的每一题几乎都是只要看懂了会调用api就可以了,代码量都很少。

第一阶段:Rustling 与 Rust 基础练习

这个阶段我主要进行了 Rustling 题目的练习和 Rust 编程语言的基础训练。因为我本身有一定编程基础,所以整体难度对我来说并不高,主要是为了熟悉 Rust 的语言风格和核心概念,比如所有权、借用、模式匹配等。为后面更深入的系统开发打下了语言基础。


第二阶段:操作系统内核功能实现

到了第二阶段,框架已经搭建好,任务主要是完成其中某些具体功能模块的实现。虽然刚开始面对内核设计和系统调用这样的内容有些抽象,但随着理解的深入,实际的编码和调试也渐渐变得顺利起来。
具体详情见:https://github.com/LearningOS/2025s-rcore-Tecto-Wang


第三阶段:借助资料进行模块化理解

第三阶段的学习方式更为系统。我通过 PPT 和视频资料来逐步学习实现细节,并通过留空的方式聚焦于具体模块的实现。这样的方式可以集中注意力专注于每一个点,然后再逐渐拼凑出整个系统的全貌。相比第二阶段,这种学习方式更轻松、更具条理,也帮助我对整个系统架构的整体理解。


个人碎碎念

了解到rCore训练营是一位大佬拉我一起参加的,之前没有参加过类似的训练营,没有学习过rust,对os的理解也只停留在408里面片面的os(实际做下来跟应试学习的完全是两个东西)。回想起来当时在做之前应该先去看一下除提供的文档之外的os知识,很多时候也缺少走读代码和理解代码的能力,拖团队后腿了。
通过这次训练营,意识到自己很菜,一开始还是蛮焦虑的(虽然现在也是),跟不上大家,后来焦虑多了也在心态上有一些变化,开始慢慢走读现有的代码,结合训练营提供的资料一步一步理解任务,再根据自己的理解完成任务,不懂的就在团队的小群上问群友,也是比较艰辛的把三个阶段给完成了。
也是感谢几位群友,在我拖后腿的时候都会比较耐心的等我慢慢做,本来队伍还打算拿优胜队长的奖励的hhh。

第一阶段

由于是第一次接触rust,之前只接触过java,写起来非常割裂,并且在一些java可以的地方,rust是禁止的,就比如在类型检查上。rust的match以及一些闭包函数是蛮好用的(这里也要小小的吐槽一下rust实现链表太麻烦了。

第二阶段

这个阶段主要是了解系统内核,学习rCore指导书并且完成五个实验,这个阶段有大半时间都处在焦虑状态,没有好好的理解指导书和代码内容,结果就是一些实验需要靠群友帮助才能完成。但还是学习到了os底层的运作方式,多任务系统,虚拟地址空间映射,进程的管理调度,文件系统,锁的实现。印象最深的就是在写sys_linkat的时候由于没有走读理解现有的代码,愣是卡了一周才完成。

第三阶段

这个阶段原以为是在阶段二的基础上继续添加完善os系统,结果并不是,有一些实验写下来感觉不如阶段二,不过正因为这个阶段没有那么难,算是比较顺利的在预期时间就做完了,这个阶段开始慢慢的看懂框架代码,随后根据提示完成任务,算是进步比较大的阶段,还需要持续学习,接下来打算试试参加阶段四,拿一个结营证书,同时要好好反思自己,努力学习提升代码能力和计算机基础。

Read more »

2025 年春夏开源操作系统训练营三阶段总结

第一阶段总结

学习 rust 的语法,发现很多都是现代 c++的写法,遂上手很快,但与 c++不同的是,其拥有所有权机制,人为限制了 c++中不安全的写法,对内存更加安全,改正了自己之前写 c++时候的乱用指针,引用的不安全的写法,同时也学会了一门新的语言。

第二阶段总结

lab1

为了实现 sys_trace 系统调用(ID 为 410),我们查看了任务系统的机构,在其中人为的加上了我们所需要的参数,使得我们对 TCB 的结构熟悉和了解

lab2

我们实现了 mmap syscall ID:222 和 munmap syscall ID:215 的系统调用,其中,我们了解到每个任务的 mm,也就是 TCB 中 memory_set,中的结构有了更加深刻的了解。我们只需要在其中的 area 完成插入和删除。

lab3

这里要求我们实在 spawn 进程,因此,我们可以根据将其类似为 fork + exec ,其中,不必像 fork 一样复制父进程的地址空间。我们只需要新建一个地址空间,其中,我们需要新建一些虚拟区域,然后就可以完成,整体类似于与 fork + exec 的逻辑,其中,只是没有复制其地址空间。

然后,要我们完成 stride 调度算法,我们可以直接参考 manager 中的 fifo 的实现来进行更改,其中,manager 增加 BIG_STRIDE 这个成员,然后 tcb 中的 inner 加入 priority 和 Stride 这两个成员(因为是可变的)。这个时候,我们需要每次调度的时候寻找最小的 Stride,linux 中是采用红黑树查询的,但是这里比较简单,我们就直接使用轮询的方式。

lab4

要求我们去完成pub fn sys_linkat(_old_name: *const u8, _new_name: *const u8) -> isize这样的调用接口,仿照上面的 sys_open()我们可以也写一个类似于 open_file 的函数,其形式为:pub fn __sys_linkat(_old_name: &str, _new_name: &str) -> isize我们在__sys_linkat 中就可以调用 ROOTINODE 中的 linkat 方法。对于 linkat 方法,我们可以参照上面 create 方法,我们只需要注意以下:pub fn linkat(&self, _old_name: &str, _new_name: &str) -> isize

  • 判断 oldname 的文件不为空,为空直接返回负一
  • 由 oldname 中寻找 inode_id,而不是像 create 中直接 alloc_inode 得到

unlinkat:

​ 前面于 linkat 相同,当到了 ROOTINODE 中的 unlink 方法pub fn unlink(&self, name: &str) -> isize接下来,其思路和 linkat 完全相反,由于这里不要求我们删除,我们便不管

fstat:

​ 参考文档,我们只需要获取 ino 和 nlink。其中 ino 我们写一个 osnode 中的get_inode_id,其中,类型转化我们写一个 any 的 trait,将其转换,nlink 我们写一个 get_link_num 的方法,数有几个 DirEntry。再将其数据写入_st 中,我们便完成的 fstat 的写入

lab5

根据要求,我们,需要 Available ,为含有 m(资源数量) 个元素的一维数组,我们可以把他放到 process 中,其中他检测每个资源,根据题意要求,我们可以分别给 mutex 和 semaphore 设计一个。同时在线程中(task),我们需要添加相应的 Allocation 和 Need,其中长度为 mutex 和 semaphore 的数量,我们在修改相应的,创建,lock,unlock 函数的逻辑,按照作业中要求我们使用的逻辑和流程去完成编写。于此同时,我们需要修改 task 的创建,进程的初始化,fork 函数的逻辑,这样,我们就可以通过了。

第三阶段总结

Unikernel

这个阶段,我们需要完成以下内容:

  1. 带颜色的输出
  2. 手写一个 HashMap
  3. 实现 bump 内存分配算法
  4. 在 axfs_ramfs 下实现 rename 功能

print_with_color 很简单,我们只需要理解一下 axstd 模块,然后对照着对 println 这个宏进行修改

support_hash_map 比较困难,这里我偷了个懒,使用了 hashbrown::HashMap,这个过程中我们需要注意编译时候的条件限制,我们需要这样去进行条件编译

1
2
#[cfg(feature = "alloc")]
pub mod collections;

alt_alloc 很简单,我们按照 ppt 的提示,我们完成其 byte 和 page 的 api 的编写,只需要实earlyAllocatortrait 就可以接入内核中了

ramfs_rename 也不是很难,要把 cargo 里的包换成 arceos 下面的,找到对 trait 去实现 rename 函数,我们可以参照上面的创建和删除的 api,我们只需要修改就是修改两个 DirNode 下的BTreeMap<String, VfsNodeRef>

Monolithic Kernel

接下来我们从 Unikernel 到了宏内核,我们需要完成以下内容:

  1. 实现 sys_mmap

sys_map 我们可以按照提示,参考 m1_0,我们需要在 current 的task_ext提供的接口去使用,我们可以使用 man 工具具体的查看每个参数的作用,根据其为 NULL 的时候,我们需要找片空地,在翻 aspeace 提供的 api 中,我们可以使用find_free_area,在按照其逻辑,如果有文件,读文件,写入,就是文件映射,没有,就直接返回所寻找的虚拟地址。等实际使用爆出页错误再进行处理。

Hypervisor

在 Unikernel 的基础上引入 RISC-V 的 H 扩展,获得了虚拟化的能力。我们需要虚拟化 cpu,内存和进程。我们需要完成以下内容:

  1. 支持 simple_hv

simple_hv,我们只要在 vmexit_handler中处理异常,然后给 a0,a1 赋值,我们就可以完成我们的任务。

总结

相比 rcore,arceos 复杂了许多,但是 arceos 中的很多思想思路都出现在 rcore 中,所以我们学习,上手的就很同时我们了解了组件化内核,其可以到 Monolithic Kernel 和 Hypervisor 中,我收获到了很多。同时遇上了很多的困难,在与伙伴聊天中收获到了很多的思路,看到了很多优秀的人。

rcore第二阶段

rcore的五个实验,捋清楚代码,就比较好做。这是我第一次捋这么多代码量的项目,学到了很多。以下几点是我理解并做出实验的心得。

  1. 不需要全部细节搞懂。理解调用过程并不需要关注所有细节。
  2. 先提出问题,再去找答案。可以用gpt辅助提问题。
  3. debug其实后面用的都少了,多用log。
  4. 关注层次,有些理解不了就是站的角度不对,从内核视角看,从用户视角看,从文件系统各个层次看,等等,可以切换视角来整体性的把握代码。
  5. 有些是代码写出来是方便查看,但并不一定有啥功能上的作用。所以有些地方不用太纠结。
  6. 画图!只要你能画出内存、追踪寄存器、理解调用过程,那其实内核没啥难的,每一步都是可以追踪的。多画图让自己可视化的把握这整个过程。尤其是ch8那个死锁算法,我自己画图,把整个过程都画一遍,案例自己走了一遍,那就很清晰了。
  7. 读代码不要线性读过去。可以让gpt梳理流程再读。同时可以一个变量一个变量追踪,上来全部看会云里雾里的。
  8. 个人感觉makefile和一些rust嵌入式可以搜索b站相关资料学习一下。有这两个基本技能就能先对内核代码是怎么生成的、为啥是内核、怎么写的,有个框架性的把握。
  9. 不需要让自己了解很多前置知识才能开始,盯着具体问题去思考补啥知识。
  10. 对于每个题目,印象最深的就是多体会案例吧,毕竟是练习用的,很多情况不考虑的。
  11. 文档第一遍应该是略看,大概知道一下知识,最重要的是自己捋代码。
  12. 印象最深的是死锁那里,没有drop导致多重借用了。

arceos第三阶段

  1. 一开始不理解feature怎么传递的,感觉搞不懂了,心态爆炸。但是往后做就理解了,em所以前期真的不用纠结太多我觉得。
  2. arceos这里在toml里面一堆文档阿,先看这个会有更宏观的把握。
  3. 最难的感觉就是开始,了解了re-export这个机制,重新认识了一下rust的项目管理,之后就没啥了。
  4. 这里印象最深的是文件系统和对齐,前者再让我体会了lsp机制不完善吧,然后通过条件编译管理以达到组件化的效果也是学到了,我看大多数都会有一个接口或者一个默认的实现,然后再用条件编译来管理不同的实现,估计第四阶段会进一步用到吧。

这是rcore训练营前三个阶段的总结报告。

做实验的过程中有写一些笔记,不过是写给自己看的,行文有些杂乱:rcore-notesarceos-notes


在群里看到有人分享rcore训练营的消息,然后在rcore开营启动会那天加入了进来。对os的很多概念一直只能靠想象,没有代码级的理解,通过这次训练营,学到了非常非常多。以前尝试去看过《一个64位操作系统的设计与实现》这本书,但是这本书并无过多讲解,并不适合入门os代码,读不动。现在有了训练营的基础,后面有时间再试试。

训练营的内容大部分时间是读代码,完成练习所需写的代码量并不大。训练营准备了详尽的文档与指导书,并已经准备好了构建脚本,能非常顺利地上手开始学习os。

此外,这次训练营学习还连带着学习了rust,之前听说过rust和其它语言在思维上有些不同,不过实际接触下来感觉还好,还是和c++很相似的,只是有个所有权的机制很特别。rust吸收并处理了c++的一些好的概念与不足(移动语义,没有包管理器等等),有Cargo这一点比c++方便多了。

第一阶段

学习rust基础,做rustlings的练习。

这个比较基础,我是看了下rust的菜鸟教程学rust,然后做的过程中不知道的问chatgpt就行。

第二阶段

学习rcore指导书并完成5个实验。

rcore指导书的质量非常高,前几章基础的代码需要仔细阅读理解,这样就能知道基础的执行流程。

前面的章节把一些代码(比如那几个汇编写的函数)交给chatgpt解读非常方便。后面的章节效果要差一些,有些主要起个提示作用。

第三阶段

学习arceos并完成6个练习。

原本以为第三阶段是第二阶段的递进,会去学习M态的rustabi什么的,但是实际第三阶段的arceos是和rcore指导书平级的,相当于是另一种设计思路下实现的os。

有了第二阶段rcore指导书的基础,第三阶段问题不大。

总结

训练营的质量非常高,特别是考虑到了对学生的教学,文档和工程都很齐全,rcore指导书的质量非常高。学习到了很多。

感谢清华大学的老师们开放的课程,以及助教,群友等的答疑。