【ARM】-SWI 和未定义指令异常中断处理程序的返回

2023-12-20 17:20

本文主要是介绍【ARM】-SWI 和未定义指令异常中断处理程序的返回,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

    • 处理流程
    • 示例
    • 代码实现
      • SWI
      • 未定义指令
    • 附录源码

处理流程

SWI 和未定义指令异常中断是由当前执行的指令自身产生的,当 SWI 和未定义指令异常中断产生时,程序计数器的 PC 的值还未更新,它指向当前指令后面第 2 条指令(对于 ARM 指令来说,它指向当前指令地址加 8 个字节的位置;对于 Thumb 指令来说,它指向当前指令地址加 4 个字节的位置)。
当 SWI 和未定义指令异常中断发生时,处理器将 PC-4 保存到异常模式下的 LR_mode 寄存器中。这时 LR_mode 中的值即为PC-4 ,即指向当前指令的第一条指令。因此返回操作直接将 LR_mode(指向当前指令的下一条指令) 的值赋给 PC 即可,可以通过下面的指令实现:

MOVS PC, LR   // 注意 S ,指定了 S 意味着同时将SPSR 拷贝到 CPSR

该指令将寄存器 LR 中的值,复制到程序计数器 PC 中,实现程序返回,同时将 SPSR_mode 寄存器内容复制到当前程序计数器 CPSR 中。
当异常中断处理程序中使用了数据栈时,可以通过下面的指令在异常中断处理程序时保存被中断程序的执行现场,在退出异常中断处理程序时恢复被中断程序的执行现场。异常中断处理程序中使用的数据栈由用户提供。

stmdb sp!, {r0-r12, lr}   // 保存现场 r0-r12 - reg_list
// user code
ldmia sp!, {r0-r12, pc}^  // 恢复现场 r0-r12 - reg_list

在上述指令中,reg_list 是异常中断处理程序中使用的寄存器列表。标识符 ^ 指示将 SPSR_mode 寄存器内容复制到 CPSR 寄存器中,该指令只能在特权模式下使用。

示例

在这里插入图片描述

  • 假设在 instruction+0 指令执行完成后发生 swi/undef 异常
  • 此时 PC 值 未更新还是指向 instruction+2
  • 进入 swi/undef 异常后,LR_mode = PC -4,所以此时 LR 指向 instruction+1
  • swi/undef 异常处理完成之后,程序需要返回到 instruction+1 处执行,所以将此时的 LR_mode 寄存器的值赋给 PC 即可

代码实现

SWI

异常处理程序

    .align 2.arm.weak SVC_Handler.type SVC_Handler, %function
SVC_Handler:/* 执行到这里之前:* 1. lr_svc 保存有被中断模式中的下一条即将执行的指令的地址* 2. SPSR_svc 保存有被中断模式的 CPSR* 3. CPSR 中的 M4-M0 被设置为 10011, 进入到 svc 模式* 4. 跳到 0x08 的地方执行程序*//* 保存现场 *//* 在 swi 异常处理函数中有可能会修改 r0-r12, 所以先保存 *//* lr 是异常处理完后的返回地址, 也要保存 */stmdb sp!, {r0-r12, lr}.if 0mov r4, lr /* LR 由硬件自动保存软中断指令下一条指令的地址 *//* 处理swi异常 */mrs r0, cpsrldr r1, =swi_stringbl printExceptionsub r0, r4, #4 /* LR 为硬件自动保存 SWI xxx 指令的下一条指令地址,LR – 4 就是 SWI 指令地址,由 SWI 指令编码知识可知,SWI 指令低 24 位保存有软中断号 */bl printSWIVal
.elseldr r4,[lr, #-4] /* LR 由硬件自动保存软中断指令下一条指令的地址,指令地址存放的是指令的操作码,将操作码取出,低 24 位置,即为软中断号 */bic r0, r4, #0xff000000 /* LR 为硬件自动保存 SWI xxx 指令的下一条指令地址,LR – 4 就是 SWI 指令地址,由 SWI 指令编码知识可知,SWI 指令低 24 位保存有软中断号 */push {r0}/* 处理swi异常 */mrs r0, cpsrldr r1, =swi_stringbl printExceptionpop {r0}bl printSWIVal
.endif/* 恢复现场 */ldmia sp!, {r0-r12, pc}^  /* ^ 会把 spsr 的值恢复到 cpsr 里 */swi_string:.string "swi exception"

触发 swi

swi_code:swi 0x123  /* 执行此命令, 触发SWI异常, 进入0x8执行 */

C 语言中将软中断号打印出来

void printSWIVal(unsigned int *pSWI)
{swi_flag = 1;printf("SWI val = 0x%x\r\n", *pSWI & ~0xff000000);
}

未定义指令

异常处理程序

    .align 2.arm.weak Undefined_Handler.type Undefined_Handler, %function
Undefined_Handler:/* 执行到这里之前:* 1. lr_und 保存有被中断模式中的下一条即将执行的指令的地址* 2. SPSR_und 保存有被中断模式的CPSR* 3. CPSR 中的 M4-M0 被设置为 11011, 进入到 und 模式* 4. 跳到 0x4 的地方执行程序*//* 在 und 异常处理函数中有可能会修改 r0-r12, 所以先保存 *//* lr 是异常处理完后的返回地址, 也要保存 */stmdb sp!, {r0-r12, lr}/* 保存现场 *//* 处理 und 异常 */mrs r0, cpsrldr r1, =und_stringbl printException/* 恢复现场 */ldmia sp!, {r0-r12, pc}^  /* ^ 会把 spsr 的值恢复到 cpsr 里 */und_string:.string "undefined instruction exception"

触发未定义指令异常

und_code:nop              /* for debug */.word 0xeeadc0de /* undefine instruction */nop              /* for debug */.word 0xFFFFFFFF /* undefine instruction */nop              /* for debug */ldr   r0, =mainbx    r0

C 语言中将异常字符串打印出来

void printException(unsigned int cpsr, char *str)
{excep_flag = 1;printf("Exception! cpsr is 0x%x\r\n", cpsr);
}

附录源码

.equ Mode_USR,        0x10
.equ Mode_FIQ,        0x11
.equ Mode_IRQ,        0x12
.equ Mode_SVC,        0x13
.equ Mode_MON,        0x16
.equ Mode_ABT,        0x17
.equ Mode_HYP,        0x1A
.equ Mode_UND,        0x1B
.equ Mode_SYS,        0x1F.equ Stack_size,      0x400
.equ Stack_Start,     0x80200000.equ Mode_USR_Stack,  Stack_Start + Stack_size
.equ Mode_FIQ_Stack,  Mode_USR_Stack + Stack_size
.equ Mode_IRQ_Stack,  Mode_FIQ_Stack + Stack_size
.equ Mode_SVC_Stack,  Mode_IRQ_Stack + Stack_size
.equ Mode_MON_Stack,  Mode_SVC_Stack + Stack_size
.equ Mode_ABT_Stack,  Mode_MON_Stack + Stack_size
.equ Mode_HYP_Stack,  Mode_ABT_Stack + Stack_size
.equ Mode_UND_Stack,  Mode_HYP_Stack + Stack_size
.equ Mode_SYS_Stack,  Mode_UND_Stack + Stack_size/* 定义一个 .isr_vector 段,链接脚本中定义相应的段来存放该段的数据 */.section .isr_vector, "a".arm.align 2.globl __isr_vector
__isr_vector:ldr     pc, =Reset_Handler           /* Reset                  */ldr     pc, =Undefined_Handler       /* Undefined instructions */ldr     pc, =SVC_Handler             /* Supervisor Call        */ldr     pc, =PrefAbort_Handler       /* Prefetch abort         */ldr     pc, =DataAbort_Handler       /* Data abort             */.word   0                            /* RESERVED               */ldr     pc, =IRQ_Handler             /* IRQ interrupt          */ldr     pc, =FIQ_Handler             /* FIQ interrupt          *//* 余下的指令的放在 .text 中,所以用 .text 指定段 */
/* Reset Handler */.text.arm.align 2.globl   Reset_Handler.weak    Reset_Handler.type    Reset_Handler, %function
Reset_Handler:cpsid i /* 关闭全局中断 *//* 关闭I,DCache和MMU* 采取读-改-写的方式。*/mrc p15, 0, r0, c1, c0, 0     /* 读取 CP15 的 C1 寄存器到 R0 中 */bic r0,  r0, #(0x1 << 12)     /* 清除 C1 寄存器的  bit12 位(I位),关闭 I Cache */bic r0,  r0, #(0x1 <<  2)     /* 清除 C1 寄存器的 bit2 (C位),关闭 D Cache */bic r0,  r0, #0x2             /* 清除 C1 寄存器的 bit1 (A位),关闭对齐 */bic r0,  r0, #(0x1 << 11)     /* 清除 C1 寄存器的 bit11 (Z位),关闭分支预测 */bic r0,  r0, #0x1             /* 清除 C1 寄存器的 bit0 (M位),关闭 MMU */mcr p15, 0, r0, c1, c0, 0     /* 将 r0 寄存器中的值写入到 CP15 的 C1 寄存器中 */#if 0/* 汇编版本设置中断向量表偏移 */ldr r0, =0x80000000dsbisbmcr p15, 0, r0, c12, c0, 0dsbisb
#endif/* 模式切换并设置 sp 地址 */cps     #Mode_FIQldr     sp, =Mode_FIQ_Stackcps     #Mode_IRQldr     sp, =Mode_IRQ_Stackcps     #Mode_SVCldr     sp, =Mode_SVC_Stackcps     #Mode_MONldr     sp, =Mode_MON_Stackcps     #Mode_ABTldr     sp, =Mode_ABT_Stackcps     #Mode_HYPldr     sp, =Mode_HYP_Stackcps     #Mode_UNDldr     sp, =Mode_UND_Stack/* sys mode and user have common sp register */cps     #Mode_SYSldr     sp, =Mode_SYS_Stackcpsie i /* 打开全局中断 *//* clear bss */ldr r1, =__bss_start__ldr r2, =__bss_end__mov    r0, #0
bss_loop:cmp     r1, r2itt     ltstrlt   r0, [r1], #4blt    bss_loop/* 使能IRQ中断 */mrs r0, cpsr        /* 读取cpsr寄存器值到r0中 */bic r0, r0, #0x80   /* 将r0寄存器中bit7清零,也就是CPSR中的I位清零,表示允许IRQ中断 */msr cpsr, r0        /* 将r0重新写入到cpsr中 */swi_code:swi 0x123  /* 执行此命令, 触发SWI异常, 进入0x8执行 */und_code:nop              /* for debug */.word 0xeeadc0de /* undefine instruction */nop              /* for debug */.word 0xFFFFFFFF /* undefine instruction */nop              /* for debug */ldr   r0, =mainbx    r0.align 2.arm.weak Undefined_Handler.type Undefined_Handler, %function
Undefined_Handler:/* 执行到这里之前:* 1. lr_und 保存有被中断模式中的下一条即将执行的指令的地址* 2. SPSR_und 保存有被中断模式的CPSR* 3. CPSR 中的 M4-M0 被设置为 11011, 进入到 und 模式* 4. 跳到 0x4 的地方执行程序*//* 在 und 异常处理函数中有可能会修改 r0-r12, 所以先保存 *//* lr 是异常处理完后的返回地址, 也要保存 */stmdb sp!, {r0-r12, lr}/* 保存现场 *//* 处理 und 异常 */mrs r0, cpsrldr r1, =und_stringbl printException/* 恢复现场 */ldmia sp!, {r0-r12, pc}^  /* ^ 会把 spsr 的值恢复到 cpsr 里 */und_string:.string "undefined instruction exception".align 2.arm.weak SVC_Handler.type SVC_Handler, %function
SVC_Handler:/* 执行到这里之前:* 1. lr_svc 保存有被中断模式中的下一条即将执行的指令的地址* 2. SPSR_svc 保存有被中断模式的 CPSR* 3. CPSR 中的 M4-M0 被设置为 10011, 进入到 svc 模式* 4. 跳到 0x08 的地方执行程序*//* 保存现场 *//* 在 swi 异常处理函数中有可能会修改 r0-r12, 所以先保存 *//* lr 是异常处理完后的返回地址, 也要保存 */stmdb sp!, {r0-r12, lr}.if 0mov r4, lr /* LR 由硬件自动保存软中断指令下一条指令的地址 *//* 处理swi异常 */mrs r0, cpsrldr r1, =swi_stringbl printExceptionsub r0, r4, #4 /* LR 为硬件自动保存 SWI xxx 指令的下一条指令地址,LR – 4 就是 SWI 指令地址,由 SWI 指令编码知识可知,SWI 指令低 24 位保存有软中断号 */bl printSWIVal
.elseldr r4,[lr, #-4] /* LR 由硬件自动保存软中断指令下一条指令的地址,指令地址存放的是指令的操作码,将操作码取出,低 24 位置,即为软中断号 */bic r0, r4, #0xff000000 /* LR 为硬件自动保存 SWI xxx 指令的下一条指令地址,LR – 4 就是 SWI 指令地址,由 SWI 指令编码知识可知,SWI 指令低 24 位保存有软中断号 */push {r0}/* 处理swi异常 */mrs r0, cpsrldr r1, =swi_stringbl printExceptionpop {r0}bl printSWIVal
.endif/* 恢复现场 */ldmia sp!, {r0-r12, pc}^  /* ^ 会把 spsr 的值恢复到 cpsr 里 */swi_string:.string "swi exception".align 2.arm.weak PrefAbort_Handler.type PrefAbort_Handler, %function
PrefAbort_Handler:ldr r0, =PrefAbort_Handlerbx r0.align 2.arm.weak DataAbort_Handler.type DataAbort_Handler, %function
DataAbort_Handler:ldr r0, =DataAbort_Handlerbx r0.align 2.arm.weak IRQ_Handler.type IRQ_Handler, %functionIRQ_Handler:push {lr}                   /* 保存lr地址 */push {r0-r3, r12}           /* 保存r0-r3,r12寄存器 */mrs r0, spsr                /* 读取spsr寄存器 */push {r0}                   /* 保存spsr寄存器 */.if 0 /* it always return 0, i don't know why */mrc p15, 4, r1, c15, c0, 0 /* 从CP15的C0寄存器内的值到R1寄存器中* 参考文档ARM Cortex-A(armV7)编程手册V4.0.pdf P49* Cortex-A7 Technical ReferenceManua.pdf P68 P138*/
.elseldr r1, =0x00a00000
.endifadd r1, r1, #0X2000         /* GIC基地址加0X2000,也就是GIC的CPU接口端基地址 */ldr r0, [r1, #0XC]          /* GIC的CPU接口端基地址加0X0C就是GICC_IAR寄存器,* GICC_IAR寄存器保存这当前发生中断的中断号,我们要根据* 这个中断号来绝对调用哪个中断服务函数*/push {r0, r1}               /* 保存r0,r1 */cps #0x13                   /* 进入SVC模式,允许其他中断再次进去 */push {lr}                   /* 保存SVC模式的lr寄存器 */ldr r2, =system_irqhandler	/* 加载C语言中断处理函数到r2寄存器中*/blx r2                      /* 运行C语言中断处理函数,带有一个参数,保存在R0寄存器中 */pop {lr}                    /* 执行完C语言中断服务函数,lr出栈 */cps #0x12                   /* 进入IRQ模式 */pop {r0, r1}str r0, [r1, #0X10]         /* 中断执行完成,写EOIR */pop {r0}msr spsr_cxsf, r0           /* 恢复spsr */pop {r0-r3, r12}            /* r0-r3,r12出栈 */pop {lr}                    /* lr出栈 */subs pc, lr, #4             /* 将lr-4赋给pc */.align 2.arm.weak FIQ_Handler.type FIQ_Handler, %function
FIQ_Handler:ldr r0, =FIQ_Handlerbx r0.end

这篇关于【ARM】-SWI 和未定义指令异常中断处理程序的返回的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/516828

相关文章

这15个Vue指令,让你的项目开发爽到爆

1. V-Hotkey 仓库地址: github.com/Dafrok/v-ho… Demo: 戳这里 https://dafrok.github.io/v-hotkey 安装: npm install --save v-hotkey 这个指令可以给组件绑定一个或多个快捷键。你想要通过按下 Escape 键后隐藏某个组件,按住 Control 和回车键再显示它吗?小菜一碟: <template

工作常用指令与快捷键

Git提交代码 git fetch  git add .  git commit -m “desc”  git pull  git push Git查看当前分支 git symbolic-ref --short -q HEAD Git创建新的分支并切换 git checkout -b XXXXXXXXXXXXXX git push origin XXXXXXXXXXXXXX

Android中如何实现adb向应用发送特定指令并接收返回

1 ADB发送命令给应用 1.1 发送自定义广播给系统或应用 adb shell am broadcast 是 Android Debug Bridge (ADB) 中用于向 Android 系统发送广播的命令。通过这个命令,开发者可以发送自定义广播给系统或应用,触发应用中的广播接收器(BroadcastReceiver)。广播机制是 Android 的一种组件通信方式,应用可以监听广播来执行

struts2中的json返回指定的多个参数

要返回指定的多个参数,就必须在struts.xml中的配置如下: <action name="goodsType_*" class="goodsTypeAction" method="{1}"> <!-- 查询商品类别信息==分页 --> <result type="json" name="goodsType_findPgae"> <!--在这一行进行指定,其中lis是一个List集合,但

mysql中导入txt文件数据的操作指令

1 表tt的格式:    CREATE TABLE `tt` (   `ind` int NOT NULL auto_increment,   `name` char(100) default NULL,   PRIMARY KEY  (`ind`)  )   2 文件d.txt的内容示例:  1,a  2,b  3,c

可选择的反思指令微调

论文:https://arxiv.org/pdf/2402.10110代码:GitHub - tianyi-lab/Reflection_Tuning: [ACL'24] Selective Reflection-Tuning: Student-Selected Data Recycling for LLM Instruction-Tuning机构:马里兰大学, Adobe Research领

bash: arm-linux-gcc: No such file or directory

ubuntu出故障重装了系统,一直用着的gcc使用不了,提示bash: arm-linux-gcc: No such file or directorywhich找到的命令所在的目录 在google上翻了一阵发现此类问题的帖子不多,后来在Freescale的的LTIB环境配置文档中发现有这么一段:     # Packages required for 64-bit Ubuntu

编译linux内核出现 arm-eabi-gcc: error: : No such file or directory

external/e2fsprogs/lib/ext2fs/tdb.c:673:29: warning: comparison between : In function 'max2165_set_params': -。。。。。。。。。。。。。。。。。。 。。。。。。。。。。。。。 。。。。。。。。 host asm: libdvm <= dalvik/vm/mterp/out/Inte

驱动安装注册表指令

HKCR: HKEY_CLASSES_ROOT HKCU: HKEY_CURRENT_USER HKLM: HKEY_LOCAL_MACHINE HKU: HEKY_USER HER: 相对根键

4G模块、WIFI模块、NBIOT模块通过AT指令连接华为云物联网服务器(MQTT协议)

MQTT协议概述 MQTT(Message Queuing Telemetry Transport)是一种轻量级的消息传输协议,它被设计用来提供一对多的消息分发和应用之间的通讯,尤其适用于远程位置的设备和高延迟或低带宽的网络。MQTT协议基于客户端-服务器架构,客户端可以订阅任意数量的主题,并可以发布消息到这些主题。服务器(通常称为MQTT Broker)则负责接受来自客户端的连接请求,并转发消