图为PCB的结构,内核栈位于PCB的高地址。内核栈详解如下:
1. 用户栈程序经0x80中断进入内核,将用户栈指针 pc指针等压栈
2. 调用sys_call,将一些现场信息压入栈
2. 进入reschedule,若引发调度则进入调度函数,否则进行ret,这里若引发调度也要先把ret函数地址压栈,保证调度完了能够正常返回,如下图
3.调度函数内部调用的是系统调用switch_to,准备好需要的参数,调用switch函数
4. 进入switch_to以后,将一些调用者寄存器压栈,以便后续使用
5. 这时切换内核,将esp指针换成另一个内核栈的栈顶,注意此时那个内核栈的栈顶也是长上图这个样子的。切换过去内核栈以后,switch将eax ebx ecx等弹出,最后ret弹出},回到schdule函数的}处执行,
在C函数的“}” 处,会自动弹出参数pnext 和_LDT(next),并弹出ret_from_sys_call的地址作为EIP开始执行ret_from_sys_call。
内核栈情况如下:
6. ret from sys call执行完以后
7. 最后执行iret,将上图中的内核栈依次弹出,从而返回用户态。