Linux系统的一般执行过程
(1)正在运行的用户态进程X。
(2)发生中断(包括异常、系统调用等),CPU完成load cs:rip(特定ISR入口点),即跳转到中断处理程序入口。
(3)中断上下文切换,具体包括以下几点:
• swapgs指令保存现场,通过swapgs指令快照当前CPU的寄存器状态。
• rsp指向内核堆栈,将当前进程的内核堆栈顶部地址加载到rsp寄存器。快速系统调用是通过系统调用入口处的汇编代码实现用户堆栈和内核堆栈的切换。
• 保存cs:rip/ss:rsp/rflags:将当前CPU关键上下文保存到进程X的内核堆栈中,快速系统调用是通过系统调用入口处的汇编代码实现的。
完成中断上下文切换后,即从进程X的用户态切换到进程X的内核态。
(4)在中断处理过程中或中断返回之前,调用schedule函数。此函数完成进程调度算法的选择,包括选择下一个进程、进行进程地址空间切换以及关键的进程上下文切换(switch_to)等操作。
(5)switch_to调用__switch_to_asm汇编代码,执行关键的进程上下文切换。将当前进程X的内核堆栈切换到调度算法选择的下一个进程Y的内核堆栈,并完成进程上下文所需的指令指针寄存器状态切换。然后开始运行进程Y(假设通过上述步骤切换出来的进程)。
(6)中断上下文恢复,与(3)中的中断上下文切换相对应。需要注意的是,这是在进程Y的中断处理过程中发生的,而(3)中的中断上下文切换是在进程X的中断处理过程中发生的,因为内核堆栈已从进程X切换到进程Y。
(7)为了对应,中断上下文恢复的最后一步单独列出(6的最后一步),即iret - pop cs:rip/ss:rsp/rflags。从进程Y的内核堆栈中弹出(3)中相应的堆栈内容。完成中断上下文切换,即从进程Y的内核态返回到进程Y的用户态。需要注意,快速系统调用返回sysret和iret处理稍有不同。
(8)继续执行用户态进程Y。
虚拟化相关不是非常理解,此处仅给出我所查询到的相关信息:
Qemu模拟外设,通过irqfd来触发Hypervisor进行中断注入;
Hypervisor往List Register写入虚拟中断,Virtual CPU interface将virtual irq信号发送至vCPU;
CPU将处理该异常,Guest OS会从Virtual CPU Interface读取中断状态进行响应。
课程总结 完成Linux操作系统分析课程后,我学到了许多关键概念和核心原理。以下是课程主要内容的概述:
学习了Linux操作系统的生态环境,了解了操作系统的发展历程。不同架构计算机对操作系统运行带来的差异,掌握了常用的x86,arm64,riscv汇编;中断发生时的具体操作;进程创建时,切换时发生的故事;系统调用与函数调用的异同。更重要的是授人以渔,学会了如何调试linux操作系统内核,这样再有不会的地方也可以通过跟进代码来获得相关信息了。