标题:
ARM 软件中断指令SWI讲解(2)
[打印本页]
作者:
look_w
时间:
2017-9-24 18:11
标题:
ARM 软件中断指令SWI讲解(2)
二、软中断处理
CPU
执行到
swi xxx
执行后,产生软件中断,由异常处理部分知识可知,软中断产生后
CPU
将强制将
PC
的值置为
异常向量表地址
0x08
,在异常向量表
0x08
处安放跳转指令
b HandleSWI
,这样
CPU
就跳往我们自己定义的
HandleSWI
处执行。
1--
保护现场
软中断处理中通过
STMFD SP!, {R0-R12, LR}
要保存程序执行现场,将
R0~R12
通用寄存器数据保存在管理模式下
SP
栈内,
LR
由硬件自动保存软中断指令下一条指令的地址(后面利用
LR
的地址取得
SWI
指令编码),该寄存器值也保存在
SP
栈内,将来处理完毕之后返回;
2--
获取
SWI
指令编码
由
SWI
指令编码知识可知,
SWI
指令低
24
位保存有软中断号
,通过
LDR R4, [LR, #-4]
指令,取得
SWI
指令编码(
LR
为硬件自动保存
SWI xxx
指令的下一条指令地址,
LR – 4
就是
SWI
指令地址),
将其保存在
R4
寄存器中。通过
BIC R4, R4, #0xFF000000
指令将
SWI
指令高
8
位清除掉,只保留低
24
位立即数,取得SWI指令编码;
3--
根据
SWI
指令做出相应操作
根据
24
位立即数中的
软中断号
判断用户程序的请求操作。如果
24
位立即数为
1
,表示
led_on
系统调用产生的软中断,则在管理模式下调用对应的亮灯操作
do_led_on
。如果
24
位立即数为
2
,表示
led_off
系统调用产生的软中断,则调用灭灯操作
do_led_on
,根据
ATPCS
调用规则,
R0~R3
做为参数传递寄存器,在软中断处理中没有使用这
4
个寄存器,而是
使用
R4
作为操作寄存器的
。
4--
返回并恢复现场
执行完系统调用操作之后,返回到
swi_return
(在调用对应系统操作时,通过
LDREQ LR, =swi_return
设置了返回地址),执行返回处理,通过
LDMIA SP!, {R0-R12, PC}^
指令将用户寄存器数据恢复到
R0~R12
,将进入软中断处理时保存的返回地址
LR
的值恢复给
PC
,实现程序返回,
同时还恢复了状态寄存器。切换回用户模式下程序中继续执行。
; 异常向量表开始
; 0x00: 复位Reset异常
b Reset
; 0x04: 未定义异常(未处理)
HandleUndef
b HandleUndef
; 0x08: 软件中断异常,跳往软件中断处理函数HandleSWI
b HandleSWI
… …
; 省略其它异常向量和对应处理
… …
;***********************************************************************
; 软中断处理
;***********************************************************************
IMPORT do_led_on
IMPORT do_led_off
HandleSWI
STMFD SP!, {R0-R12, LR} ; 保存程序执行现场
LDR R4, [LR, #-4] ; LR - 4 为指令" swi xxx" 的地址,低24位是软件中断号
BIC R4, R4, #0xFF000000 ; 取得ARM指令24位立即数
CMP R4, #1 ; 判断24位立即数,如果为1,调用do_led_on系统调用
LDREQ LR, =swi_return ; 软中断处理返回地址
LDREQ PC, = do_led_on ; 软中断号1对应系统调用处理
CMP R4, #2 ; 判断24位立即数,如果为2,调用do_led_off系统调用
LDREQ LR, =swi_return ; 软中断处理返回地址
LDREQ PC, = do_led_off ; 软中断号2对应系统调用处理
MOVNE R0, #-1 ; 没有该软中断号对应函数,出错返回-1
swi_return
LDMIA SP!, {R0-R12, PC}^ ; 中断返回, ^表示将spsr的值复制到cpsr
其实讲到这,会产生一个疑问,什么时候需要我们从用户模式切换到管理模式?我们应该记得系统调用,就是用户态向内核态的切换。
三、系统调用
操作系统的主要功能是为应用程序的运行创建良好的环境,保障每个程序都可以最大化利用硬件资源,防止非法程序破坏其它应用程序执行环境,为了达到这个目的,
操作系统会将硬件的操作权限交给内核来管理,用户程序不能随意使用硬件,
使用硬件(对硬件寄存器进行读写)时要先向操作系统发出请求,操作系统内核帮助用户程序实现其操作,也就是说用户程序不会直接操作硬件,而是提供给用户程序一些具备预定功能的内核函数,通过一组称为
系统调用的(
system call)
的接口呈现给用户,系统调用把应用程序的请求传给内核,调用相应的内核函数完成所需的处理,将处理结果返回给应用程序。
这好比我们去银行取款,用户自己的银行帐户不可能随意操作,必须要有一个安全的操作流程和规范,银行里的布局通常被分成两部分,中间用透明玻璃分隔开,只留一个小窗口,面向用户的是用户服务区,工作人员所在区域为内部业务操作区,取款时,将银行卡或存折通过小窗口交给业务员,并且告诉他要取多少钱,具体取钱的操作你是不会直接接触的,业务员会将银行帐户里减掉取款金额,将现金给你。上述操作流程可以很好保护银行系统,银行系统的操作全部由业务员来实现,用户只能向业务员提出自己的服务请求。银行里的小窗口就类似与操作系统的系统调用接口,是将用户请求传递给内核的接口。
操作系统里将用户程序运行在用户模式下,并且为其分配可以使用内存空间,其它内存空间不能访问,内核态运行在特权模式下,对系统所有硬件进行统一管理和控制。从前面所学知识可以了解到,
用户模式下没有权限进行模式切换
,这也就意味着用户程序不可能直接通过切换模式去访问硬件寄存器,如果用户程序试图访问没有权限的硬件,会产生异常。这样用户程序被限制起来,如果用户程序想要使用硬件时怎么办呢?用户程序使用硬件时,必须调用操作系统提供的
API
接口才可以,而操作系统
API
接口通过软件中断方式切换到管理模式下,实现从用户模式下进入特权模式。
At91rm9200
处理器对应的
linux2.4.19
内核系统调用对应的软中断定义如下:
#if defined(__thumb__) //thumb模式
#define __syscall(name) \
"push {r7}\n\t" \
"mov r7, #" __sys1(__NR_##name) "\n\t" \
"swi 0\n\t" \
"pop {r7}"
#else //arm模式
#define __syscall(name) "swi\t" __sys1(__NR_##name) "\n\t"
#endif
#define __sys2(x) #x
#define __sys1(x) __sys2(x)
#define __NR_SYSCALL_BASE 0x900000 //此为OS_NUMBER << 20运算值
#define __NR_open (__NR_SYSCALL_BASE+ 5) //0x900005
欢迎光临 电子技术论坛_中国专业的电子工程师学习交流社区-中电网技术论坛 (http://bbs.eccn.com/)
Powered by Discuz! 7.0.0