[OS]Three Easy Pieces Chapter 6
Mechanism: Limited Direct Execution
操作系统必须以高效的方式虚拟化 CPU,同时保留对系统的控制。为此,需要硬件和操作系统的支持。操作系统通常会明智地使用一些硬件支持,以便有效地完成工作。
1 Basic Technique: Limited Direct Execution
图中显示了直接执行的简要流程,这个流程存在两个问题:
- 操作系统如何保持对进程的控制,防止其做违法操作
- 操作系统如何切换进程,以在多个进程间共享CPU
2 Problem #1: Restricted Operations
为了限制进程的行为,提出内核态和用户态的概念。
用户进程一般运行在用户态,用户态中对硬件资源的访问是受限的,不能执行特权指令(访问IO等);而操作系统内核一般运行在内核态,在内核态中对硬件资源有完整的访问权限,可以执行特权指令,访问各种IO等。
有了这个概念,当一个用户进程希望访问一些硬件资源的时候,需要执行系统调用,告诉操作系统他要干啥,然后操作系统进行一些参数、权限检查等,确保用户进程有权利执行这个操作,并且这个操作不是一些恶意操作,然后替用户进程执行这个操作,再返回用户进程继续执行。从用户进程的视角来看,系统调用就像任何一个正常的函数调用一样。
为了执行系统调用,程序必须执行一个特殊的trap指令,该指令跳转到内核中并修改当前态为内核态,同时,该指令也会保存一些寄存器到内核栈(每个进程都有一个)中,以便能够顺利返回到用户进程。当操作系统完成系统调用后,会执行一个特殊的返回指令,该指令从内核栈中恢复寄存器的值,返回到用户进程继续执行,并修改当前态为用户态。
最后,一个trap指令如何知道跳转到哪里执行呢,如何区分不同的系统调用。我们不能允许用户进程直接指定执行指令的位置,因此,操作系统通过一个trap table来实现。trap table实际上就是一个表格,将不同的系统调用映射到对应的处理例程的地址。执行trap指令的时候,由用户负责提供一个系统调用号,然后操作系统根据这个系统调用号跳转到对应的地方执行。trap table是在操作系统boot的时候设定的(通过某种特权指令告诉硬件trap table的地址,硬件记住这个地址,之后直接到这里查找)。
3 Problem #2: Switching Between Processes
操作系统如何获取控制权
进程切换的第一个问题是,当进程上CPU执行之后,操作系统理论上就不能执行任何操作了(没有CPU资源),那么操作系统如何切换进程?因此,我们需要提供一种机制让操作系统能够重新获取控制权。
合作方法:等待进程执行系统调用
在早期的OS中,内核相信进程会时不时的让出CPU的控制权,即使进程不让出控制权,其也会时不时的执行系统调用,或者是触发异常等,操作系统在此时获取控制权。然而,当进程陷入死循环中,操作系统就无法获取控制权了。
非合作方法:操作系统接管
通过借助硬件的帮助(时钟中断),操作系统可以获取控制权。具体的,在boot的时候,操作系统告诉硬件,当发生时钟中断的时候,执行什么代码,然后启动时钟。这样,当时钟中断发生的时候,当前进程就会停止执行,然后跳转到时钟中断处理程序中执行,这时,操作系统就获取了控制权,可以做任何事情。
需要注意的是,对中断处理和系统调用很类似,硬件都要负责保存寄存器的值,切换态等,以便之后能够顺利继续执行。
4 Saving and Restoring Context
上下文切换要做的事情其实很简单,保存当前进程的寄存器的值到PCB中,然后从要切换的进程的PCB中恢复这些值到寄存器中。具体的,当时钟中断发生的时候,硬件会负责将一些寄存器保存到当前进程A的内核栈中,然后进入时钟中断处理程序执行,并切换到内核态,内核决定要进行调度,切换另一个进程B执行,此时进行上下文切换,将当前寄存器的值保存到当前进程A的PCB中,然后从进程B的PCB中恢复这些寄存器的值,然后切换到进程B的内核栈,此时执行返回指令,硬件从内核栈中恢复寄存器的值,跳转到进程B被中断的地方继续执行。可能还会涉及额外的页表的切换。