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