处理器运行模式

1.1.1 结尾提到一条贯穿全课的规律:操作系统的每一项管理能力,背后都有一个硬件机制在支撑。 这一节讲的就是最根本的那一个。

问题很具体:操作系统凭什么能阻止一个用户程序去关中断、去改页表、去直接读磁盘?如果靠软件逐条检查,那检查代码本身也在 CPU 上跑,用户程序同样可以绕过。 唯一可行的办法是把这件事交给硬件。

机制

两种运行模式

CPU 划分出两种运行状态:

用户态(目态)——权限低,只能执行非特权指令,不能直接访问关键硬件和内核数据。应用程序运行在这个状态。

内核态(核心态、管态)——权限高,可以执行全部指令,能管理硬件和系统资源。操作系统内核运行在这个状态。

当前处于哪种状态,由程序状态字寄存器(PSW)中的一个二进制位标志。 CPU 在执行每一条指令时都会检查这一位——这就是”硬件支撑”的确切位置。

特权指令与非特权指令

特权指令是只允许在内核态执行的指令,典型的有:关中断、置时钟、清内存、修改存储器管理寄存器、送程序状态字到 PSW、I/O 指令。

它们的共同点是:一旦被用户程序执行,就能破坏整个系统。 关了中断,时钟中断进不来,调度就永远轮不到别人,这个程序可以独占 CPU 到关机;改了存储器管理寄存器,就能访问任意进程的内存。

非特权指令是普通的算术运算、访存等指令,两种状态下都能执行。

疑问点:特权指令错由谁检查,开销是否很大

之前说的”特权指令错”可能是运行了内核态的指令,那是谁在检查?是操作系统吗? 那会是一笔很大的开销吗?

特权指令错是怎样被发现的

这一点最容易被误解,也是理解本节的关键。

操作系统并没有逐条扫描用户程序去找特权指令——那既做不到(程序可以在运行时动态生成指令),也太慢。

实际发生的是:CPU 执行到一条特权指令时,硬件检查 PSW 中的模式位,发现当前是用户态,于是拒绝执行并触发一个异常(“特权指令错”),控制权随即转入内核。

换句话说,检查是”执行时由硬件做的”,不是”事先由软件做的”。 操作系统所做的,只是在系统启动时把规则配置好(配置中断向量表、页表权限等),之后就交给硬件自动执行。

因此这项检查几乎没有额外开销。 它不是一段需要执行的代码,而是与指令译码同时进行的一次硬件比较——CPU 本来就要译码判断这是什么指令,顺便看一眼模式位即可。“开销大”的担心,来自把它想象成软件检查;一旦认清是硬件做的,这个担心就消失了。

顺带可以回答一个常见的实践疑问:在早期的微机接口实验中能直接使用关中断指令,并不是因为那段程序”运行在内核态”,而是因为那种环境根本没有操作系统在管理特权级——实模式下 CPU 不作特权检查,所有指令都能执行。特权级机制要起作用,前提是有人把规则配置好并让 CPU 运行在保护模式下。

疑问点:受控入口如何被"标记"

CPU 检测某处是受控入口——它怎么检测,怎么”标记”受控入口,是操作系统启动时挂载上去的吗?

用户态如何进入内核态:三种受控入口

用户程序不能随便跳到内核的任意位置——否则它只要跳到某个跳过权限检查的地方,保护就形同虚设。

能进入内核的入口必须是操作系统预先配置给 CPU 的受控入口,共三种触发方式:

入口触发原因例子
系统调用用户程序主动请求操作系统服务read()、write()、fork()
中断外部事件打断 CPU时钟中断、I/O 完成中断
异常当前指令执行出现问题缺页、除零、非法指令、特权指令错

这些入口的地址由操作系统在启动时写入硬件的中断向量表(如 x86 的中断描述符表 IDT),之后 CPU 只承认这张表里的入口。用户程序无法伪造”我直接跳进内核某个函数”这种事——它连跳过去的地址都没有合法途径写进去。

三者的最短判据:系统调用是主动请求,中断来自外部,异常来自当前指令。

内核态如何返回用户态

回到用户态靠的是一条特权指令——通常是”中断返回”类指令,它在恢复现场的同时把 PSW 中的模式位改回用户态。

注意方向的不对称性:进入内核态是”被动”的(要么被中断/异常打断,要么执行陷入指令),返回用户态是”主动”的(内核执行一条特权指令主动交还控制权)。这个不对称正是保护得以成立的原因——如果用户程序能主动切到内核态,一切保护都没有意义。

操作系统内核包含什么

内核是操作系统中最基本、最核心的部分,运行在内核态,包含四部分:

① 时钟管理——提供时间标准,时钟中断是进程切换的基础(时间片用完靠它来触发)。

② 中断机制——负责响应和处理各类中断,是本节所有受控入口的实现基础。

③ 原语——处于操作系统最底层、最接近硬件的部分。它的特点是:运行具有原子性(操作只能一气呵成,不可中断)、运行时间较短、调用频繁。典型的有设备驱动、CPU 切换等。

④ 系统控制的数据结构及处理——进程管理、存储器管理、设备管理所用的各种数据结构(如 PCB、页表、设备控制表)及对它们的操作。

边界

疑问点:用户态与内核态是否只是一个标志字段

用户态和内核态指的只是一个标志(字段)吗?谁在管理它?有硬件参与吗?

用户态与内核态不是操作系统维护的一个变量

这是最容易犯的理解错误。

如果模式位只是操作系统在内存里维护的一个布尔变量,那么用户程序只要把它改成”内核态”就能提权——保护立刻崩塌。

实际上模式位在 PSW 寄存器里,而”修改 PSW”本身就是一条特权指令。 于是形成一个闭环:想改模式位,先得处于内核态;想处于内核态,只能通过受控入口进去。 用户程序从任何一个方向都进不来。

理解这个闭环,就理解了操作系统保护机制的全部原理。

模式切换不等于进程切换

这一条与 2.2.4 的结论一致,此处从运行模式的角度再说一遍:

模式切换只说明 CPU 从用户态进入了内核态(或反之),进程可能一点没变。

场景是否进入内核态是否一定切换进程
系统调用是不一定
中断是不一定
异常是不一定
时间片用完是通常会
普通函数调用否否

一句话:所有进程切换都要经过内核态,但进入内核态不一定切换进程。

一个进程调用 getpid(),进内核、取个数、回用户态,全程都是它自己在跑——发生了两次模式切换,零次进程切换。

调度发生在返回用户态之前

这是一个容易记反的时序细节。

内核在准备返回用户态之前,会检查是否需要重新调度。 若当前进程仍可运行且无需让出 CPU,就返回同一个进程;若时间片已用完、或有更合适的进程就绪,内核会先完成进程切换,再返回(另一个进程的)用户态。

准确说法是”返回用户态前检查调度”,而不是”返回用户态后开始调度”——后者在逻辑上不可能,因为一旦回到用户态,控制权已经不在内核手里了。

调度发生在内核态,常见时机是:中断处理结束时、系统调用返回用户态前、进程阻塞或被唤醒后。

特权指令与”只能在用户态执行的指令”

绝大多数指令要么是特权指令(只能内核态),要么两种模式都能执行。

但有一条例外:陷入指令(访管指令)是唯一一个只能在用户态执行、而不可在内核态执行的指令。

理由很直白:陷入指令的作用是”从用户态进入内核态”。已经在内核态了还执行它,语义上没有意义。 这一条是选择题的常见落点。

对照速查

用户态(目态)内核态(核心态、管态)
权限低高
能执行仅非特权指令全部指令
谁在跑应用程序操作系统内核
标志位置PSW 中的一位同左
特权指令举例为什么必须特权
关中断关了就能独占 CPU 到关机
置时钟篡改时间基准
修改存储器管理寄存器能访问任意进程的内存
送程序状态字到 PSW能直接改模式位(保护闭环的关键)
I/O 指令能绕过一切设备保护
三种受控入口触发者判据
系统调用用户程序主动主动请求
中断外部设备来自外部
异常当前指令来自当前指令
内核的四部分说明
时钟管理提供时间标准,是进程切换的基础
中断机制所有受控入口的实现基础
原语最底层、原子性、时间短、调用频繁
系统控制的数据结构及处理PCB、页表、设备控制表等

考点

  • 模式位在 PSW 中,由硬件在执行每条指令时检查——不是软件事先扫描
  • 保护闭环:改模式位需内核态,进内核态只能走受控入口
  • 三种受控入口:系统调用(主动)、中断(外部)、异常(当前指令)
  • 入口地址由操作系统启动时配置进中断向量表,用户程序无法伪造
  • 所有进程切换都要经过内核态,但进入内核态不一定切换进程
  • 调度在返回用户态之前进行,不是之后
  • 原语的四个特点:最底层、原子性、时间短、调用频繁
  • 陷入指令是唯一只能在用户态执行的指令

链接