前言
本人没有 408 基础,之前仅仅是有过 CRUD 的经验,但是对各种底层很感兴趣,最近考试结束正好有时间参加训练营。索性接受了大佬的邀约(毕竟以后也是要做的)。
凭着已有的rust知识速通了,都是基础填空题没啥好说的。
应用填空题,多看几遍就会了,没什么工作量,主要是看。详细报告见二阶段仓库。
https://github.com/LearningOS/2025s-rcore-Vinci-hit
主要感觉还是重在看,只要多看几遍就知道怎么做了,而且有提示,还是填空题。
第一题要求实现HashMap,只需要实现一个HashMap即可,有些坑会自动出现。
第二题要求实现内存分配算法,但其实都已经实现好了只需要学会看懂后调用api即可。
之后的每一题几乎都是只要看懂了会调用api就可以了,代码量都很少。
这个阶段我主要进行了 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系统,结果并不是,有一些实验写下来感觉不如阶段二,不过正因为这个阶段没有那么难,算是比较顺利的在预期时间就做完了,这个阶段开始慢慢的看懂框架代码,随后根据提示完成任务,算是进步比较大的阶段,还需要持续学习,接下来打算试试参加阶段四,拿一个结营证书,同时要好好反思自己,努力学习提升代码能力和计算机基础。
学习 rust 的语法,发现很多都是现代 c++的写法,遂上手很快,但与 c++不同的是,其拥有所有权机制,人为限制了 c++中不安全的写法,对内存更加安全,改正了自己之前写 c++时候的乱用指针,引用的不安全的写法,同时也学会了一门新的语言。
为了实现 sys_trace 系统调用(ID 为 410),我们查看了任务系统的机构,在其中人为的加上了我们所需要的参数,使得我们对 TCB 的结构熟悉和了解
我们实现了 mmap syscall ID:222 和 munmap syscall ID:215 的系统调用,其中,我们了解到每个任务的 mm,也就是 TCB 中 memory_set,中的结构有了更加深刻的了解。我们只需要在其中的 area 完成插入和删除。
这里要求我们实在 spawn 进程,因此,我们可以根据将其类似为 fork + exec ,其中,不必像 fork 一样复制父进程的地址空间。我们只需要新建一个地址空间,其中,我们需要新建一些虚拟区域,然后就可以完成,整体类似于与 fork + exec 的逻辑,其中,只是没有复制其地址空间。
然后,要我们完成 stride 调度算法,我们可以直接参考 manager 中的 fifo 的实现来进行更改,其中,manager 增加 BIG_STRIDE 这个成员,然后 tcb 中的 inner 加入 priority 和 Stride 这两个成员(因为是可变的)。这个时候,我们需要每次调度的时候寻找最小的 Stride,linux 中是采用红黑树查询的,但是这里比较简单,我们就直接使用轮询的方式。
要求我们去完成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
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 的写入
根据要求,我们,需要 Available ,为含有 m(资源数量) 个元素的一维数组,我们可以把他放到 process 中,其中他检测每个资源,根据题意要求,我们可以分别给 mutex 和 semaphore 设计一个。同时在线程中(task),我们需要添加相应的 Allocation 和 Need,其中长度为 mutex 和 semaphore 的数量,我们在修改相应的,创建,lock,unlock 函数的逻辑,按照作业中要求我们使用的逻辑和流程去完成编写。于此同时,我们需要修改 task 的创建,进程的初始化,fork 函数的逻辑,这样,我们就可以通过了。
这个阶段,我们需要完成以下内容:
print_with_color 很简单,我们只需要理解一下 axstd 模块,然后对照着对 println 这个宏进行修改
support_hash_map 比较困难,这里我偷了个懒,使用了 hashbrown::HashMap,这个过程中我们需要注意编译时候的条件限制,我们需要这样去进行条件编译
1 | #[cfg(feature = "alloc")] |
alt_alloc 很简单,我们按照 ppt 的提示,我们完成其 byte 和 page 的 api 的编写,只需要实earlyAllocatortrait 就可以接入内核中了
ramfs_rename 也不是很难,要把 cargo 里的包换成 arceos 下面的,找到对 trait 去实现 rename 函数,我们可以参照上面的创建和删除的 api,我们只需要修改就是修改两个 DirNode 下的BTreeMap<String, VfsNodeRef>
接下来我们从 Unikernel 到了宏内核,我们需要完成以下内容:
sys_map 我们可以按照提示,参考 m1_0,我们需要在 current 的task_ext提供的接口去使用,我们可以使用 man 工具具体的查看每个参数的作用,根据其为 NULL 的时候,我们需要找片空地,在翻 aspeace 提供的 api 中,我们可以使用find_free_area,在按照其逻辑,如果有文件,读文件,写入,就是文件映射,没有,就直接返回所寻找的虚拟地址。等实际使用爆出页错误再进行处理。
在 Unikernel 的基础上引入 RISC-V 的 H 扩展,获得了虚拟化的能力。我们需要虚拟化 cpu,内存和进程。我们需要完成以下内容:
simple_hv,我们只要在 vmexit_handler中处理异常,然后给 a0,a1 赋值,我们就可以完成我们的任务。
相比 rcore,arceos 复杂了许多,但是 arceos 中的很多思想思路都出现在 rcore 中,所以我们学习,上手的就很同时我们了解了组件化内核,其可以到 Monolithic Kernel 和 Hypervisor 中,我收获到了很多。同时遇上了很多的困难,在与伙伴聊天中收获到了很多的思路,看到了很多优秀的人。
rcore的五个实验,捋清楚代码,就比较好做。这是我第一次捋这么多代码量的项目,学到了很多。以下几点是我理解并做出实验的心得。
这是rcore训练营前三个阶段的总结报告。
做实验的过程中有写一些笔记,不过是写给自己看的,行文有些杂乱:rcore-notes,arceos-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本身的设计理念来满足测试要求。整体难度不大,理解起来也比较顺利。
相比于语言本身,算法部分的挑战更大。虽然按照要求可以找到相应算法的描述,照着实现基本能完成任务,但有两个方面:
偶然有天看到 Rust 中文社区的公众号转发了一个开源 OS 训练营的消息,点进去一看原来是 rCore,早就听过 rCore 这个项目,但一直没来得及学习,自己也对 Rust 在嵌入式开发和内核中的应用很感兴趣,于是转发到群里忽悠了几个朋友一起组团参加