本文解析进程上下文切换的核心代码;区别于linux的使用TR寄存器的硬切换,也区别于linux的软切换;FreeBSD的切换仍然继承于unix-v6风格下的函数栈的切换(直接简单可理解),所以理解函数栈帧的切换是其中的本质;进程切换要保存进程的现场环境以便于恢复现场,这里就需要重新去温习一下x86_64位的硬件体系结构编程,最后对汇编语言的理解和编写能力也有一定的要求,这里的汇编不是nasm而是gas语法.
1. x86_64平台寄存器使用约定
相关的内容可以点击这里了解,函数参数使用的寄存器参照下图:
2. 上下文硬件切换代码位置
1 | // freebsd/sys/kern/sched_ule.c(line:2145) |
3. x86_64位的硬件的寄存器
4. cpu_switch注释
这个需要另外开辟一个笔记来记录栈帧原理,虽然x86和x86_64的栈帧回溯方式发生了改变,但是在FreeBSD中,使用的还是x86的栈帧方式;具体文章可以先参考这里;
cpu_switch的切换进程的基本原理是先将旧的进程保存到旧进程的 PCB结构中(内核页),然后将新进程的PCB中的寄存器信息恢复到寄存器中,其中rbp和rsp的恢复比较重要,至此在ret的时候将跳转到rsp所指的地址去执行(也就是新进程去执行),整个切换过程都是在内核模式下进行的.以下cpu_switch的参数意思参考第一节的内容,pcb的保存所使用的寄存器信息参见第三节的图片.
1 | //freebsd/sys/amd64/amd64/cpu_switch.S(line:75) |
后续: 上下文切换的硬件依赖性部分就是这个cpu_switch函数,因为注重效率所以使用gas汇编编写,其中未有详尽的地方也可以看完以后思考一下,这个切换是否可以打断?如果能够打断会发生什么?不同CPU上运行的代码是否是共用一套寄存器,还是每个CPU单独使用寄存器,上述代码对于页面的保存恢复没有注释,以及如果一个进程被迁出内存了,放在虚拟内存的时候,是否可以直接切换到这个进程执行,还是需要等待所有内容迁入到内存中在执行?跟平台无关的进程上下文切换函数是mi_switch,他最终调用不同平台的cpu_switch实现,上述代码是x86_64平台下的实现,后续将读源码的进度继续解读进程切换的细节