OPERATING SYSTEMS / AN INTERACTIVE WORKBENCH
从用户态出发,再回到用户态.
用户程序与参数 → CPU 入口机制 → 内核处理链 → 现场恢复 i386 · int 0x80 · read(fd, buf, len)
用户侧 代码 / 参数 / 栈
执行核心 / 状态与现场
内核内存 表与配置
用户程序CPL=3
1mov eax, 3; read
2mov ebx, fd; 参数 1
3mov ecx, buf; 参数 2
4mov edx, len; 参数 3
5int 0x80; 陷入
6; 下一条指令:继续执行
封装代码用户栈中断向量号 0x80
通用寄存器CPU · 传参视图
EAX3 · read系统调用号
EBXfd参数 1
ECXbuf参数 2 · 地址
EDXlen参数 3
用户栈SS : ESP
buf 缓冲区(本例放在栈上)
局部变量
返回地址
⋯ 栈顶
进入内核后暂时不用,但不会被销毁
读图约定LEGEND
- 青 · 用户态 CPL=3
- 琥珀 · 内核态 CPL=0
- 紫 · 硬件原子动作
- 虚线 · 快速路径
- 亮线和移动光点表示本步数据或控制流向。
断点回位返回点
int 0x80 的下一条下一条
恢复现场后,用户程序从这里继续,接收本次系统调用的返回结果。
CPU · 硬件硬件原子动作
CURRENT PRIVILEGE
3用户态
CS 低 2 位 = 3
CS · 代码段选择子用户代码段 · CPL=3
EIP / RIP · 指令指针用户断点
EFLAGS · IF 位IF = 1
SS : ESP · 当前栈用户栈
IDTR · IDT 基址→ IDT 基址
TR · 任务寄存器→ TSS
MSR · 快速入口
快速入口地址 · 段选择子 · 标志清除掩码
不查 IDT · 硬件不压栈 / 换栈
内核处理链CPL=0
汇编入口保存剩余通用寄存器,形成 trapframe
›
trap()陷阱总处理,判断为系统调用
›
syscall()按系统调用号查分派表
›
read()具体服务例程,真正执行
⤷ 硬件跳到的是内核汇编入口,不是 trap() 本身。
内核栈 · 现场快照低地址 ↑ 栈顶
trapframe = 硬件现场 + 汇编保存SS : ESP ← TSS
通用寄存器EAX · EBX · ECX · EDX …汇编保存
EIP用户断点(int 0x80 的下一条)硬件
CS用户代码段 · CPL=3硬件
EFLAGSIF = 1(用户态旧值)硬件
ESP用户栈指针硬件
SS用户栈段硬件
硬件 5 项 + 汇编保存的通用寄存器 = 本例需要恢复的用户现场
IDT · 中断描述符表访存
0x00预置门描述符
0x80系统调用门DPL
内核 CS 选择子内核入口偏移门类型DPL
IDTR 给出基址;按向量号 0x80 取项
GDT · 全局描述符表描述符
内核内核代码段 · DPL 0
用户用户代码段 · DPL 3
门里的选择子指向这里
TSS · 任务状态段内核栈
SS内核栈段
ESP内核栈指针
TR 关联 TSS;进入内核时取栈
系统调用分派表按号
syscall() 用系统调用号索引 · 不是向量号
3read示例号
4write
5open
…其他服务例程
表项给出具体服务例程入口
两个编号,别混
0x80中断向量号 → 查
IDT 拿门描述符3系统调用号 → 查
分派表 拿 read 入口注门类型决定入口处 IF:中断门清零,陷阱门不清零。
硬件动作 · 分解慢放
按笔记顺序拆开观察;画面间隔不代表用户程序可介入。