zzgezi的个人空间 https://bbs.21ic.com/?712331 [收藏] [复制] [RSS]

日志

ARM汇编的SWI指令软中断(转)

已有 809 次阅读2016-6-3 11:32 |系统分类:ARM

ARM汇编的SWI指令软中断

转:http://blog.chinaunix.net/u2/84172/showart_1794880.html
转:http://blog.csdn.net/nih1986517/archive/2008/10/16/3087286.aspx

从下面的一个ARM 汇编小程序要弄懂的以下三个问题:
1).在ARM状态转到THUNB状态和BX的应用
2).汇编的架构
3) SWI指令的使用
    AREA    ADDREG,CODE,READONLY
    ENTRY
MAIN
      ADR  r0,ThunbProg + 1  ;(为什么要加1呢?因为BX指令跳转到指定的地址执行程序   时,若(BX{cond}  Rm)Rm的位[0]为1,则跳转时自动将CPSR中的标志T置位即把目标 代码解释为Thunb代码)
      BX    r0
      CODE16
ThunbProg
      mov r2,#2
     mov r3,#3
     add r2,r2,r3
        ADR r0,ARMProg;ADM伪指令ADR伪指令将基于PC相对偏移的地址值或基于寄存器相对偏移的地址值读取到寄存器中。
例如:(查表)                     
    ADR    R0,DISP_TAB        ; 加载转换表地址
    LDRB   R1,[R0,R2]        ; 使用R2作为参数,进行查表
    …
DISP_TAB
    DCB   0xC0,0xF9,0xA4,0xB0,0x99, 0x92,0x82,0xF8

    BX  ro;转回ARM状态
    CODE32
ARMProg
     mov r4,#4
    mov r5,#5
    add  r4,r4,r5
       stop   
        
       LDR  r1,=0x20026
       SWI   0x123456
       END
SWI--软中断指令:
SWI指令用于产生软中断,从用户模式变换到管理模式,CPSR保存到管理模式的SPSR中.
 SWI{cond}      immed_24      ;immed_24为软中断号(服务类型)
使用SWI指令时,通常使用以下两种方法进行传递参数,SWI 异常中断处理程序就可以提供相关的服务,这两种方法均是用户软件协定.SWI异常中断处理程序要通过读取引起软中断的SWI指令,以取得24位立即数.
(1) 指令中的24位立即数指定了用户请求的服务类型,参数通过通用寄存器传递.(APCS)
 mov   r0,#34    ;设置子功能号位34
   SWI   12     ;调用12号软中断
(2) 指令中的24位立即数被忽略,用户请求的服务类型有寄存器RO的值决定,参数通过其他的通用寄存器传递.
 mov  r0,#12         ;调用12号软中断
 mov r1,#34         ;设置子功能号位34
 SWI  0
在SWI异常中断处理程序中,取出SWI立即数的步骤为:首先确定引起软中断的SWI指令是ARM指令还是Thunb指令,这可通过对SPSR访问得到;然后取得该SWI指令的地址,这可通过访问LR寄存器得到;接着读出指令,分解出立即数.如如下程序:
T_bit  EQU  0X20
SWI_Handler:0x00000008(SWI中断的入口地址应该有一个BL指令对应这一块)
    STMFD   SP!,{R0-R3,R12,LR};现场保护
    MOV     r1,sp;// 若SWI调用带参,将R1指向第一个参数
    MRS     R0,SPSR ;读取SPSR
    STMFD   SP!,{R0};保存SPSR              
    TST     R0,#T_bit                        
    LDRNEH  R0,[LR,#-2] ;若是Thunb指令,读取指令码(16位)
  BICNE   R0,#0XFF00;取得Thunb指令的8位立即数
  LDREQ   R0,[LR,#-4];若是ARM指令,读取指令码(32位)
  BICEQ   R0,#0XFF000000           ;取得ARM指令的24位立即数
    ;// r0 now contains SWI number
    ;// r1 now contains pointer to stacked registers

  BL      SWI_Exception_Function ;// 调用C编写的SWI处理函数(这个应该是下面的红色的部分)
    LDMFD   sp!,  {r0}  
    
MSR     spsr_cf,r0               ;// spsr出栈
    LDMFD   sp!,  {r0-r3, r12, pc}^   ;// 恢复现场   
软件中断SWI的实现
在需要软件中断处调用
__SWI  0xNum           ;Num为SWI中断处理模块的编号,见表SwiFunction
;软件中断
SWI_Exception_Function
        CMP     R0, #12 ;R0中的SWI编号是否大于最大值

/* 下面这句语句把 (LDRLO这条指令的地址+8+ R0*4) 的地址装载到PC寄存器,举例如果上面的 Num="1",也就是R0 = 1, 假设LDRLO这条指令的地址是0x00008000,那么根据ARM体系的3级流水线 PC寄存器里指向是下两条指令 于是PC = 0x00008008  也就是伪指令DCD TASK_SW 声明的标号TASK_SW  的地址,注意DCD TASK_SW 这条指令本身不是ARM能执行的指令,也不会占有地址,这条指令靠汇编器汇编成可执行代码,它的意义就是声明 TASK_SW的地址,  , [PC, R0, LSL #2] 这个寻址方式就是 PC + R0的值左移2位的值( 0x01<<2  => 0x04 ),这样PC的值就是0x0000800C, 即ENTER_CRITICAL的地址于是ARM执行该标号下的任务 */

        LDRLO   PC, [PC, R0, LSL #2]  
        MOVS    PC, LR;返回
SwiFunction
        DCD     TASK_SW                ;0
        DCD     ENTER_CRITICAL         ;1
        DCD     EXIT_CRITICAL            ;2
        DCD     ISRBegin                 ;3
        DCD     ChangeToSYSMode         ;4
        DCD     ChangeToUSRMode         ;5
        DCD     __OSStartHighRdy        ;6
        DCD     TaskIsARM               ;7
        DCD     TaskIsTHUMB             ;8
        DCD     OSISRNeedSwap           ;9
        DCD     GetOSFunctionAddr       ;10
        DCD     GetUsrFunctionAddr      ;11
TASK_SW
        MRS     R3, SPSR                        ;保存任务的CPSR
        MOV     R2, LR                          ;保存任务的PC
        MSR     CPSR_c, #(NoInt | SYS32Mode)    ;切换到系统模式
        STMFD   SP!, {R2}                       ;保存PC到堆栈
        STMFD   SP!, {R0-R12, LR}               ;保存R0-R12,LR到堆栈
                                                ;因为R0~R3没有保存有用数据,所以可以这样做
        B       OSIntCtxSw_0                    ;真正进行任务切换
ENTER_CRITICAL
                                                ;OsEnterSum++
        LDR     R1, =OsEnterSum
        LDRB    R2, [R1]
        ADD     R2, R2, #1
        STRB    R2, [R1]
                                                ;关中断
        MRS     R0, SPSR
        ORR     R0, R0, #NoInt
        MSR     SPSR_c, R0
        MOVS    PC, LR
================================================================================

备忘如下:

1、触及SWI软中断,就不能不说ATPCS过程调用,将后续日志记录;

2、SWI异常一旦触发,内核硬件完成:
   进入Supervisor模式;
   拷贝CPSR至SPSR_svc
   拷贝异常返回地址至LR_svc
   将0x00000008装入PC
   因此,当触发SWI软中断前内核处于Supervisor模式,SPSR_svc、LR_svc中的值将被破坏;

3、SWI指令编码中自带24bit数据作为软中断号(swi_num),因此可通过取SWI指令编码获取软中断号;LDR r0,[lr,#-4]就是这样;

4、SWI_Exception_Function函数一般采用C编码(也可汇编),采用C编码可直接套用switch根据swi_nun软中断号切换,SWI_Exception_Function函数的编制是灵活的,比如可以为带参或不带参函数;

5、一个SWI调用允许带1~4个字型参数和1~4个字型返回值,触发SWI调用时四个参数依次保存在R0~R3中,返回值也存于R0~R3内,这和ATPCS函数调用一致;

6、在C中声明一个典型的无参无返回值的SWI调用为:”__swi(0x00) void IRQEnable();“这样随时都可以使用”IRQEnable();“触发一个软中断(中断号0),其允许IRQ中断的功能必须在 SWI_Exception_Function软中断处理函数中实现;

8、最后须要注意的:SP堆栈指针时为间接寻址,”MOV r1,sp“指令将R1也变成一个指针,其存放的内容为R0在RAM中的地址而非R0值;

9、还有一点:SWI调用带参和SWI_Exception_Function函数的带参,是两回事,SWI调用带参是指的是调用多少号软中断,SWI_Exception_Function函数是函数(软中断运行的参数)

路过

鸡蛋

鲜花

握手

雷人

评论 (0 个评论)