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

posted @ 2021-11-26 20:31  kitiz  阅读(477)  评论(0)    收藏  举报