Appearance
CPU运行模式(内核态与用户态)
2026 大纲 一(三)1 CPU 运行模式,补充说明点名两个术语:内核模式、用户模式。
OS 凭什么管得住那些不听话的程序
上一节说操作系统要站在硬件和程序之间替所有程序做主。可 OS 自己也不过是一段代码, 和用户程序一样由同一个 CPU 执行——凭什么用户程序就得听它的?
如果答案是"因为 OS 写得早、跑得早",那它一点用也没有:一个用户程序只要执行一条 "关中断",OS 就再也拿不回 CPU;执行一条 I/O 指令,就能绕过 OS 直接读别人的磁盘数据。 软件层面的约定挡不住这些,因为执行指令的是硬件,硬件不认识谁是 OS。
所以答案只能在硬件里:CPU 自己带一个模式位,处在某种模式下时,有一批指令 它压根就不执行。OS 运行在那个能执行全部指令的模式里,用户程序运行在另一个模式里。 这一个比特,就是操作系统全部权威的物理来源。
这一节要把三件事说清:这批"只有 OS 能用"的指令是按什么标准圈出来的、 用户程序硬要执行会发生什么、以及两种模式之间怎么来回切。 最后一件事尤其要留意,因为它是不对称的——而那处不对称就是隔离能成立的全部技术含量。
一、两种运行模式
模式由 PSW(程序状态字)里的处理器状态位标识。CPU 每执行一条指令前都会拿这一位 和指令的权限要求对照。
| 模式 | 别名 | 模式位 | 可执行的指令 |
|---|---|---|---|
| 内核态(内核模式) | 核心态、管态、特权态 | 0 | 所有指令(含特权指令) |
| 用户态(用户模式) | 目态 | 1(或 3) | 只有非特权指令 |
这张表最容易被答反的是右下角那一格。内核态能执行的是"全部指令",不是"只有特权指令"—— 内核里绝大多数代码也是普通的加减跳转。"某某态只能执行某类指令"这种句式, 只有"用户态只能执行非特权指令"这一句是对的。
硬件其实提供 0~3 共 4 个特权级,但通用操作系统只用了 0 级与 3 级, 中间两级在实践中被跳过了——这也是大纲只点名内核模式与用户模式的现实依据。
相应地,系统中运行的程序分为系统程序与应用程序:两者是控制与被控制的关系, 前者有权管理与分配资源,后者只能申请与使用系统资源。
二、特权指令是按什么标准圈出来的
判据只有一条:这条指令是否可能影响其他进程或整个系统。 凡是能让"检查机制本身失效"的操作,一律划入特权。
按这条判据往下推,特权指令集中在三处——改硬件状态、改保护规则、改控制流权限:
| 指令 / 操作 | 特权指令 | 依据 |
|---|---|---|
启动 I/O(in / out / DMA 启动) | 是 | 直接操作硬件,可读写他人数据 |
| 修改 PSW(程序状态字) | 是 | 会改变 CPU 模式位——这条是隔离的命门 |
| 关中断 / 开中断(修改 IF) | 是 | 影响响应中断的能力,关中断即可独占 CPU |
| 设置 / 修改页表基址寄存器(PTBR) | 是 | 改地址翻译规则,等于换一套内存视图 |
| 修改重定位 / 界地址寄存器 | 是 | 改内存保护边界 |
| 装入定时器 | 是 | 影响时钟中断频率,可让 OS 再也夺不回 CPU |
停机指令 hlt | 是 | 一条指令停掉整机 |
中断返回指令(iret) | 是 | 从内核态降到用户态,会写模式位 |
系统调用指令(int 0x80 / syscall,即陷入指令 / 访管指令) | 不是(用户态可执行) | 但执行后立刻由硬件带入内核态 |
| 算术 / 逻辑运算、压栈 | 不是 | 不影响其他进程 |
| 访存指令 / 跳转指令 | 不是 | 越界由 MMU 硬件当场检测 |
设置断点(如 int 3) | 不是 | 调试器在用户态插进去就行 |
表里有两行是反直觉的,值得单独讲。
陷入指令不是特权指令。 它必须能在用户态执行,否则用户程序永远发不出请求, 系统调用这条路就断了。它的安全性不靠"禁止执行",而靠"执行后落到哪里"—— 执行它会立刻由硬件把模式位置 0,而进入内核后从哪一段代码开始跑, 是由内核的系统调用表决定的,用户改不了。它给了你进门的权利,但门后走哪条路不归你定。
iret 反过来必须是特权指令。 它要把模式位从 0 写回 1。如果用户态能执行它, 用户程序就可以自己构造一个"模式位=0"的 PSW 然后加载它,隔离当场失效。
三、隔离的闭环:用户态执行特权指令会怎样
"特权指令只能在内核态执行"这句话本身不构成保护——它只是一条规定。 真正让隔离成立的,是"违规时会发生什么"。
图里三步各自都不能少。指令根本没被执行——不是"先执行再检查", 不存在"已经把 I/O 端口写坏了才报错"这种事,检查发生在译码阶段。 产生的是异常(内中断)而不是外中断——它由当前这条指令自身引发,与外部设备无关。 异常处理程序运行在内核态——违规者自己没有任何处置权。教材给出的处理原则是: 非法指令、用户态使用特权指令、地址越界、非法存取等指令异常一律终止进程。
所以"用户态不能执行特权指令"这句话只说了一半,完整的说法是 "指令不被执行 + 产生非法指令异常 + 进程被终止",保护是靠最后这一步合上闭环的。
四、判断一个「程序」在哪态运行
上面三节问的都是"指令",真题还会换个问法:这个程序运行在哪一态。 判据要换一条:看它需要访问什么资源。只用得着用户态可访问的资源,就在用户态; 要读写内核数据结构或执行特权指令,才在内核态。
按这条判据过一遍常见的几个:
- 缺页处理程序要查页表、改 PCB、发起磁盘 I/O ——内核态。
- 进程调度程序要读写 PCB 和就绪队列 ——内核态。
- 时钟中断处理程序要改内核时钟变量和 PCB 的时间字段 ——内核态。
- 命令解释程序(shell)——用户态。
最后这个最容易判错,因为开机就有它,看起来像 OS 的一部分。但 bash、zsh、cmd 都只是普通的用户进程,和 vim、git 没有区别,只是被设置成开机自动启动而已。 它的工作流程是「读输入 → 解析命令 → fork() → exec() → wait()」, 每一步都是用户态代码。中间那几个是系统调用,shell 通过它们陷入内核, 但发起调用的代码在用户态,被调用的服务才在内核态。 "它调用了系统调用"不等于"它运行在内核态",否则所有程序都在内核态了。
五、特权指令 vs 敏感指令
这一组概念是虚拟机那一篇的地基,分界在于看的是哪件事:
| 概念 | 定义 | 判据 |
|---|---|---|
| 特权指令 | 只能在内核态执行,用户态执行会触发异常 | 执行时会不会因权限不足而陷入 |
| 敏感指令 | 会读或改机器的关键状态(模式位、中断开关、页表基址、机器配置),或其行为随当前模式不同而不同 | 它碰不碰系统全局状态 |
特权一定敏感,敏感不一定特权。 麻烦出在"敏感但不特权"这一类: 它读或改了关键状态,但在用户态执行时并不报错,而是悄悄返回一个当前模式下的结果, 或者干脆什么也不做。
举个例子:某条读取中断开关状态的指令,在用户态执行既不陷入也不报错,只返回一个无意义的值。 对普通应用无所谓,但对一个被降到用户态运行的 Guest OS 就是灾难——它会据此做出错误判断, 而 VMM 根本收不到任何通知(没有陷入就没有通知)。所以当且仅当所有敏感指令都是特权指令时, "陷入-模拟"这套虚拟化方案才自动成立。
六、两个方向的态切换:一边是硬件,一边是软件
进内核只有一条路——中断。它有三类:
| 触发方式 | 说明 | 举例 |
|---|---|---|
| 外中断(异步中断事件) | 来自 CPU 外部,与当前指令无关 | 时钟中断、I/O 完成中断 |
| 内中断(同步异常事件) | 指令执行过程中出现问题 | 缺页异常、除零异常、用户态执行特权指令 |
| 自愿性中断(主动陷入) | 用户程序主动请求 OS 服务 | 系统调用(执行陷入指令 / 访管指令) |
这两个方向是不对称的,而这处不对称就是隔离的全部技术含量。
上行(用户态 → 内核态)由硬件完成:中断、异常、陷入指令都会让硬件自动置模式位并交换 PSW, 整个过程没有任何一条指令是用户程序写的,因而用户伪造不出来。
下行(内核态 → 用户态)由软件完成:OS 主动执行 iret。
为什么不能让程序自己改模式位?把链条写全就明白了:模式位在 PSW 里 ⇒ 改 PSW 是特权指令 ⇒ 用户态执行它会触发非法指令异常并被终止 ⇒ "自行升权"这条路在硬件层面就是死的。 用户能做的只有"请求"。
还有一处要分清:态切换不等于进程切换。系统调用返回后通常仍回到同一个进程, 只是模式位变了两次。反过来则成立——进程切换必然发生在内核态,因为它要读写 PCB。
七、内核的组成:为什么偏偏是这几样
内核成员是被一条判据筛出来的:这件事在用户态做得成吗。做不成的才进内核。
| 层次 | 组件 | 为什么它必须在内核态 |
|---|---|---|
| 与硬件紧密相关 | 时钟管理 | 要装入定时器、响应时钟中断,都是特权操作;且时钟中断是抢占式调度的物理基础,若能被用户态关掉,OS 就再也夺不回 CPU |
| 中断处理 | 中断向量表、断点与现场保存都在内核空间,用户态连读都读不到;且中断到来时硬件已把模式位置 0 | |
| 原语(原子操作) | 原语要求执行期间不可被打断,实现手段是关中断,而开关中断是特权指令 | |
| 内核功能 | 进程管理 | 要读写 PCB、修改就绪队列,都是内核数据结构 |
| 存储器管理 | 要改页表基址寄存器、界地址寄存器,都是特权指令 | |
| 设备管理 | 要执行 I/O 指令、操作设备寄存器,都是特权指令 |
硬件那 4 个特权级各自是干什么的,以及原语的原子性为什么只能靠关中断(想按教材原文口径答"处理器状态有几种",或想把"原语必须在内核态"这条推导链走通时展开)
先说 4 个特权级。 大多数计算机系统的处理器状态有 4 种,支持 0~3 级共 4 个特权级别:
| 级别 | 名目 | 权限 |
|---|---|---|
| 0 级 | 处理 I/O 与中断 | 权限最高,即内核态 |
| 1 级 | 系统调用级 | |
| 2 级 | 共享库级 | |
| 3 级 | 应用程序级 | 权限最低,即用户态 |
但几乎所有通用操作系统实现都只使用了 0 级与 3 级,即简单区分内核态与用户态, 中间两级在实践中被跳过了。
再说原语。
原语(primitive)是由若干条指令组成的、完成某个特定功能的一段程序, 其执行必须一气呵成——要么全做完,要么一条都不做。
为什么必须这样?以"把一个进程从阻塞队列摘下、挂到就绪队列"为例:这个动作要改好几个指针, 做到一半被打断,队列就处于自相矛盾的中间状态;此时若切换到另一个进程也去动这个队列, 数据结构就彻底坏了。
实现手段最直接的一种就是关中断:
关中断期间 CPU 不响应任何可屏蔽中断,没有中断就不会发生进程切换, 这段代码自然不可能被打断。而开关中断是特权指令——用户态程序连"关中断"这个动作都做不出来, 也就无法保证任何原子性。
推导链完整写出来是:原语要求执行期间不被打断 ⇒ 打断只可能来自中断(及由中断引发的进程切换) ⇒ 屏蔽办法是关中断 ⇒ 关中断是特权指令 ⇒ 用户态做不到 ⇒ 原语只能在内核态。
这也解释了为什么原语必须短:关中断期间时钟中断也被挡在门外, 原语越长,整个系统对外部事件的响应就越迟钝。
考点速记
- 模式由 PSW 中的处理器状态位标识。特权指令的判据只有一条——是否可能影响其他进程或整个系统——因而集中在改硬件状态、改保护规则、改控制流权限三处。
- 陷入指令不是特权指令(否则用户发不出请求),
iret是(否则用户能自行升权)。 - 隔离的闭环靠"违规会怎样"合上:指令不被执行 → 硬件产生非法指令异常 → 陷入内核 → OS 终止该进程。只说"不能执行"是半句话。
- 问指令看权限,问程序看它要访问什么资源。shell 是用户程序——调用系统调用不等于运行在内核态。
- 两个方向不对称:上行由硬件完成(用户伪造不出),下行由软件完成(且
iret是特权指令)。进内核只有中断一条路,含外中断、内中断、自愿性中断三类。 - 特权一定敏感,敏感不一定特权;虚拟化的"陷入-模拟"方案要求两者重合。
这一节在真题里被考过的形式:
考法高度集中,只有两种问法,而且四道题里三道都在同一个模子里。
- 给四条指令,问哪条不能在用户态执行 / 只能在内核态执行(2014-25、2021-23)。这是最标准的问法,直接套"会不会影响其他进程或整机"。2014-25 答关中断:用户态若能关中断,恶意程序关掉再死循环,时钟中断进不来、调度器叫不醒它,整机就被锁死。2021-23 答 I/O 指令:放给用户态,任何程序都能直接操作磁盘网卡,设备保护全废。⚠️ 这两道题的干扰项都放了
trap指令,而它恰恰不是特权指令——这是本节被反复利用的唯一一个反直觉点。 - 判断"某态只能执行某类指令"的四种组合(2022-27)。答用户态只能执行非特权指令。四个选项把"只能 + 特权/非特权"和"用户态/内核态"两两配齐,只有这一种成立。⚠️ 最有迷惑力的是"内核态只能执行特权指令"——内核里大量代码也是普通指令,"只能"这个词就把它判死了。
- 给四个程序,问哪个在用户态执行(2011-24)。答命令解释程序(shell)。另三个(缺页处理、进程调度、时钟中断处理)都要动内核数据结构。⚠️ 这道题换了问法,判据从"指令权限"变成"要访问什么资源",按前一条判据是答不出来的。
复习优先级:必须拿满。这一节考点窄、判据单一,把特权指令那张表的三处归类 (改硬件状态 / 改保护规则 / 改控制流权限)记住,加上 trap 与 iret 这一对反例, 选择题就没有失分空间。第四节那条"看程序访问什么资源"的判据要单独记, 它和前面几节用的不是一套。
易错:把陷入指令(
trap/ 访管指令)当成特权指令。它必须能在用户态执行,安全性靠"执行后由硬件带入内核、入口由内核决定"来保证。
易错:说"内核态只能执行特权指令"。内核态能执行全部指令;只有"用户态只能执行非特权指令"这一句是对的。
易错:把"用户态不能执行特权指令"当成完整答案。完整的是"指令不被执行 + 产生非法指令异常 + 进程被终止"。
易错:认为 shell 是 OS 的一部分、运行在内核态。它是普通用户进程;调用系统调用的代码仍在用户态。
易错:把用户态执行特权指令产生的当成外中断。它由当前指令自身引发,是内中断(异常)。
易错:把态切换当成进程切换。系统调用返回后通常仍是同一进程;反过来"进程切换必然在内核态"才成立。
教材出处
- 孙钟秀、费翔林《操作系统教程》(第 6 版)2.1 处理器(p43):处理器状态位是"程序状态字中的比特位";"大多数计算机系统的处理器状态有 4 种,分别支持 0~3 级共 4 个特权级别",而"几乎所有通用操作系统实现都只使用了 0 级与 3 级";处理器状态转换一节给出"只有中断才会使处理器从用户态向内核态转换"及其三类情况,并指出"计算机系统通常会提供一条称作加载程序状态字的特权指令(如 iret 指令),用于实现从内核态返回用户态"。
- 同书 2.2.2 中断源·程序性中断事件(p46):处理原则中明确"非法指令、用户态使用特权指令、地址越界、非法存取等指令异常:终止进程"。
- 同书 1.3.5 系统调用(p25):"由于系统调用而引起处理器中断的机器指令称为陷入指令(trap),它是非特权指令,在用户态下执行时会产生 CPU 模式切换。"
相关知识
操作系统基本概念与发展历程|中断和异常的处理|系统调用|虚拟机