1008 字
5 分钟
Trap、中断与系统调用详解
陷入 (Trap)
陷入是由程序主动执行特定指令(如系统调用指令 int 0x80 或 syscall)触发的同步事件。它让CPU从用户态切换到内核态,执行内核代码。
- 特点:同步(由程序主动发起)、软件驱动。
- 目的:实现用户程序向操作系统请求服务(如读写文件、创建进程)。
特权指令 (Privileged Instruction)
特权指令是只能在内核态(最高权限)下执行的指令,如修改页表基址寄存器、开关中断等。如果在用户态执行这些指令,CPU会触发一个保护异常(属于中断的一种),阻止操作。
- 特点:权限限制。
- 目的:保护系统资源不被用户程序随意修改,保证系统安全。
区别总结
| 维度 | 中断 | 陷入 | 特权指令 |
|---|---|---|---|
| 本质 | 事件(Event) | 事件(Event) | 指令(Instruction) |
| 触发源 | 硬件/异常 | 软件(程序) | 程序(试图执行) |
| 同步性 | 异步 | 同步 | 同步 |
| 作用 | 响应外部变化 | 请求系统服务 | 管理硬件资源 |
关系与交互
- 当用户程序需要执行特权操作(如读写磁盘)时,它不能直接执行特权指令,而是通过陷入(系统调用)进入内核,由内核代为执行。
- 如果用户程序非法执行特权指令,会触发一个中断(保护异常),导致程序被终止。
触发陷入(进入内核)只需要执行一条特定的指令(如 int 0x80, syscall)。但,这条指令只是一个“门铃”,按下门铃后,执行的是操作系统内核中预先写好的、功能完整且复杂的服务例程
这是一个经典的交互流程,以“写文件”这个系统调用为例:
// 用户程序int main() { write(fd, buffer, size); // 1. 调用库函数 // ...}发生的步骤:
-
库函数包装:
write是C库函数,它的核心工作是:- 将系统调用号(标识是
write)、参数(fd,buffer,size)放到约定好的寄存器或栈中。 - 执行一条
trap指令(如syscall)。 - 这条指令是用户态最后一条指令。
- 将系统调用号(标识是
-
陷入与切换:CPU执行
syscall指令,硬件自动完成:- 切换到内核态。
- 保存用户程序现场(寄存器、程序计数器等)。
- 跳转到操作系统内核预先设定好的统一入口(系统调用处理程序)。
-
内核执行复杂逻辑:现在完全在内核态运行,操作系统开始工作:
- 分发:根据放在寄存器里的系统调用号,查表找到对应的服务函数,比如
sys_write。 - 执行核心服务:
sys_write是操作系统内核里一个复杂的函数,它可能要做:- 参数检查(缓冲区是否有效?文件描述符是否合法?)。
- 从用户态缓冲区拷贝数据到内核(因为内核不能直接操作用户内存)。
- 文件系统操作:找到文件的inode,检查权限。
- 驱动交互:调用硬盘驱动程序,将数据写入缓存或直接写入磁盘。
- 进程调度:如果需要等待IO,可能会挂起当前进程,切换到其他进程运行。
- 所有这些,都是在内核态执行的特权代码,功能可以非常复杂。
- 分发:根据放在寄存器里的系统调用号,查表找到对应的服务函数,比如
-
返回结果:内核函数执行完毕后:
- 将返回值(成功写入的字节数或错误码)放入约定寄存器。
- 执行一条特殊的返回指令(如
sysret或iret)。 - CPU硬件恢复用户态现场,跳回用户程序
syscall指令之后继续执行。
所以,核心思想是:
trap 指令只是一把钥匙,打开了通往内核的大门。门后是一个由操作系统构建的、拥有完整功能和最高权限的“新世界”。用户程序通过“钥匙”请求这个世界里的“居民”(内核函数)来为自己完成复杂的特权工作。
Trap、中断与系统调用详解
https://youki.bbroot.com/posts/cs/trap-interrupt-syscall/