一步一步写ARM汇编(五)
软中断SWI
在Linux程序中,用户程序是不能访问调用系统资源,但是可以通过系统调用或异常访问系统资源。那usr模式下是如何实现系统调用呢? 答案是通过SWI + 中断号。每一个系统调用对应一个SWI + 中断号,在arch/arm/kernel/entry-common.S下保存所有的SWI+ 中断号对应的系统调用。
在usr模式下,调用swi时cpu会跳到Supervisor工作模式下,在这个过程中会执行异常处理的所有操作,这个过程参考博文:arm异常处理流程。
示例代码如下:
areafirst, code, readonly
code32
entry
; 定义的异常向量表
vector
breset_handler ; 跳转到 reset_handler
nop
bswi_handler ; SWI 指令异常跳转的地址
nop
nop
nop
nop
nop
swi_handler
;swi handler code
;异常处理首先要压栈保存处理器现场
mrsr0, cpsr
movr0, #1
mov r1, #2
movspc, lr ; lr > pc 且 spsr -> cpsr返回 SVC -> USER
reset_handler
;初始化 SVC 模式堆栈
ldrsp, =0x40002000
;修改当前的模式从SVC模式改变为USER模式
mrsr0, cpsr
bicr0, r0, #0x1f
orrr0, r0, #0x10
msrcpsr_c, r0
;初始化 USER 模式堆栈
ldrsp, =0x40001000
movr0, #1
;USER SWI
swi5 ; open APP USER 这条语句由用户程序自己出发异常
;观察并记录对比指令执行前后的 PC LR CPSR SPSR SP的变化
addr1, r0, r0
stop
bstop
end
cpu在swi 5 后异常处理流程由硬件自己完成,这个过程如下图:
注1:如果同时返回到异常发生的位置,同时又能切换模式只能使用如下指令:
注2:进入swi异常,如何得到 swi 指令后面跟的那个参数?
所有的系统调用,都是依赖swi指令,操作系统提前给所有的系统调用编号
思路:swi异常发生的时候,会把该指令的下一条指令的地址给 svc模式的lr,
ldr r0, [lr,#-4] ; 获得SWI指令的机器码
bic r0, r0,#0xff000000 ; 通过机器码获得SWI NUMBER