详细参考:
https://blog.csdn.net/yangkuanqaz85988/article/details/52403726
https://www.zhihu.com/question/43699081
http://www.360doc.com/content/14/0226/14/14451193_355852979.shtml
http://www.360doc.com/content/12/0614/01/4672432_218018481.shtml
https://www.cnblogs.com/Wangzhike/p/4608405.html
http://www.voidcn.com/article/p-kdxnsdgw-bwn.html
https://www.jb51.net/LINUXjishu/540993.html
https://www.dazhuanlan.com/2020/01/30/5e3210fbabfce/
进程内核栈、用户栈
1.1. 进程的堆栈
内核在创建进程的时候,在创建task_struct的同时,会为进程创建相应的堆栈。每个进程会有两个栈,一个用户栈,存在于用户空间,一个内核栈,存在于内核空间。
当进程在用户空间运行时,cpu堆栈指针寄存器里面的内容是用户堆栈地址,使用用户栈;
当进程在内核空间运行时,cpu堆栈指针寄存器里面的内容是内核栈空间地址,使用内核栈。
1.2. 进程用户栈和内核栈的切换
当进程因为中断或者系统调用而陷入内核态之行时,进程所使用的堆栈也要从用户栈转到内核栈。
进程陷入内核态后,先把用户态堆栈的地址保存在内核栈之中,然后设置堆栈指针寄存器的内容为内核栈的地址,这样就完成了用户栈向内核栈的转换;当进程从内核态恢复到用户态之行时,在内核态之行的最后将保存在内核栈里面的用户栈的地址恢复到堆栈指针寄存器即可。这样就实现了内核栈和用户栈的互转。
那么,我们知道从内核转到用户态时用户栈的地址是在陷入内核的时候保存在内核栈里面的,但是在陷入内核的时候,我们是如何知道内核栈的地址的呢?
关键在进程从用户态转到内核态的时候,进程的内核栈总是空的。这是因为,当进程在用户态运行时,使用的是用户栈,当进程陷入到内核态时,内核栈保存进程在内核态运行的相关信心,但是一旦进程返回到用户态后,内核栈中保存的信息无效,会全部恢复,因此每次进程从用户态陷入内核的时候得到的内核栈都是空的。所以在进程陷入内核的时候,直接把内核栈的栈顶地址给堆栈指针寄存器就可以了。