ARM体系结构与编程学习(十二)

时间:2021-03-19 19:08:07

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 );
}