HNU2026-操作系统-笔记 3 Mechanism: Limited Direct Execution
本文介绍了受限直接执行(LDE)机制的核心思想。LDE通过硬件和操作系统协作实现CPU虚拟化,平衡性能与控制需求。关键点包括:1)采用用户态/内核态双模式隔离特权操作;2)通过系统调用和定时器中断实现控制权转移;3)利用上下文切换保存/恢复进程状态。LDE让程序直接运行在CPU上,同时通过陷阱表初始化、时钟中断等机制确保操作系统始终能重新获得控制权。这种机制既保证了执行效率,又维持了系统安全性和调
Mechanism: Limited Direct Execution (受限直接执行)
课件:[[第3次课-06. Mechanism_Limited_Direct_Execution.pptx]]
教材:OSTEP Chapter 6
上一章我们知道了“进程”这个抽象,但要让多个进程轮流运行,光有抽象还不够,还需要一套具体机制。
本章要解决两个问题:
- 性能(Performance):CPU 虚拟化怎样做,额外开销才不会太大?
- 控制(Control):程序高效运行时,操作系统怎么保证自己随时能拿回控制权?
OSTEP 的答案是:受限直接执行(Limited Direct Execution, LDE)。
核心思路很朴素:平时让程序直接在硬件上跑,关键时刻再由硬件和内核接管。
1. 从“直接执行”说起
最理想的性能方案就是直接执行:OS 完成初始化后,让程序一路在 CPU 上跑。
课件给出的典型流程是:
- OS 侧:创建进程项、分配内存、装入程序、设置
argc/argv、清寄存器; - 程序侧:执行
main(),返回后退出; - OS 侧:回收内存、移除进程项。
这种方案很快,但有个根本问题:如果不加限制,OS 会失去控制。
用户程序可能直接做危险操作,也可能死循环不交出 CPU。那时操作系统就退化成“普通库”,不再是管理者。
所以关键不是“要不要直接执行”,而是:如何在直接执行上加边界。
2. 问题一:受限操作怎么做?(Restricted Operation)
2.1 双模式:用户态与内核态
硬件先提供最基础的隔离机制:
- User mode(用户态):应用不能直接访问全部硬件资源;
- Kernel mode(内核态):内核可执行特权操作。
这样,像磁盘 I/O、进程创建、内存扩展这类操作,就不能让应用直接碰硬件,只能经内核代理。
2.2 系统调用与受保护控制转移
应用想要特权功能时,走系统调用路径:
- 执行
trap指令,陷入内核; - 硬件提升特权级,跳到内核处理例程;
- 内核完成检查与执行;
- 执行
return-from-trap,返回用户态继续运行。
这条路径的关键是“受保护控制转移(protected control transfer)”:
用户程序只能进入内核允许的入口,不能随意跳到内核任意地址。
2.3 Trap table 为什么在启动时初始化?
课件强调:OS 在 boot 阶段就初始化陷阱表(中断向量表),把系统调用和中断处理入口写给硬件。
之后每次 trap 或 interrupt,硬件按表跳转。这能防止用户程序伪造入口地址。
3. 问题二:OS 如何重新拿回 CPU?(Regaining Control)
只靠系统调用还不够,因为程序可能一直不调用系统调用。
3.1 协作式方案(Cooperative)
思路是“程序主动让出 CPU”:
- 通过
yield()等系统调用交还控制权; - 或发生非法操作(如除零、非法地址访问)触发异常,陷入内核。
问题是:若程序死循环且不触发系统调用,OS 就拿不回 CPU,只能重启。
3.2 非协作式方案(Non-Cooperative)
现代 OS 用硬件定时器解决这个问题:
- OS 启动时编程 timer;
- timer 每隔若干毫秒触发一次时钟中断;
- 中断发生时,当前进程被硬件打断,状态被保存,CPU 强制转入内核处理程序。
这意味着:无论进程愿不愿意,OS 都能定期重新获得运行机会。
4. 上下文切换(Context Switch)
当中断或系统调用让内核重新运行后,调度器要决定:
- 继续当前进程;还是
- 切换到另一个进程。
若发生切换,核心工作是“保存旧上下文 + 恢复新上下文”。
4.1 需要保存/恢复哪些状态?
课件列出的重点包括:
- 通用寄存器;
- 程序计数器(PC);
- 栈相关寄存器(尤其是内核栈指针)。
4.2 切换动作的本质
switch() 这段低层汇编通常做三件事:
- 把进程 A 的寄存器现场写入 A 的内核数据结构;
- 从进程 B 的内核数据结构读出寄存器现场;
- 把栈指针切到 B 的内核栈,然后返回。
“返回”之后,CPU 自然就会按 B 的现场继续执行。
5. 结合时钟中断看完整 LDE 协议
课件第 14、15 页给出的链路可以串成下面这条主线:
- boot 阶段:OS 初始化 trap table,并启动 timer。
- 用户态运行 A:A 正在 CPU 上执行。
- timer 中断到来:硬件保存 A 的必要状态,切入内核。
- 内核处理 trap:调度器决定切到 B。
- 调用
switch():保存 A、恢复 B、切换到 B 的内核栈。 - return-from-trap:硬件回到用户态,从 B 的 PC 继续执行。
所以“受限直接执行”并不是频繁模拟执行,而是:
大部分时间直接跑用户代码,少量关键时刻由硬件强制回到内核并完成切换。
6. xv6 switch 代码怎么看
课件给了 xv6 的 switch(struct context **old, struct context *new) 代码。读这段代码时抓两段就够:
- 前半段:把当前寄存器写入
old指向的上下文; - 后半段:从
new指向的上下文恢复寄存器并切换栈; - 最后
ret:跳转到新上下文对应的位置继续执行。
这就是“上下文切换”的可执行版本。
7. 中断处理中又来中断怎么办?
课件最后提出并发问题:处理中断时如果又来一个中断,会不会把内核状态搞乱?
常见应对手段:
- 在关键中断处理区间临时关闭中断;
- 用锁机制保护内核共享数据结构。
本质上都是为了保证:内核状态更新可控且一致。
随堂复习自测
1)为什么“无限制直接执行”不可行?
因为用户程序可能越权访问硬件或不交还 CPU,OS 会失去控制。
2)系统调用是如何安全进入内核的?
通过
trap+ 已初始化的 trap table 进行受保护控制转移,入口由硬件强制决定。
3)为什么现代 OS 必须依赖时钟中断?
因为它提供非协作抢回控制权的能力,保证 OS 能周期性运行调度逻辑。
4)上下文切换的最低必要动作是什么?
保存当前进程寄存器现场,恢复目标进程寄存器现场,并切换到目标进程内核栈。
5)LDE 的核心思想一句话怎么说?
让应用尽量直接在 CPU 上运行,但通过 trap、timer interrupt 和上下文切换机制确保 OS 始终可控。
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐


所有评论(0)