用Rust改写riscv-pk总结
闲话
最近闲来无事, 便想总结一下暑假进行的用Rust改写riscv-pk这个练手项目, 主要是为了熟悉一下rCore以及Rust, 也学会了用objdump来反汇编一个二进制文件进行debug, 目前看来除了rCore的文件系统以及一些驱动基本都熟悉了一遍, 因为riscv-pk的文件系统是直接交由宿主机完成, 它只是一个代理作用, 熟悉rCore的同时也了解了riscv-pk的pk部分, 与现在在看的x86_64的内存空间分布感觉差不多.
总的来讲改写起来还是蛮有趣的, 主要有成就感的点有几个, 一个是当os输出hello world的时候(蛮简单的), 以及虚拟内存成功跑起来, 还有一个就是跑user-mode的elf文件, 并且syscall陷入trap, 最后一个点成就感比较明显. 但这一次改写只是搭建了一个框架, 实现了user-mode程序的hello world, 没有实现其他的syscall, 这一部分还是需要未来慢慢熟悉, 慢慢实现.
最后补一句: rCore无论是教程还是代码都蛮不错, 建议去看看, 附:
阶段
这一次总结不说明代码的内部细节, 只是想总结一下改写过程遇到的事情, 由于改写已经经过了一个月了, 所以有一些可能记得不是很清楚, 见谅.
起步阶段
起步阶段大致就是需要看懂riscv-pk他是如何启动的, 毕竟proxy-kernel的环境和真正的操作系统还是有点区别, 他把bootloader和操作系统相当于嵌在一起了, 这一部分没啥好说的, 由于proxy-kernel他的系统调用都跑到宿主机上了, 所以实现起来比较简单, hello world大概一周还是两周就跑起来了.
中间阶段
这一阶段比较难… 由于对rCore的多任务以及虚拟内存还是不太熟悉, 所以需要同时看两边代码, 一边看一边学习, 在这期间还遇到了一个无语的问题, 就是proxy kernel他要将PTE中的Access bit置为1才能访问, 不然他就不知道这个虚拟地址..这个问题卡了我一周, 尝试了各种方式, 包括把proxy kernel的映射方式改到rCore中, 把rCore改写成支持大页模式, 改static变量的内存地址, 最后把proxy kernel简历页表的那些bit弄过来才发现要Access bit, 他对RWX权限定义的bit和正常的bit还不一样..
虚拟内存结束了就是多任务以及任务的地址空间布局了, 这一部分还好, proxy kernel并不支持多任务系统, 他的页表也是用户和内核共用的, 只不过内核映射到了高位地址, 用户使用低位地址, 这一部分我就直接用了rCore的映射方式, 第一点是改写static变量的地址在Rust中貌似比较烦..proxy kernel他用c语言直接设置offset地址就好了, rCore一对一映射不用改地址比较舒服. 第二点是rCore现成的就摆在那了(懒得改了).
结束阶段
最后一步就是trap以及文件系统了, 这一部分最简单了, 对于trap, 在解决了前面的问题后, 只需要看懂proxy kernel以及rCore他们的trap汇编和其他代码就好了, 当然最后采用的是rCore的方式, 毕竟地址空间布局用的人家的, 合情合理(hh). 文件系统把proxy kernel那一套移植一下就完成了, 毕竟是直接给宿主机发系统调用, 不用写太多.
最后整合在一起, 用户态二进制文件我直接用的rCore中的user编译出来的hello world程序了, 毕竟他用的系统调用较少, 我直接编译一个c文件发现他用了贼多系统调用..还是rCore的那个简单, 一个write, 一个exit解决了.
总结
这一篇比较短, 没有太多代码细节, 毕竟是练手项目, 没啥好说的, 最后写完的感觉就是rCore以及pk的缝合体hh, 不过缝合的过程中对他们的具体实现也理解的蛮多, 收获应该有以下几点吧:
- 对rCore的代码理解的更深了, 具体为虚拟内存, trap, 多任务, 地址空间分布.
- 对于Rust的引用那些的使用的更熟了一点
- 会通过看反汇编文件, 一步步跑汇编指令来debug了, 虽然riscv-pk还不是用gdb debug的, 但一些功能是gdb的.
- pk的地址空间分布与最近在看的x86_64地址空间分布类似, 当初还一头雾水, 不知道为啥要这样搞, x86_64之后才了解到大家貌似都是这么搞得hh.
改写后的代码还没整理, 包括去除一些不必要的文件等事情还没做, 只是把Rust编译的warning给弄掉了, 因此就没弄成公开状态.