惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

S
Secure Thoughts
罗磊的独立博客
T
The Blog of Author Tim Ferriss
人人都是产品经理
人人都是产品经理
博客园 - 叶小钗
Last Week in AI
Last Week in AI
美团技术团队
Google Online Security Blog
Google Online Security Blog
Application and Cybersecurity Blog
Application and Cybersecurity Blog
D
Docker
G
Google Developers Blog
大猫的无限游戏
大猫的无限游戏
酷 壳 – CoolShell
酷 壳 – CoolShell
小众软件
小众软件
月光博客
月光博客
L
LINUX DO - 最新话题
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
W
WeLiveSecurity
H
Heimdal Security Blog
Vercel News
Vercel News
SecWiki News
SecWiki News
Forbes - Security
Forbes - Security
Blog — PlanetScale
Blog — PlanetScale
Google DeepMind News
Google DeepMind News
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
www.infosecurity-magazine.com
www.infosecurity-magazine.com
TaoSecurity Blog
TaoSecurity Blog
T
Troy Hunt's Blog
A
About on SuperTechFans
C
Check Point Blog
S
Security Affairs
Hacker News - Newest:
Hacker News - Newest: "LLM"
AI
AI
WordPress大学
WordPress大学
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
Help Net Security
Help Net Security
博客园_首页
The Last Watchdog
The Last Watchdog
S
SegmentFault 最新的问题
Hugging Face - Blog
Hugging Face - Blog
Security Archives - TechRepublic
Security Archives - TechRepublic
Engineering at Meta
Engineering at Meta
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
I
Intezer
K
Kaspersky official blog
M
MIT News - Artificial intelligence
J
Java Code Geeks
G
GRAHAM CLULEY
P
Palo Alto Networks Blog

zStack

Kerberos 认证体系引起的产品系统免密问题 | zStack 通过 strace 追踪 sqlldr 的性能问题 控糖革命 | zStack 单例模式的几种 C++ 实现 | zStack 通过 ChatGPT 协助解决软件安装问题 | zStack 【xv6】Copy on write fork() | zStack 【xv6】system call | zStack 如何用 C 实现协程 | zStack 利用 nginx-upload-module 实现文件上传和重命名 | zStack 在 WSL2 的 Arch Linux 下编译并替换内核 如何找到一个适合自己的笔记软件 | zStack 为终端设置 ASCII ART | zStack Qver - 用于练手的服务器程序 | zStack 关于我在宿舍种草的那些事 | zStack
【xv6】trap | zStack
Noicdi · 2022-10-05 · via zStack

【xv6】trap

2022-10-05 09:00:00 #操作系统  #xv6 

当遇到一些事件时,会要求 CPU 从一般代码的执行转移到特殊的事件处理机制,这个机制就是 trap。也可以看作操作系统从用户态陷入内核态。

一般来说有三种情况会触发 trap:

  1. system call 通过 ecall 进入内核态;
  2. 程序访问越界或访问地址 0;
  3. I/O 设备引发中断,例如读写完成。

发生 trap 时,执行流从用户态转移到内核态,保存用户态的状态(寄存器、页表等),在执行完事件处理机制后,再回到用户态程序转移前执行的代码。trap 对于用户态程序来说是透明的,并不知道发生了什么。

system call 触发 trap

system call 从用户态触发 traps,这里通过一张简单的图给出大致流程:

xv6-trap-1

以用户程序调用 sleep() 为例,不会进入具体的 c 函数,而是通过 usys.S 中找到相关的入口,保存 sleep() 的调用号 SYS_sleep 到寄存器 a7,并通过汇编指令 ecall 陷入内核态。

当汇编代码中调用 ecall 时,首先会从 user mode 转换到 supervisor mode;其次会保存程序计数器 pc 到寄存器 sepc;最后会将 pc 设置成寄存器 stvec 保存的值,stvec 中保存了 trampoline page 的起始地址,这个页块中保存的是 uservec()userret() 的汇编代码。

在跳转到 trampoline page 后, uservec() 会对诸多寄存器做处理。首先将寄存器 a0 的值保存到寄存器 sscratch 中,这样可以在 a0 中填入 TRAPFRAME,指向的是 trapframe page 的地址,xv6 会在这个页块中保存用户态下的寄存器。然后会将 trapframe page 保存的前几个值写入寄存器。16(a0) 所保存的是 struct trapframe 结构体中的 kernel_trap,这里指向了 trap.c/usertrap() 的地址。

跳转到 usertrap() 后,会获取当前进程的 struct proc,并将寄存器 sepc 保存到 proc->trapframe->epc 中,防止发生进程调度,覆盖这个寄存器。然后检查寄存器 scause,这个寄存器用于保存发生 trap 的原因的描述号。

system call 的描述号是 8,通过检查后会对 proc->trapframe->epc + 4,这是因为 proc->trapframe->epc 保存的是用户态中汇编指令 ecall 的地址,+4 后指向其下一个汇编指令。

然后通过 syscall.c/syscall() 找到 system call sleep() 真正的实现函数 sys_sleep() 并执行,保存其返回值到 a0 中。

当 system call 执行完成后,就需要从内核态回到用户态,在这之前要恢复环境。调用 trap.c/usertrapret(),关中断;变量 trampoline_uservec 计算得到 trampoline.S/uservec() 的地址,通过内联汇编保存到寄存器 stvec 中,方便下一次 system call 时使用;然后保存 kernel 相关寄存器的值到 proc->trapframe 中;变量 x 用于修改状态并保存到寄存器 sstatus 中;写入 ecall 下一个汇编指令的地址到寄存器 sepc 中,方便 pc 使用;变量 satp 记录用户态页表;变量 trampoline_userret 计算得到 trampoline.S/userret() 的地址,并以 satp 作为参数进行调用。

trampoline.S/userret() 中,将 trapframe page 中记录的值恢复到寄存器中,汇编指令 sret 将寄存器 sepc 中记录的值写入 pc,从 supervisor mode 恢复到 user mode,并开中断。这样就会回到用户程序并继续执行。