9.4 SWI异常中断处理程序
在实时操作系统中,通常使用SWI异常中断为用户程序提供系统功能调用。
通常SWI异常中断处理程序分为两级:
第1级SWI异常中断处理程序为汇编程序,用于确定SWI指令中的24位的立即数;
第2级SWI异常中断处理程序具体实现SWI各个功能,可以是汇编,也可以是C程序。
第1级SWI异常中断处理程序
AREA LevelOneSWI ,CODE ,READONLY
EXPORT SWI_Handler
SWI_Handler
;保存用到的寄存器
STMFD SP!,{R0-R12,LR}
;计算SWI指令的地址,并把它读取到寄存器R0中
LDR R0,{LR,#-4}
;将SWI指令中的24位立即数存放到R0寄存器中
BIC R0,R0,#0XFF000000
;使用R0寄存器中的值,调用相应的SWI异常中断的第2级处理程序
;
;恢复使用到的寄存器,并返回
LDMFD SP!,{R0-R12,LR}
END
第2级SWI异常中断处理程序(使用汇编)
;判断R0寄存器中的立即数是否超过允许的最大值
CMP R0,#MAXSWI
LDRLS PC, [PC,R0,LSL #2]
B SWIOutOfRange
SWIJumpTable
DCD SWInum0
DCD SWInum1
;其他的DCD
;
;立即数为0对应的SWI中断处理程序
SWInum0
B EndofSWI
;
;其他的SWI中断处理程序
;
;结束SWI中断处理程序
EndofSWI
将第1级和第2级程序组成完整的SWI中断处理程序
AREA LevelOneSWI ,CODE ,READONLY
EXPORT SWI_Handler
SWI_Handler
;保存用到的寄存器
STMFD SP!,{R0-R12,LR}
;计算SWI指令的地址,并把它读取到寄存器R0中
LDR R0,{LR,#-4}
;将SWI指令中的24位立即数存放到R0寄存器中
BIC R0,R0,#0XFF000000
;使用R0寄存器中的值,调用相应的SWI异常中断的第2级处理程序
;
;判断R0寄存器中的立即数是否超过允许的最大值
CMP R0,#MAXSWI
LDRLS PC, [PC,R0,LSL #2]
B SWIOutOfRange
SWIJumpTable
DCD SWInum0
DCD SWInum1
;其他的DCD
;
;立即数为0对应的SWI中断处理程序
SWInum0
B EndofSWI
SWInum1
B EndofSWI
;
;其他的SWI中断处理程序
;
;结束SWI中断处理程序
EndofSWI
;恢复使用到的寄存器,并返回
LDMFD SP!,{R0-R12,LR}
END
第2级SWI异常中断处理程序(C程序)
void C_SWI_Handler (unsigned number )
{
switch (number)
{
case 0:
//SWI为0时执行的代码
break;
case 1:
//SWI为1时执行的代码
break;
//其他SWI号执行代码
default:
}
}
一个完整的中断处理程序为C程序的SWI异常中断处理程序
AREA LevelOneSWI ,CODE ,READONLY
EXPORT SWI_Handler
IMPORT C_SWI_Handler
SWI_Handler
;保存用到的寄存器
STMFD SP!,{R0-R12,LR}
;计算SWI指令的地址,并把它读取到寄存器R0中
LDR R0,{LR,#-4}
;将SWI指令中的24位立即数存放到R0寄存器中
BIC R0,R0,#0XFF000000
;使用R0寄存器中的值,调用相应的SWI异常中断的第2级处理程序
;
BL C_SWI_Handler
;恢复使用到的寄存器,并返回
LDMFD SP!,{R0-R12,LR}
END
9.4.2 SWI异常中断调用
1、在特权模式下调用SWI
;保存用到的寄存器,保存R14_svc
STMFD SP!,{R0-R3,R12,LR}
;保存SPSR_svc
MOV R1 , SP
MRS R0,SPSR
STMFD SP!,{R0}
;读取SWI指令
LDR R0,{LR,#-4}
;计算其中24位的立即数,并把其放入R0
BIC R0,R0,0XFF000000
;调用C_SWI_Handler
BL C_SWI_Handler
;恢复SPSR_svc
LDMFD SP!,{R0}
MSR SPSR_svc, R0
;恢复其他寄存器,包括寄存器LR_svc
LDMFD SP!,{R0-R3,R12,PC}^
2从应用程序中调用SWI
分两种情况:1是使用汇编指令调用;2是使用C程序调用
汇编调用:
MOV R0,#100 ;将参数放到寄存器中
SWI 0X0 ;调用的SWI功能号
C程序调用:
//头文件swi.h
__swi(0) int multiply_two(int, int);
__swi(1) int add_two(int, int);
__swi(2) int add_multiply_two(int, int, int, int);
struct four_results
{
int a;
int b;
int c;
int d;
};
__swi(3) __value_in_regs struct four_results
many_operations(int, int, int, int);
//主函数
#include <stdio.h>
#include "swi.h"
unsigned *swi_vec = (unsigned *)0x08;
extern void SWI_Handler(void);
//使用Install_Handler()注册SWI异常中断处理程序
unsigned Install_Handler (unsigned routine, unsigned *vector)
/* Updates contents of 'vector' to contain branch instruction */
/* to reach 'routine' from 'vector'. Function return value is */
/* original contents of 'vector'.*/
/* NB: 'Routine' must be within range of 32MB from 'vector'.*/
{ unsigned vec, oldvec;
vec = ((routine - (unsigned)vector - 0x8)>>2);
if ((vec & 0xFF000000))
{
/* diagnose the fault */
prinf ("Installation of Handler failed");
exit (1);
}
vec = 0xEA000000 | vec;
oldvec = *vector;
*vector = vec;
return (oldvec);
}
int main( void )
{
int result1, result2;
struct four_results res_3;
Install_Handler( (unsigned) SWI_Handler, swi_vec );
printf("result1 = multiply_two(2,4) = %d/n", result1 = multiply_two(2,4));
printf("result2 = multiply_two(3,6) = %d/n", result2 = multiply_two(3,6));
printf("add_two( result1, result2 ) = %d/n", add_two( result1, result2 ));
printf("add_multiply_two(2,4,3,6) = %d/n", add_multiply_two(2,4,3,6));
res_3 = many_operations( 12, 4, 3, 1 );
printf("res_3.a = %d/n", res_3.a );
printf("res_3.b = %d/n", res_3.b );
printf("res_3.c = %d/n", res_3.c );
printf("res_3.d = %d/n", res_3.d );
return 0;
}
//第1级SWI异常中断处理程序
AREA LevelOneSWI ,CODE ,READONLY
EXPORT SWI_Handler
IMPORT C_SWI_Handler
T_bit EQU 0X20
SWI_Handler
;保存用到的寄存器
STMFD SP!,{R0-R3,R12,LR}
;保存参数
MOV R1,SP
;保存SPSR
MRS R0,SPSR
STMFD SP!,{R0}
TST R0, #T_bit
;如果为thumb状态
LDRNEH R0,{LR,#-2}
BICNE R0,R0,0XFF00
;读取SWI指令
LDREQ R0,{LR,#-4}
;计算其中24位的立即数,并把其放入R0
BICEQ R0,R0,0XFF000000
;调用C_SWI_Handler
BL C_SWI_Handler
;恢复SPSR_svc
LDMFD SP!,{R0}
MSR SPSR_svc, R0
;恢复其他寄存器,包括寄存器LR_svc
LDMFD SP!,{R0-R3,R12,PC}^
END
;第2级SWI异常中断处理程序
void C_SWI_Handler (unsigned swi_num,int *regs)
{
switch (swi_num)
{
case 0:
regs[0]=regs[0]*regs[1];
break;
case 1:
regs[0]=regs[0]+regs[1];
break;
case 2:
regs[0]=(regs[0]*regs[1])+(regs[2]*regs[3]);
break;
case 3:
{
int w,x,y,z;
w=regs[0];
x=regs[1];
y=regs[2];
z=regs[3];
regs[0]=w+x+y+z;
regs[1]=w-x-y-z;
regs[2]=w*x*y*z;
regs[3]=(w+x)*(y-z);
}
break;
}
}
3应用程序动态调用SWI
#ifdef __thumb
/* Thumb Semihosting SWI */
#define SemiSWI 0xAB
#else
/* ARM Semihosting SWI */
#define SemiSWI 0x123456
#endif
/* Semihosting SWI to write a character */
__swi(SemiSWI) void Semihosting(unsigned op, char *c);
#define WriteC(c) Semihosting (0x3,c)
void write_a_character(int ch)
{
char tempch = ch;
WriteC( &tempch );
}