0%

2022开源操作系统夏令营第二阶段-模块化rcore-鹿敏宽

repo

我第二阶段选择的主题是模块化rcore,刚开始想的比较美好,这个模块化rcore项目和第一阶段都属同一个项目,做起来难度应该不大;并且模块化正是程序员所追求的一种境界。但是一着手实现就有很多问题了。第一个问题是怎么实现模块化,有没有一种切实可行的一种方法?此外,虽然经过了操作系统夏令营的洗礼,但是我依然缺少对操作系统底层相关的技术的理解。比如应用程序如何加载,这过程中使用到了什么命令等等细节的问题。

无奈何只能从头开始看rcore-tutorial的文档了。因此我第二阶段做的工作并不是模块化rcore,而是按照rcore-tutorial文档复现出一个操作系统。

关键知识点

下面介绍复现过程中印象很深的一些知识点。

应用程序的加载

  • 应用程序需要内核系统调用的支持,user/src/syscall.rs传递系统调用的参数到相应的寄存器,而后进入内核的syscall处理,内核的syscall处理函数从寄存器中取出参数,进行相应的处理。
  • 应用程序第二,三章的时候需要手动去除header信息,使用的指令是rust-objcopy;第四章的时候,由于实现了地址空间的抽象,可以利用elf文件解析器解析出入口地址,因此不需要裁剪应用程序的二进制文件。
  • 应用程序要经过编译成可执行文件;生成链接脚本将应用程序的可执行文件链接到内核中;将应用程序可执行文件加载到对应的物理地址三个步骤才可以正确执行。
  • 应用程序的加载,第二,三章都是需要手动实现一个load函数,将程序copy到对应的地址。而第四章程序的加载是在TaskManager的初始化中隐式完成的。TaskManager中需要初始化TCB数组,TCB有一个属性是memoryset,而memoryset就是从elf文件解析得到的。

运行第一个程序

  • 这个问题涉及到如何从S态转变到U态。第二章的实现是直接利用restore函数,在内核栈中压入一个trap context,将内核栈指针传入,即可实现从S态转变为U态。
  • 第三章利用switch函数进行了实现。构造一个空的task context,与要执行的task context交换,task context的ra为restore函数,sp就是内核栈指针。因此本质上还是调用restore函数。
  • 第四章和第三章基本一致。但由于内核地址空间和用户地址空间的隔离,在执行restore函数的时候还需要多传入一个用户地址空间的token。

Trap处理与任务切换

  • Trap处理是从U态切换到S态,又从S态切换到U态。而switch仅仅是内核态中两个任务上下文的互换,任务上下文中比较关键的两个属性,ra记录执行完switch函数之后下一步执行的地址;sp记录了内核栈指针。

跳板页

  • 跳板页之所以叫跳板页,是因为这一个虚拟页中放了涉及到地址空间切换的alltraps和restore两个函数。
  • 在每一个地址空间中,无论是内核地址空间还是应用程序的地址空间,都存在这样的一条虚拟页和物理帧的对应关系。TRAMPOLINE---strampoline,其中TRAMPOLINE是虚拟页最开始的地址,在config中配置;strampoline是链接脚本指定的跳板页开始的物理地址。
  • 这么独立配置之后,调用alltraps和restore两个函数十分方便,alltraps函数的虚拟地址就是TRAMPOLINErestore函数的虚拟地址就是TRAMPOLINE+ __restore as usize - __alltraps as usize

总体感想

参加了这个操作系统训练营,过的十分充实,更加深刻的理解了操作系统。之前只是从书本上得到一个很模糊的印象,对于细节方面的东西完全不懂。参加了训练营之后,更加深刻的理解了操作系统。第一阶段,我理解了系统调用是操作系统的核心。第二阶段从头开始,重新理解了rcore。第一章在一个裸机操作系统实现一个prin语句;第二章实现内核态与用户态的隔离,进而实现了一个批处理操作系统;第三章实现了分时多任务,此时有了任务切换;第四章加入了地址空间的抽象,使得我们不用手动指定每个应用程序的基地址。

体会与建议

第一阶段的任务十分明确,完善一个个系统调用,直到这一章所有的测例通过了,就可以进入下一章的学习了。因此第一阶段过的十分紧凑。完成了一个章节,然后着手解决下一个章节。

但到了第二阶段,一个最明显的感觉是无所适从,不知道该干什么。因此我想提出一些建议,这些建议是依据我的第二阶段经历来的。

  • 这次的第二阶段刚开始进行了一周的zcore报告,这些报告对于我的选题没有什么借鉴,因此这一周的时间相当于是浪费了。直到陈瑜老师的选题分配会议,我才真正开始了第二阶段的工作。因此我的想法是先进行选题的分组,而后根据各组的题目安排相应的讲座。
  • 我第一阶段重点关注系统调用的实现,结果第二阶段要实现一个模块化的rcore。这两个阶段差别极大,第一阶段助教们已经为我们设置了十分舒适的环境,只需要关注系统调用的实现即可。而第二阶段要求我们实现一个操作系统,这对我难度非常大,所以最后只能重头开始学rcore-tutorial了。因此我的想法是尽量让两个阶段衔接起来,第一阶段是手动实现一个操作系统,那么第二阶段就是模块化操作系统。