Rust & RISC-V & Rcore
第一次知道 rcore 这个项目是在一个 CS 的开源交流群里,因为一直是开发小白,想要找一些项目来写,提升自己的实力。
暑假开始学 xv6,但是因为旅游计划搁置了,刚好开学后听闻 rcore 的项目,脑袋一拍就想参与,并也是进入以后才了解到 rust 语言。
起初参加的原因只是希望找人和我一起写课程来督促我成长,因为本人很容易分心。但是这个问题在开始写 lab 以后就眼小云散了,发现自己在写实验的时候还是很专注,能够投入时间的。
在学习了第一阶段的 rustlings 后,我了解到了很多独属于 rust 本身的魅力,比如所有权,又比如unsafe,同时 rust 的编译器比较严格,能够在编译层面上杜绝一大部分难以在代码层面上发现的 BUG,
同样的,riscv 架构是一个新兴架构,指令集简洁且开源,易于掌握和学习。
下面简单总结一下在第二阶段我完成的各个实验情况。
ch3
本次实验在一个分时多任务系统架构的基础上实现了一个当前任务信息查询调用。
从系统调用的层面上(S态)实现了该功能。
sys_task_info调用的实现建立在对TaskManager的修改的基础上。
我在TaskManagerInner中的TaskControlBlock里添加了syscall_times来统计该任务的各个系统调用次数的统计(在Trap_handler中增加贡献),并且在Inner中添加start_time来计算Task开启的时间长度,任务块实现函数中统计。
由于本次实验框架基于数组的实现方式,是建立在系统体量较小的基础上,所以能够理解。但是如果系统逐渐庞大,系统调用和任务数量的增加,会导致TaskManager内存部分乘法增长(因为是数组套数组)。
任务数量应该远小于系统调用的情况下使用HashMap来替代TaskControlBlock内部的统计数组会好一些。
ch4
本次实验重写了ch3中的sys_write和sys_task_info,因为在分页机制启用的基础上原有代码不再可用。
上面两个系统调用涉及到用户空间中的内存使用,所以我设计了一个modify_byte_buffer函数,用于将src(启用分页的内核空间地址)中的len长度的内容拷贝到ptr(启用分页的内核用户地址)相同长度的物理内存中去。
本次实验还实现了sys_mmap和sys_mummap的匿名映射的内存申请和解绑系统调用。
这两个函数都需要对所映射的地址范围进行检查,其中有一个关键点在于框架内所有的区间都使用左闭右开的形式。而且在使用虚拟地址来找到对应的物理地址时,框架(mm::page_table::find_pte)在第0和第1层遇到没有下一层映射的情况时返回None,但是到第2层时会直接返回,所以我们在返回值不是None的情况下也要判断是否Vaild。
上面这个 Vaild 的问题我真的是调了两个小时才发现的,真的需要知道每一块代码的运行方式和功能。
ch5
本次实验继承了ch4中的所有功能。
同时实现了spawn创建进程以及通过设置priority优先级和stride参数来对进程进行调度。
本次实验较为简单,使用 git cherry-pick 能简单的得到前面提交的代码,方便了功能的继承。
同时这次实验的调试也并不容易,其中在 syscall 统计其次数时,我像之前一样获取了TaskManager的所有权后增加,但是这样导致我在 waitpid 中的一个 assert 一直未能通过,后才发现改正。
总结
本次 rcore-os 训练营的第二阶段,让我巩固和学习掌握了很多操作系统的知识,并且亲身实践了功能,受益匪浅。
第二阶段将较难的一些概念和功能拆分,让我们不至于对一个东西很难上手,同时实验循序渐进,能够在原来写好东西的基础上增加对系统的理解修改代码,让我们的思维不断蜕变;而且增加功能的实验方式让我感觉像是在写自己的系统,就会更认真的写,学到更多东西,有强烈的正反馈。
同时第二阶段的实践也让我的 rust 语言熟练读更上一层楼。
如果还有时间我将继续学习 ch6 和 ch8 两个实验。