Operating Systems Notes: The Path to the Kernel

1. 核心概念与关系

  • Interrupt (中断): 异步事件,由外部硬件(键盘、网卡、定时器)触发。它的发生与程序执行流无关。
    • 比喻: 外来的电话打断了你当前的工作。
  • Trap (陷阱): 同步事件,由内部软件(当前正在执行的指令)主动触发。它是可预测的,是程序逻辑的一部分。
    • 比喻: 你在工作中遇到一个需要老板审批的环节,于是你主动放下工作去敲老板的门。
  • Exception (异常): 同步事件,由内部软件执行出错被动触发。
    • 比喻: 你在工作中算错了一个数字,导致流程无法继续,被动地需要老板介入。
  • System Call (系统调用): 一个高层概念,是操作系统提供给用户程序的服务接口(如读写文件、创建进程)。它不是一个硬件机制。

最重要的关系: 用户程序通过主动触发一次 Trap 来向内核发起一次 System Call 请求。 Trap 是实现 System Call 的底层机制。

2. int 指令的“身份”之谜

  • int 指令是 Trap: 尽管它的名字叫 int (interrupt),但它的行为(软件触发、同步发生)完全符合 Trap 的定义。
  • 为什么叫 int: 因为它在硬件层面复用了与硬件中断相同的处理机制(中断描述符表 IDT)。
  • int 的多样性:
    • int 0x80: 在32位Linux上,是发起系统调用的传统方式。
    • int 3: 用于调试断点
    • int 0: 用于处理除零异常
    • 结论: 并非所有 int 触发的陷阱都是为了系统调用。

3. 一次完整系统调用的生命周期

这是一个从用户空间到内核空间再返回的完整旅程:

  1. 用户空间 (User Space): 程序调用一个库函数,如 write()
  2. C 库包装 (Wrapper): 执行流进入C标准库(glibc)。这个包装函数负责准备工作:
    • 系统调用编号放入约定好的寄存器(如 %rax)。
    • 函数参数放入其他寄存器。
  3. 触发陷阱 (Trigger Trap): 包装函数执行一条特殊指令来陷入内核。
    • 经典方式: int 0x80
    • 现代方式: syscall
  4. 模式切换 (Mode Switch): CPU硬件响应陷阱指令,自动完成:
    • 暂停用户程序。
    • 切换到内核模式 (Kernel Mode)
    • 查找并跳转到内核的陷阱处理程序入口。
  5. 内核空间 (Kernel Space):
    • 内核的陷阱处理程序首先接管。
    • 它从 %rax 寄存器中读取系统调用编号
    • 使用该编号作为索引,在系统调用表 (System Call Table) 中查找并调用真正的内核函数(如 sys_write())。
    • sys_write() 执行特权操作。
  6. 返回 (Return):
    • 内核函数执行完毕,将返回值存入寄存器。
    • 内核执行 sysretiret 指令,触发硬件切换回用户模式
    • 用户程序从陷阱指令之后的地方恢复执行。
  7. 回到用户空间: C 库包装函数从寄存器中取回返回值,并将其返回给调用者。

4. syscall vs. int 0x80:效率的进化

  • 共同点: 两者都是触发陷阱的指令,目的都是为了发起系统调用。进入内核后,确定具体调用的方式(查 %rax 寄存器)是一样的
  • 区别 (效率):
    • int 0x80: 走通用的中断处理路径,需要查询中断描述符表 (IDT),开销稍大。
      • 比喻: 去政府大楼的总咨询台问路,再被指引到正确的部门。
    • syscall: 走为系统调用优化的专用硬件路径,直接读取CPU专用寄存器 (MSR) 来找到入口地址,开销极小。
      • 比喻: 直接用专线电话打给目标部门的负责人,跳过了总咨询台。

结论: syscall 是一个更高效的“陷阱触发器”,但它并没有改变“陷阱 -> 查编号 -> 执行”这个基本流程。