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存放的是系统的调用的返回值,所以不需要从堆栈中恢复。

 

 系统调用实现

 

 

 

 

.macro kernel_ventry, el, label, regsize = 64
.align = 7   // 地址对齐要求
sub sp, sp, #S_FRAME_SIZE   //堆栈指针处理
b el\()\el\()_\label        //跳转
.endm

系统调用是从“kernel_ventry 0, sync”进入,即el=0,label=sync。因此最终跳转进入el0_sync汇编

其中" \()"是汇编符号连接,\el和\label是汇编宏的参数引用。

 

汇编宏el0_sync

汇编宏el0_sync主要分为两部分:第一部分实现从用户空间到内核空间的上下文切换, kernel_entry 0;第二部是根据异常症状寄存器esr_el1判断异常原因,然后再进入具体处理函数。系统调用是用户态执行SVC指令导致的,因此要进入el0_svc处理函数。
 

/*
 * EL0 mode handlers.
 */
        .align  6
el0_sync:
        kernel_entry 0
        mrs     x25, esr_el1                    // read the syndrome register
        lsr     x24, x25, #ESR_ELx_EC_SHIFT     // exception class
        cmp     x24, #ESR_ELx_EC_SVC64          // SVC in 64-bit state 
        b.eq    el0_svc                         // 这系统调用入口
        cmp     x24, #ESR_ELx_EC_DABT_LOW       // data abort in EL0
        b.eq    el0_da
        cmp     x24, #ESR_ELx_EC_IABT_LOW       // instruction abort in EL0
        b.eq    el0_ia
        cmp     x24, #ESR_ELx_EC_FP_ASIMD       // FP/ASIMD access
        b.eq    el0_fpsimd_acc
        cmp     x24, #ESR_ELx_EC_SVE            // SVE access
        b.eq    el0_sve_acc
        cmp     x24, #ESR_ELx_EC_FP_EXC64       // FP/ASIMD exception
        b.eq    el0_fpsimd_exc
        cmp     x24, #ESR_ELx_EC_SYS64          // configurable trap
        ccmp    x24, #ESR_ELx_EC_WFx, #4, ne
        b.eq    el0_sys
        cmp     x24, #ESR_ELx_EC_SP_ALIGN       // stack alignment exception
        b.eq    el0_sp
        cmp     x24, #ESR_ELx_EC_PC_ALIGN       // pc alignment exception
        b.eq    el0_pc
        cmp     x24, #ESR_ELx_EC_UNKNOWN        // unknown exception in EL0
        b.eq    el0_undef
        cmp     x24, #ESR_ELx_EC_BREAKPT_LOW    // debug exception in EL0
        b.ge    el0_dbg
        b       el0_inv
 

 


 

案例

[root@centos7 arm]# uname -a
Linux centos7 4.14.0-115.el7a.0.1.aarch64 #1 SMP Sun Nov 25 20:54:21 UTC 2018 aarch64 aarch64 aarch64 GNU/Linux
[root@centos7 arm]#

 

svc指令

//静态编译
[root@centos7 arm]# gcc test.c -o test --static
//反汇编
objdump -D  test > test.txt

 





 20634 0000000000413d8c <__libc_open>:
 20635   413d8c:       a9af7bfd        stp     x29, x30, [sp,#-272]!
 20636   413d90:       910003fd        mov     x29, sp
 20637   413d94:       f90073a2        str     x2, [x29,#224]
 20638   413d98:       a90153f3        stp     x19, x20, [sp,#16]
 20639   413d9c:       2a0103e2        mov     w2, w1
 20640   413da0:       f90077a3        str     x3, [x29,#232]
 20641   413da4:       f9007ba4        str     x4, [x29,#240]
 20642   413da8:       f9007fa5        str     x5, [x29,#248]
 20643   413dac:       f90083a6        str     x6, [x29,#256]
 20644   413db0:       f90087a7        str     x7, [x29,#264]
 20645   413db4:       3d801ba0        str     q0, [x29,#96]
 20646   413db8:       3d801fa1        str     q1, [x29,#112]
 20647   413dbc:       3d8023a2        str     q2, [x29,#128]
 20648   413dc0:       3d8027a3        str     q3, [x29,#144]
 20649   413dc4:       3d802ba4        str     q4, [x29,#160]
 20650   413dc8:       3d802fa5        str     q5, [x29,#176]
 20651   413dcc:       3d8033a6        str     q6, [x29,#192]
 20652   413dd0:       3d8037a7        str     q7, [x29,#208]
 20653   413dd4:       aa0003e1        mov     x1, x0
 20654   413dd8:       37300262        tbnz    w2, #6, 413e24 <__libc_open+0x98>
 20655   413ddc:       52880003        mov     w3, #0x4000                     // #16384
 20656   413de0:       72a00803        movk    w3, #0x40, lsl #16
 20657   413de4:       0a030043        and     w3, w2, w3
 20658   413de8:       7150107f        cmp     w3, #0x404, lsl #12
 20659   413dec:       d2800003        mov     x3, #0x0                        // #0
 20660   413df0:       540001a0        b.eq    413e24 <__libc_open+0x98>
 20661   413df4:       f0000460        adrp    x0, 4a2000 <initial+0x248>
 20662   413df8:       b94f0800        ldr     w0, [x0,#3848]

 

 20663   413dfc:       35000380        cbnz    w0, 413e6c <__libc_open+0xe0>
 20664   413e00:       92800c60        mov     x0, #0xffffffffffffff9c         // #-100
 20665   413e04:       93407c42        sxtw    x2, w2
 20666 413e08: d2800708 mov x8, #0x38 // #56 20667 413e0c: d4000001 svc #0x0
 20668   413e10:       b140041f        cmn     x0, #0x1, lsl #12
 20669   413e14:       540001e8        b.hi    413e50 <__libc_open+0xc4>
 20670   413e18:       a94153f3        ldp     x19, x20, [sp,#16]
 20671   413e1c:       a8d17bfd        ldp     x29, x30, [sp],#272
 20672   413e20:       d65f03c0        ret
 20673   413e24:       910383a0        add     x0, x29, #0xe0
 20674   413e28:       f9002ba0        str     x0, [x29,#80]
 20675   413e2c:       128005e0        mov     w0, #0xffffffd0                 // #-48
 20676   413e30:       910443a4        add     x4, x29, #0x110
 20677   413e34:       b9005ba0        str     w0, [x29,#88]
 20678   413e38:       12800fe0        mov     w0, #0xffffff80                 // #-128
 20679   413e3c:       b980e3a3        ldrsw   x3, [x29,#224]
 20680   413e40:       f90023a4        str     x4, [x29,#64]
 20681   413e44:       f90027a4        str     x4, [x29,#72]
 20682   413e48:       b9005fa0        str     w0, [x29,#92]
 20683   413e4c:       17ffffea        b       413df4 <__libc_open+0x68>
 20684   413e50:       90000462        adrp    x2, 49f000 <__FRAME_END__+0x10aa8>
 20685   413e54:       f947c842        ldr     x2, [x2,#3984]
 20686   413e58:       4b0003e0        neg     w0, w0
 20687   413e5c:       d53bd041        mrs     x1, tpidr_el0
 20688   413e60:       b8226820        str     w0, [x1,x2]
 20689   413e64:       92800000        mov     x0, #0xffffffffffffffff         // #-1
 20690   413e68:       17ffffec        b       413e18 <__libc_open+0x8c>
 20691   413e6c:       f9001ba1        str     x1, [x29,#48]

 

可以看到将寄存器x8设置为系统调用号0x38 (openat),
然后调用了svc进入异常处理。

进入异常模式后,内核根据异常类型(同步异常)及当前所处的ELx, 调用相应的异常处理函数,这里是el0_sync。

 

进入异常模式后,内核根据异常类型(同步异常)及当前所处的ELx, 调用相应的异常处理函数,这里是el0_sync。
arch/arm64/kernel/entry.S
Screen Shot 2021-06-18 at 1.43.32 PM.png

Screen Shot 2021-06-18 at 1.46.03 PM.png
667,668行:通过读取esr_el1得到产生异常的原因,保存到寄存器x24
669行:判断x24中保存的异常原因是否为svc
670行:上一行如果判断相等,调用el0_svc
Screen Shot 2021-06-18 at 1.47.26 PM.png
914行:读入syscall table的指针
915行:将系统调用号(w8)保存到wscno中,上面的讲解中libc库将系统调用号写入了x8寄存器
928行:以系统调用号为索引,得到syscall table表中相应的函数地址,这里就是sys_openat
929行:调用sys_openat

 




更详细分析见:

https://cloud.tencent.com/developer/article/1413292


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM