Stanford CS140e 学习笔记 (4):用户态程序的运行

Assignment 3 的主要目标,是使自己的操作系统能够运行用户态程序。这个 Assignment 中,需要实现特权级别切换、上下文切换、调度器、系统调用处理、虚拟内存等代码。并将之前实现的 shell 移动至用户态,做为一个进程来运行。

启动第一个进程

文章目录:

ARM 架构基础知识学习

Assignment 3 所实现的不少功能,都需要操作系统软件和 CPU 的配合。所以,在正式实验之前,需要了解 ARM 架构的基础知识。主要参考如下文档:

为了实现用户态和内核态之间的切换,首先需要关注异常和特权级别。原网页已经有较为详细的介绍。同时我又找了这样几篇文章用于加深理解。

同时也进行了指令集、寻址方式的简单学习。并阅读了 init.S 初始化程序。

异常与中断处理

切换到 EL1

AArch64 CPU 启动时,EL 级别位于 EL2. 正常情况下,OS 内核工作于 EL1,用户态程序工作于 EL0。所以需要在内核初始化时,将 EL 级别由 EL2 切换到 EL1.

异常向量

为了使内核能够处理终端和异常,需要设置异常向量。ARM 的向量表中有 16 个异常向量,每条向量可存放最多 16 条指令。为了更方便地处理异常,每条异常向量,都将调用 handle_exception 函数,并设置不同的参数,最终由 handle_exception 函数统一处理。

通过汇编代码调用 handle_exception 时,需要考虑传入参数,获取返回值。对于 AArch64,前 8 个参数依次传入到 r0..r7,函数调用完毕后,前 8 个返回值也从 r0..r7 中获取。另外,在调用函数前后,还需要保存和恢复各个寄存器中的值,这些寄存器分为 caller-savedcallee-saved,对于前者,如果 caller 需要在函数执行调用后继续使用寄存器中的内容,则需要主动将寄存器中的值保存在栈上,否则不需要保存;对于后者,由 callee 保证寄存器的值在函数调用后不发生变化。

在异常处理中,实现了一个 debug shell,方便后续进行调试。

上下文切换

进入异常后,寄存器的状态可能会被异常处理程序改变,导致从异常返回后,程序无法继续执行。所以进入异常、以及从异常返回时,需要分别保存、恢复各个寄存器的状态。这一过程称为「上下文切换」。

第一个进程

对于内核,需要为每个进程维护如下信息:

  • 可执行代码
  • 虚拟地址空间
  • 调度器状态(进程是否需要被得到调度)
  • 运行状态(寄存器等信息,方便上下文切换后进行恢复)

所以在代码中,通过定义一个名为 Process 的结构体,保存进程运行所需的信息。

然后将之前实现的 shell,修改为一个用户态 (EL0) 进程。由于未实现虚拟内存,这个进程除了运行在 EL0 之外,更像是一个内核线程。对于虚拟内存的部分,留在后面的课程中实现。

调度器

定时器中断

在 AArch64 上,中断其实和异常基本类似,知识中断往往由外部事件产生。我们需要做的,是修改之前完成的定时器驱动代码,设置 BCM2837 上的定时器,同时实现中断控制器驱动,使定时器能够正常产生中断。

定时器驱动代码的修改,和之前玩单片机时使用的方式类似。通过设置一个时间比较寄存器,当定时器中的时间与该寄存器的时间相等,则产生一个中断。通过这种方式,周期性地产生中断,做为内核的时钟使用。

中断控制器也需要经过设置,才能将定时器产生的中断送至 CPU。

round-robin 抢占式调度器

之前在单片机上实现过一个简单的非抢占式的调度器,这门课程中,需要实现另外一个。

调度器通过前面实现的定时器中断,来确定接下来要运行哪个进程。用于调度的算法有很多种,本课程中,主要实现简单的 round-robin 调度算法,为每个进程分配相同的时间片。

在这个操作系统中,调度器为进程有三种状态:Ready, Running, Waiting. 所有进程放在一个队列中,当前进程的时间片用尽,则将进程放入队列末尾,并取出一个新的进程。如果新的进程状态为 Ready, 则继续执行,如果为 Waiting,则直接放入队列末尾,并再取一个新的进程执行。

系统调用

接下来要实现第一个系统调用 sleep,告诉调度器制定时间内不对本进程进行调度。同时通过在 shell 中实现 sleep 命令,验证该系统调用是否能正常工作。

系统调用是一种特殊的异常,是用户态进程请求内核服务的一种方式。在 AArch64 中,通过 svc 指令来执行系统调用。

类似函数调用,在系统调用中,也需要传入参数,获取返回值。本课程中实现的系统调用中,将寄存器 x0..x6 用做传入参数与返回值,将 x7 用做错误码。

更多

课程的剩余内容,CS140e 的网站上已经几个月没有更新了。这门课程的学习暂时告一段落,等课程更新后再继续。

扩展阅读

“Stanford CS140e 学习笔记 (4):用户态程序的运行”的一个回复

发表评论

电子邮件地址不会被公开。 必填项已用*标注