×
单片机 > 单片机程序设计 > 详情

ARM 软中断指令SWI

发布时间:2024-05-05 发布时间:
|

前面我们学习ARM工作模式中,处理器模式切换可以通过软件控制进行切换,即修改CPSR模式位,但这是在特权模式下,当我们处于用户模式下,是没有权限实现模式转换的。若想实现模式切换,只能由另一种方法来实现,即通过外部中断或是异常处理过程进行切换。于是ARM指令集中提供了两条产生异常的指令,通过这两条指令可以用软件的方法实现异常,其中一个就是中断指令SWI。

一、软件中断

软中断是利用硬件中断的概念,用软件方式进行模拟,实现从用户模式切换到特权模式并执行特权程序的机制。


硬件中断是由电平的物理特性决定,在电平变化时引发中断操作,而软中断是通过一条具体指令SWI,引发中断操作,也就是说用户程序里可以通过写入SWI指令来切换到特权模式,当CPU执行到SWI指令时会从用户模式切换到管理模式下,执行软件中断处理。由于SWI指令由操作系统提供的API封装起来,并且软件中断处理程序也是操作系统编写者提前写好的,因此用户程序调用API时就是将操作权限交给了操作系统,所以用户程序还是不能随意访问硬件。

软件中断指令(SoftwareInterrupt,SWI)用于产生软中断,实现从用户模式变换到管理模式,CPSR保存到管理模式的SPSR中,执行转移到SWI向量。在其他模式下也可以使用SWI指令,处理器同样切换到管理模式。


1、SWI指令格式如下:

SWI{cond}immed_24

其中:

immed_2424位立即数,值为从0――16777215之间的整数。


SWI指令后面的24立即数是干什么用的呢?用户程序通过SWI指令切换到特权模式,进入软中断处理程序,但是软中断处理程序不知道用户程序到底想要做什么?SWI指令后面的24位用来做用户程序和软中断处理程序之间的接头暗号。通过该软中断立即数来区分用户不同操作,执行不同内核函数。如果用户程序调用系统调用时传递参数,根据ATPCSC语言与汇编混合编程规则将参数放入R0~R4即可。

2、指令举例

使用SWI指令时,通常使用以下两种方法进行参数传递,SWI异常处理程序可以提供相关的服务,这两种方法均是用户软件协定。SWI异常中断处理程序要通过读取引起软件中断的SWI指令,以取得24为立即数。


1)、指令中24位的立即数指定了用户请求的服务类型,中断服务的参数通过通用寄存器传递。

如下面这个程序产生一个中断号位12的软中断:

MOVR0,#34;设置功能号为34

SWI12;产生软中断,中断号为12


2)、指令中的24位立即数被忽略,用户请求的服务类型有寄存器R0的值决定,参数通过其他的通用寄存器传递。


如下面的例子通过R0传递中断号,R1传递中断的子功能号:

MOVR0,#12;设置12号软中断

MOVR1,#34;设置功能号为34

SWI 0


下面的例子通过系统调用函数intled_on(intled_no)实现点亮第led_no个LED灯,由于C语言里没有SWI指令对应的语句,因此这儿要用到C语言与汇编混合编程,led_on函数里将参数led_no的值传递给R0,通过软中断SWI指令切换到软中断管理模式,同时R0软中断方式点亮LED灯,用户通过SWI#1指令可以点灯,具体点亮哪个灯,通过R0保存参数传递,如果亮灯成功返回对应LED号。


#define __led_on_swi_no 1 // 软中断号1,调用管理模式下的do_led_on函数
int led_on(int led_no){

int ret; // 返回值
__asm{ // 由于C程序中没有SWI对应表达式,所以使用混合编程
mov r0, led_no // 根据ATPCS规则,r0存放第一个参数
swi __led_on_swi_no // 产生SWI软中断,中断号为__led_on_swi_no

mov ret, r0 // 软中断处理结束,取得中断处理返回值,传递给ret变量
}

return ret; // 将ret返回给调用led_on的语句
}


二、软中断处理

CPU执行到swixxx执行后,产生软件中断,由异常处理部分知识可知,软中断产生后CPU将强制将PC的值置为异常向量表地址0x08,在异常向量表0x08处安放跳转指令bHandleSWI,这样CPU就跳往我们自己定义的HandleSWI处执行。


1--保护现场

软中断处理中通过STMFDSP!,{R0-R12,LR}要保存程序执行现场,将R0~R12通用寄存器数据保存在管理模式下SP栈内,LR由硬件自动保存软中断指令下一条指令的地址(后面利用LR的地址取得SWI指令编码),该寄存器值也保存在SP栈内,将来处理完毕之后返回;


2--获取SWI指令编码

由SWI指令编码知识可知,SWI指令低24位保存有软中断号,通过LDRR4,[LR,#-4]指令,取得SWI指令编码(LR为硬件自动保存SWIxxx指令的下一条指令地址,LR–4就是SWI指令地址),将其保存在R4寄存器中。通过BICR4,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(在调用对应系统操作时,通过LDREQLR,=swi_return设置了返回地址),执行返回处理,通过LDMIASP!,{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

[1] [2] [3]
ARM软中断指令SWI

『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
单片机中高阻态的实质及意义