0%

个人碎碎念

了解到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指导书的质量非常高。学习到了很多。

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

一阶段

总结

第一阶段主要是rustling,只需要应用Rust本身的设计理念来满足测试要求。整体难度不大,理解起来也比较顺利。

难点

相比于语言本身,算法部分的挑战更大。虽然按照要求可以找到相应算法的描述,照着实现基本能完成任务,但有两个方面:

  1. 同类算法的取舍:平均复杂度同为O(n)的两种算法,在同一实际场景中的表现不同,我并不了解这些算法的最佳适用区间。
  2. 不同实现的差异:同一个算法,采用不同的数据结构实现,所需的时间和空间开销也会不同。

    二阶段

    总结

    第二阶段主要是对操作系统的认识。每个实验大致分为三步:
  3. 阅读相关材料,了解操作系统的相关知识;
  4. 梳理实验中涉及的类与函数的层级结构及其功能;
  5. 编写实验代码,完成具体实现。
    整体过程也比较顺利。

    难点

    二阶段对文件相关内容印象最深,文件系统这个从纯指针一步一步抽象到文件的过程,通过多个层级的抽象来提供简单的交互,通过各种锁和标记来管理权限和控制并发,让我对C的便利性、内存管理有了更深刻的理解。

    三阶段

    总结

    三阶段有些难度,主要侧重于基于unikernel的模块化内核,不像二阶段那样深入去看代码,这就导致有些实验,虽然我知道应该怎么做,但是不知道我需要的函数在哪里,这也跟vscode工具不熟练有关;有的实验,我虽然知道怎么做,但是实现的位置不对,导致与其他实验冲突。

    难点

  6. 在rename里,由于入口时fs.root.rename,而在dirnode里只能通过parent查找父节点,通过children查找子节点,造成了根节点的识别与文件查找的差异,之后再看到rename的标注,仅能在同一mountpoint的文件系统内使用,才明白实验的ramfs就是在/tmp下,就是这么设计的。
  7. 挑战题没有过线,tlsf实现后达到162。本来的计划是先实现一次tlsf,再优化。但是tlsf实现的工程量超出预期,本身的代码量就有很多,还有很多debug用的log和test,应该是我抽象的层级不够。

    未尽

  8. 找到更好的代码分析方法,更好地梳理函数调用
  9. 使用debug mode,目前都是通过log调试
  10. 完成挑战题,重新设计一个内存分配方法
  11. 最后两个视频未完成

偶然有天看到 Rust 中文社区的公众号转发了一个开源 OS 训练营的消息,点进去一看原来是 rCore,早就听过 rCore 这个项目,但一直没来得及学习,自己也对 Rust 在嵌入式开发和内核中的应用很感兴趣,于是转发到群里忽悠了几个朋友一起组团参加

Read more »

作为二战选手,上次秋冬训练营止步于第四阶段,之后痛定思痛恶补了一下CSAPP还有RUST圣经,操作系统等这种基础课,还猛猛的参加了Rust训练营,今年磨拳擦掌卷土重来⸜( •ᴗ• )⸝

第一阶段

第一阶段属于是轻车熟路了,通过链表的编写更深刻的理解了Rust的裸指针和智能指针,感慨学无止境,同时也在读张汉东老师的Rust编程之道,后面死灵书等一系列内容都在排队等着学习,对语言的探索多深都不为过。

第二阶段

上一届对于汇编ld文件makefile文件这种东西稀里糊涂,经过过年前后的闭关,把这些知识都补起来了,为了更了解RISCV都汇编指令,通关了傲来训练营的一二三阶段,又自己学习了RISC-V体系结构编程与实践,现在ld文件也看得懂了,makefile也能自己改了,汇编和高级语言之间的调用也知道咋回事了,剩下的就是确定范围和补全逻辑了,有了上一次的经验,这回对从批处理,到进程再到线程的进化有了更深的体会。

第三阶段

第三阶段,上一届前进到写完hashmap因为别的事情就没有继续了,这回有时间慢慢来,一层一层弄清楚调用关系,感受何为模块化操作系统。不过仅是对功能的修改觉得不够尽兴,我也自己拉了一个repo写一个自己的操作系统玩一玩。

阶段一

这一阶段是rustlings刷题,主要是对rust的学习,我接触Rust有一段时间了,Rustlings之前刷过两遍,对我来说还是比较轻松的。

阶段二

这一阶段是rcore的练习,涉及到很多计算机底层软硬件的知识,收获很多。

1. 1~3章

  1. 对与程序的内存布局,代码段,数据段,堆,栈,有了更加深刻的认识,学习了高级语言如何与汇编语言进行交互,以及对程序编译链接过程有了的进一步认识
  2. 对中断机制有了进一步的了解,学习了中断的处理流程,以及如何在中断处理中保存和恢复寄存器的值
  3. 学习了如何在Rust中嵌入汇编语言,以及如何在Rust中调用C语言函数。
  4. 学习了CPU硬件特权级的概念,以及如何切换特权级
  5. 学习了处理机调度的概念,中断处理流程,以及如何实现基于时间片的的任务切换

2. 第4章

第四章是我花了最多时间的一章,以前对操作系统的内存管理仅仅停留在课本的知识,这一章让我对操作系统的内存管理有了更加深入的了解。

  1. 学习SV39的页表结构,对逻辑地址和物理地址的转换有了更加深入的了解,尤其是加深了对逻辑地址,物理地址,页表项,页内偏移量的理解
  2. 学习地址空间的切换,以及如何在切换地址空间时保存和恢复寄存器的值,确保操作系统和用户态程序能够正常运行。
  3. 学习了操作系统如何管理物理内存,以及如何在物理内存中分配和回收内存。
  4. 学习地址空间映射,了解和恒等映射,之前一直在纠结如何保证再开启虚拟内存后操作系统的正确运行。

3. 第5章

第五章是进程管理的章节,主要是学习了进程管理的相关知识,包括进程的创建,退出,等待,以及进程的调度,对进程的概念比较熟悉。

4. 第6章

第六章是文件系统的章节,主要是学习了文件系统的相关知识,包括文件系统的概念,文件系统的实现,以及文件系统的接口。

5. 第7~8章

学习了进程rCore的并发机制,包括信号量,锁,条件变量等概念,以及如何在rCore中实现这些机制。对银行家算法中的资源有了更加深入的了解。

阶段三

第三阶段是对arceos的学习,对组件化OS的设计有了宏观的认识,从unikernel到宏内核再到Hypervisor。相比于rCore,arceos的项目组织更加清晰,代码更加模块化,也更加易于理解。
让我印象最为深刻的是Hypervisor的实现,我之前对Hypervisor的理解是模拟计算机硬件,然后客户机在这些虚拟硬件中执行,对于硬件虚拟化的认识是比较浅的。

总结

这次操作系统训练营是一次非常有收获的经历。

rCore 2025 spring blog

第一阶段

  • 这一阶段主要就是了解学习Rust的语法和特性,以及完成所有的rustlings题目, 以及实现一些基础的数据结构和算法, 为之后的项目内容做准备.
  • 由于我之前是写Go的并没有接触过Rust,第一阶段以至于后续阶段的编码过程的感觉都非常割裂。

第二阶段

  • 第二阶段由多个小lab组成,个人感觉是有一些lab比第三阶段的lab更难,测试用例也更多,每次做都得看看实验指导书才敢下手,也是提前开始做阶段二后面的进度才能赶上来。

第三阶段

  • 第三阶段跟着ppt和自己的os理解在慢慢探索,如果没有给出提示我可能要花费两倍的时间才能写完,最后也是瞎摸索完成了阶段三,感觉对操作系统的理解又进了一步的感觉,但还需要持续学习。
Read more »