arm64系统调用分析
1、理解整个中断/系统调用流程的关键是kernel_entry和kernel_exit,也就是如何保存现场,并且恢复现场的。
我们先来看下armv8的寄存器,PLR(X30)无论是用户态还是内核态都用这个寄存器来存储程序的返回值。
sp_el0,sp_el1分别是有用户态和内核态的堆栈。
ELR_EL1用于存储,当在发生系统调用、异常、中断时,当前程序的pc值(无论是用户态还是内核态)。
SPSR_EL1用于存储,当在发生系统调用、异常、中断时,当前程序的PSTATE(无论是用户态还是内核态)。

2、当发生中断、异常、系统调用时,硬件会自动:
1)把当前程序的pc值放入ELR_EL1中
2)把当前状态PSTATE存入SPSR_EL1中
3)根据发生在内核态还是用户态,中断还是异常,会自动跳转到el1_sync,el1_irq,el0_sync,el0_irq
4)改变PSTATE,如果是用户态发生中断、异常、系统调用,此时已经进入内核态,堆栈是sp_el1。
3、kernel_entry
执行完kernel_entry的堆栈,ELR_EL1存放的是返回的PC值,SPSR_EL1存放的是返回的PSTATE。
如果是用户态发生的中断、异常、系统调用,则栈中保存都是用户态的寄存器信息。
如果是内核态发生的中断、异常,则栈中保存的内核态的寄存器信息。
4、kernel_exit
前面我们已经说过:
el1_sync,el1_irq调用的是kernel_entry 1,kernel_exit 1,也就是上面宏el为1。
el0_sync,el0_irq调用的是kernel_entry 0,kernel_exit 0,也就是上面宏el为0。
我们可以看到 .macro kernel_exit, el, ret = 0,还有一个参数ret,只有在el0_sync处理系统调用时会被置成1。
发生中断、异常、系统调用前是用户态,则返回用户态的寄存器(pc,lr,sp_el0,pstate)。注意还要把内核态的栈平衡了:ldr lr, [sp], #S_FRAME_SIZE - S_LR // 恢复lr,恢复内核sp_el1
发生中断、异常、系统调用前是内核态,则返回内核态的寄存器(pc,lr,sp_el1,pstate)。
如果处理系统调用x0存放的是系统的调用的返回值,所以不需要从堆栈中恢复。
更详细分析见:
https://cloud.tencent.com/developer/article/1413292

浙公网安备 33010602011771号