【理解ARM架构】异常处理

🐱作者:一只大喵咪1201
🐱专栏:《理解ARM架构》
🔥格言:你只管努力,剩下的交给时间!
图

目录

  • ⚡ARM系统中异常与中断处理流程
    • 🍢向量表
    • 🍢保存现场
    • 🍢恢复现场
  • ⚡异常处理
    • 🍢未定义指令异常
    • 🍢SVC异常
    • 🍢SysTick异常
  • ⚡总结

⚡ARM系统中异常与中断处理流程

图
如上图所示arm系统中异常与中断的硬件框图,左侧的按键,定时器其他等等被叫做中断源,它们发出的中断汇聚到中断控制器,也就是NVIC,再由中断控制器将中断发信号给CPU,告诉它发生了那些紧急情况,CPU会中断当前正在执行的代码去处理中断。

除了中断,异常也可以打断CPU的运行,如上图所示右侧框中:

  • 指令不对
  • 数据访问有问题
  • reset信号

等等情况,这些都可以打断CPU运行,这些都属于异常

  • 中断属于一种异常。

ARM系统中处理异常与中断的重点在于保存现场以及恢复现场,中断的使用过程如下:

  • 初始化

    • 设置中断源,让它可以产生中断
    • 设置中断控制器(可以屏蔽某个中断,优先级)
    • 设置CPU总开关,使能中断
  • 执行其他程序:正常程序

  • 产生中断,举例:按下按键—>中断控制器—>CPU

  • cpu每执行完一条指令都会检查有无中断/异常产生

  • 发现有中断/异常产生,开始处理:

    • 保存现场
    • 分辨异常/中断,调用对于异常/中断的处理函数
    • 恢复现场

🍢向量表

不同的芯片,不同的架构,在这方面的处理稍有差别。先来认识一下向量表。向量,在数学定义里是有方向的量,在程序里可以认为向量就是一个数组,里面有多个项,在ARM架构里,对于异常/中断,它们的处理入口函数会整齐地排放在向量表中。

tu
如上图所示,我们在使用CubeMX或者固件库创建好的工程中,在start.s中存在一个向量表__Vectors,其中上面的蓝色框中是处理异常的入口地址,下面的蓝色框中是处理中断的入口地址。

板子上电以后,从__Vectors处的第一个DCD处执行,这里是设置栈顶的,__initial_sp就是栈顶的地址。然后再执行第二个DCD处的Reset_Handler,我们的main函数等就放在这里。

cortex M3/M4:

M3/M4的向量表中,放置的是具体异常/中断的处理函数的地址。比如发生Reset异常时,CPU就会从向量表里找到第1项,得到Reset_Handler函数的地址,跳转去执行。

比如发生EXTI Line 0中断时,CPU就会从向量表里找到第22项,得到EXTI0_IRQHandler函数的地址,跳转去执行。

cortex A7:

tu

如上图所示A7的向量表中,放置的是某类异常的跳转指令。比如发生Reset异常时,CPU就会从向量表里找到第0项,得到b reset指令,执行后就跳转到reset函数。

比如发生任何的中断时,CPU就会从向量表里找到第6项,得到ldr pc, _irq指令,执行后就跳转到_irq函数。

🍢保存现场

在跳转到向量表执行入口函数之前,先要保存现场,也就是将CPU中寄存器中的值先保存下来。

为什么要保存现场?

tu
如上图所示代码示意图,任何程序,最终都会转换为机器码,上述C代码可以转换为右边的汇编指令。

对于这4条指令,它们可能随时被异常打断,怎么保证异常处理完后,被打断的程序还能正确运行?

  • 这4条指令涉及R0、R1寄存器,程序被打断、恢复运行时,R0、R1要保持不变。
  • 执行完第3条指令时,比较结果保存在程序状态寄存器里,程序被打断、恢复运行时,程序状态寄存器要保持不变。
  • 这4条指令,读取a、b内存,程序被打断、恢复运行时,a、b内存要保持不变

内存保持不变,这很容易实现,程序不越界就可以。所以,关键在于R0、R1、程序状态寄存器要保持不变(当然不止这些寄存器),因为这些寄存器在中断中也有可能用到,此时就会改变原本的值。

图
如上图所示,在ARM处理器中有这些寄存器,而且在ARM中有个ATPCS规则(ARM-THUMB procedure call standard(ARM-Thumb过程调用标准)约定R0-R15寄存器的用途。

图
如上图所示,R0-R3用在调用者和被调用者之间传参数,R4~R11在被调用者(函数)内使用,R12~R15是特殊用途的寄存器,还有一个程序状态寄存器,对于M3/M4它被称为XPSR

  • 保存现场就是在保存R0~R15以及XPSR寄存器。

在发生异常/中断后,在处理异常/中断前,需要保存现场,难道需要保存所有这些寄存器吗?不是的。

  • 这些这些寄存器被拆分成2部分:调用者保存的寄存器(R0-R3,R12,LR,PSR)被调用者保存的寄存器(R4-R11)

怎么理解呢?(R0-R3,R12,LR,PSR)这些寄存器是用来传参或者保存返回地址的,调用者主动将这些寄存器给被调用者直接使用,站在被调用者的角度,它认为它得到了允许,既然是你让我用的,那我就随便用了。

站在调用者的角度,就有责任来保证自己不受影响,所以在给被调用者使用之前,需要将这些寄存器的值保存起来,调用结束以后方便将值恢复到这些寄存器中。

(R4-R11)这些寄存器被调用者在使用的时候,并没有得到调用者的允许,所以它在使用之前有责任将这些寄存器原本的值保存起来,在使用完毕后再将值恢复到寄存器中,以防影响到调用者。

  • 所以在处理中断/异常之前,要将R0~R3,R12,LR,XPSR寄存器中的值保存。

保存现场时寄存器中的值保存到哪里呢?

tu
如上图所示,在保存现场时,将调用者要保存的寄存器挨个压栈,高编号寄存器值放在高地址。

  • 在M3/M4中,现场保存是由硬件完成的,我们写程序的不用关心。

  • 异常/中断类型的分辨也是由硬件完成的。

在保存完现场以后,就直接跳转到向量表中对于的处理入口执行对应的处理函数。


🍢恢复现场

图
如上图所示现场保护时栈的情况,在处理函数执行完毕后,它返回LR所指示的位置(普通调用是这样),难道把LR设置为被中断时程序的地址就行了吗?

如果只是返回LR所指示的地方,也就是执行MOV PC, LR,此时程序直接就返回到产生中断/异常的位置开始执行代码了,硬件帮我们保存在栈里的寄存器,怎么恢复?

所以M3/M4在调用异常处理函数前,把LR设置为一个特殊的值,该特殊的值被称为EXC_RETURN

图
如上图所示,该特殊值是一个32位的地址,它具有特别的意义,以后会具体讲解它的意义。

当处理函数执行完毕以后,会执行MOV PC, LR,当PC寄存器的值等于EXC_RETURN时,会触发异常返回机制,简单地说:会从栈里恢复R0-R3,R12,LR,PC,PSR等寄存器。

然后再把栈中红色框中的返回地址赋值给PC寄存器,让程序从产生中断/异常位置继续执行。

  • 恢复现场是由软件触发,硬件恢复的。

所谓软件触发就是我们在处理函数中执行return函数,此时就会触发异常/中断返回机制,由硬件将栈中保存的值恢复到寄存器中。

⚡异常处理

在了解了异常/中断的处理流程以后,来写代码感受一下。继续使用前面的代码。

图
如上图,修改散列文件,让代码段的加载地址和链接地址相等,不再需要代码段重定位,让代码在Flash上运行。

🍢未定义指令异常

所谓未定义指令就是写一条CPU不认识的指令,此时就会出异常,硬件就会让程序跳转到向量表中对应的处理入口,去执行处理函数。

tu

如上图,在向量表中只保留HardFault_HandlerUsageFault_Handler两个异常处理入口,并且声明这两个函数。

tu
如上图,定义HardFault_HandlerUsageFault_Handler两个异常处理函数,在函数里打印一句话,然后陷入死循环。

tu
如上图所示,声明串口初始化函数,然后在执行未定义指令之前初始化串口,否则就无法看到打印的东西了,因为串口还没有初始化就发生了异常。

然后会执行DCD 0XFFFFFFFF未定义指令,此时就会产生异常,这属于一个使用异常,所以应该会去UsageFault_Handler处执行处理函数。

tu
如上图,但是此时从串口助手上看到的是HardFault_Handler,说明执行的是HardFault_Handler处理函数,而不是UsageFault_Handler函数,这是为什么呢?

tu
如上图所示,未定义指令属于"处理器操作相关的错误",如果没有使能Usage Fault",发就会触发Hard Fault,所以上面执行的就是HardFault_Handler处理函数。

为了执行HardFault_Handler处理函数,需要将Usage Fault使能,在M3/M4内核中,有一个用于异常和中断控制的SCB寄存器:

tu
如上图所示SCB寄存器部分位,详细内容在ARM Cortex-M3与Cortex-M4权威指南这本书中有详细接收,该寄存器的基地址是0xE000ED00

TU
如上图,为了访问SCB寄存器方便,将该寄存器使用结构体描述出来。
图
如上图,定义一个函数UsageFaultInit,在里面将SCB寄存器的第18位,也就是SHCSR位置一,在执行未定义指令之前调用该函数,此时就使能了UsageFault

图
如上图,在用法错误异常处理函数UsageFault_Handler中,只打印异常名,不陷入死循环。

图
如上图,此时就会疯狂打印UsageFault_Handler,说明不停的在执行UsageFault_Handler处理函数。为什么会不停执行呢?执行一遍不就可以了吗?

  • 用法错误异常仍然存在,虽然执行了UsageFault_Handler处理函数,但是没有将该异常清除。

tu
如上图,在UsageFault_Handler函数中,先打印出保护现场时,调用者保护的R0~R3,R12,LR,返回地址,XPSR,这七项,它们存在栈中。

图
如上图所示,由于要在UsageFault_Handler函数中打印栈中存放的寄存器值,所以在调用该函数的时候要进行传参,而向量表中存放的入口处理函数指针是没有形参的。

所以重新定义一个入口处理函数UsageFault_Handler_asm,如上图红色框,将该函数放入到向量表中,当发生UsageFault的时候,就会跳转去执行该函数。

在该函数中,通过R0寄存器传参栈顶指针SP,然后再调用我们之前实现的UsageFault_Handler

  • 调用UsageFault_Handler函数的时候不能使用BL指令,因为这是异常处理函数,不能直接返回到LR中的地址处,需要触发恢复现场机制。
  • 所以只能使用B来调用UsageFault_Handler,现场恢复机制不在这里触发。

tu

如上图所示,此时串口仍然疯狂输出,我们截取打印内容中栈里的值,发现在调用UsageFault_Handler处理函数之前的现场保存时,存放到栈中的返回地址是0x08000068,程序执行完处理函数后会返回到这个地址继续执行。

tu
如上图,打开反汇编文件,查看0x08000068地址处的内容,发现该地址处就是那条未定义指令。

也就是说,未定义指令引起异常后调用处理函数,处理完毕以后又回到了异常指令这里,再次执行,再次引发异常,如此反复导致疯狂输出。

tu
如上图所示,在UsageFault_Handler函数中,设置栈中的返回地址,让其指向下一条指令,也就是在调用异常处理函数结束以后,硬件进行现场恢复完成,然后让PC指向未定义指令的下一条指令。

tu
如上图所示,此时程序就能正常执行了。

🍢SVC异常

在ARM指令中,有一条指令:

SVC #VAL

其中,VAL是个立即数,代表着一个编号,当SVC异常产生时,会调用对应编号的处理函数,默认情况下我们只有一个处理函数,所以该值一般填1。

当CPU执行了SVC指令后,会触发一个异常,在操作系统中,比如各类RTOS或者Linux,都会使用SVC指令故意触发异常,从而导致内核的异常处理函数被调用,进而去使用内核的服务(系统调用)。

比如Linux中,各类文件操作的函数openreadwrite,它的实质都是SVC指令。本喵这里不讲解这些,只是看一下SVC异常发生后的现象。

tu

如上图,定义一个SVC_Handler函数来处理SVC异常。

tu
如上图,在启动文件中,将SVC_Handler处理函数放入向量表并且声明,然后在Reset_Handler中执行SVC #1指令产生异常。

tu
如上图所示,此时可以看到,SVC_Handler处理函数被调用了,所以说,产生SVC异常时,会去执行对应的处理函数。

图
如上图所示,先给R0~R3,R12,LR赋值,然后在产生SVC异常后进入处理函数时停下来,查看此时栈中的内容,可以看到,我们原本赋给寄存器中的值此时保存在栈中。

  • 在调用异常处理函数之前,硬件进行了现场保存,将调用者保存的寄存器中的值放到了栈中。

🍢SysTick异常

Cortex-M处理器内部集成了一个小型的、名为SysTick的定时器,也叫做滴答定时器。可以使用它来为操作系统提供系统时钟,也可以把它当做一般的定时器。

它是一个24位的定时器,向下计数,在时钟源的驱动下,计数值到达0时,可以触发SysTick异常。

图
如上图所示SysTick定时器框图,每到了一次时钟信号,VAL计数器就会减一,当减到0以后会产生一次SysTick异常。

然后再自动从LOAD重装载寄存器中读取计数值到VAL中,如此反复产生多次异常。

控制SysTick定时器的寄存器基地址为0xE000E010


tu
如上图所示STCK_CTRL控制寄存器,通过BIT2来选择时钟源,该位是1时选择处理器时钟,也就是晶振直接作为时钟,STM32F103ZET6的晶振频率是8MHZ。

通过BIT1来使能SysTick异常,将该位设置为1,通过BIT0来使能SysTick定时器,将该位设置成1。

图
如上图所示计数器STK_VAL寄存器,其bit0~bit23存放的是计数值,要给它设置一个初始值。

图
如上图所示STK_LOAD重装载寄存器,VAL减为0以后会从这里重新拿值,所以该寄存器的值要设置成和VAL中的值一样。

图
如上图所示SCB_ICSR寄存器,SysTick异常发生以后,需要在处理函数中清除异常,将该寄存器的BIT25设置为1。


图
如上图,为了使用方便,同样将SysTick定时器用到的寄存器用结构体描述出来。

tu
如上图所示,定义一个SysTickInit函数来初始化滴答定时器,将VALLOAD寄存器的值都设置为8000,定时时间为1s,因为晶振时钟频率是8000。

再设置CTRL控制寄存器中的bit0~bi2,全部设置为1,表示选择晶振作为时钟源,使能SysTick异常,使能SysTick定时器。

图
如上图,定义异常处理函数SysTick_Handler,在里面清除SysTick异常,并且打印异常名字。

tu
如上图所示,声明异常处理函数SysTick_Handler,并将其放到向量表中。再声明定时器初始化函数SysTickInit,并在调用mymain之前调用,完成滴答定时器初始化。

tu
如上图,此时每隔一秒钟会产生一次SysTick中断,会调用一次SysTick_Handler异常处理函数。

⚡总结

要清楚异常发生的流程,包括现场保存,分辨异常源且执行相应的处理函数,通过软件触发现场恢复机制。其中现场保存和现场恢复是由硬件完成的,包括异常源的分辨也是。

  • 异常并不会经过中断控制器NVIC。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/200582.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

怎么在NAS里找照片?教你一招,精准定位

每次拍照 咔咔一顿拍 好多文档 咔咔一顿存 需要到的时候 却依稀只记得时间和部分关键词 那么怎么快速在NAS里精准定位 找到“命中注定”的它呢 嘿还真有 铁威马的Terra Search 精准搜索 快速定位 So easy! 01 什么是Terra Search Terra Search 通过建立数据…

2023年双十一报告(B站平台)

2023年双11购物节自10月24日开启预售,持续至11月13日落下帷幕。在购物狂欢期间,B站以更加成熟的姿态参战今年双11。 据B站官方数据显示,双11期间,B站带货GMV同比增长251%。其中视频带货GMV同比增长376%,直播带货GMV同…

算法基础之食物链

食物链 核心思想&#xff1a;带权并查集 用距根节点和距离表示与根节点的关系 求距离 #include<iostream>using namespace std;const int N50010;int n,m;int p[N],d[N];//找到祖宗节点(路径压缩) 并求出对应距离int find(int x){if(p[x]!x){int up[x]; //保存旧父节点…

VUE2中使用阿里云播放器AliPlayer

简述 基于 Vue 的播放器单页应用, 利用 web 播放器 sdk 进行视频点播&#xff0c;包含播放列表、字幕、多语言、自适应码率&#xff0c;皮肤自定义等功能 Web播放器文档 已知问题 vue中使用截图&#xff0c;不太好使【已自行优化】无键盘快捷键&#xff0c;无法通过空格暂停…

机器学习实验四:决策树-隐形眼镜分类(计算信息增益和信息熵以及模型准确率)

决策树-隐形眼镜分类(计算信息增益和信息熵以及准确率) Title : 使用决策树预测隐形眼镜类型 # Description :隐形眼镜数据是非常著名的数据集 ,它包含很多患者眼部状况的观察条件以及医生推荐的隐形眼镜类型 。 # 隐形眼镜类型包括硬材质 、软材质以及不适合佩戴隐形眼镜 。…

zookeeper集群+kafka集群

zookeeper集群kafka集群: kafka3.0之前依赖于zookeeper。 zookeeper开源&#xff0c;分布式的架构。提供协调服务&#xff08;Apache项目&#xff09; 基于观察者模式涉及的分布式服务管理架构。 存储和管理数据。分布式节点上的服务接受观察者的注册。一旦分布式节点上的数据发…

C语言--每日选择题--Day29

第一题 1. while(1) {x;}, 当x的取合适的初值时&#xff0c;可以避免死循环。 A&#xff1a;正确 B&#xff1a;错误 答案及解析 B 循环条件为1&#xff0c;在条件判断中&#xff0c;0为假&#xff0c;非0为真&#xff0c;1位真&#xff0c;所以无论x取什么&#xff0c;都是死循…

ASEM工控机维修工业电脑控制器维修PB3400

ASEM工控机维修asem工业电脑维修常见型号&#xff1a;PB3400;PB2000;PB3200;PB3600&#xff1b;BM2200等。 ASEM工控机维修常见故障有&#xff1a;开不了机、黑屏、不能启动、电路板故障、主板、开机没反应、显示器没反应、主板故障、蓝屏、卡机、显示器信号灯一直闪、系统不能…

基于SSM的酒店预订管理系统设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;Vue 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#xff1a;是 目录…

LaTeX插入裁剪后的pdf图像

画图 VSCode Draw.io Integration插件 有数学公式的打开下面的选项&#xff1a; 导出 File -> Export -> .svg导出成svg格式的文件。然后用浏览器打开svg文件后CtrlP选择另存为PDF&#xff0c;将图片存成pdf格式。 裁剪 只要安装了TeXLive&#xff0c;就只需要在图…

【JavaEE初阶】 HTTP响应报文

文章目录 &#x1f332;序言&#x1f38d;200 OK&#x1f340;404 Not Found&#x1f384;403 Forbidden&#x1f334;405 Method Not Allowed&#x1f38b;500 Internal Server Error&#x1f333;504 Gateway Timeout&#x1f332;302 Move temporarily&#x1f38d;301 Move…

基于Java web的多功能游戏大厅系统的开发与实现

摘 要 目前&#xff0c;国内游戏市场上的网络游戏有许多种类&#xff0c;游戏在玩法上也越来越雷同&#xff0c;形式越来越单调。这种游戏性系统给玩家带来的成就感虽然是无穷的&#xff0c;但是也有随之而来的疲惫感&#xff0c;尤其是需要花费大量的时间和精力&#xff0c;这…

【Cisco Packet Tracer】DHCP/FTP/WEB/DNS实验

本文使用CiscoPacketTracer仿真软件实现了DHCP/FTP/WEB/DNS实验&#xff0c;拓扑中包含2个客户机和3个服务器&#xff08;DHCP服务器、DNS服务器、FTP/WEB公用一个服务器&#xff09;&#xff0c;客户机的IP地址由DHCP服务器动态分配。 DHCP服务器IP地址&#xff1a;192.168.0…

OKCC 客户中心

OKCC服务了这么多家客户中心&#xff0c;但很多小伙伴们其实并不是太了解客户中心的主要功能&#xff0c;那么我今天将从两类客户中心介绍下他们的主要功能。 一、 运营机构客户中心的功能 对于运营机构而言&#xff0c;客户中心的功能包括:能够帮助运营机构提升品牌形象&…

TCP 基本认识

1&#xff1a;TCP 头格式有哪些&#xff1f; 序列号&#xff1a;用来解决网络包乱序问题。 确认应答号&#xff1a;用来解决丢包的问题。 2&#xff1a;为什么需要 TCP 协议&#xff1f; TCP 工作在哪一层&#xff1f; IP 层是「不可靠」的&#xff0c;它不保证网络包的交付…

如何远程开关机电脑丨远程开关机电脑的小技巧

在日常生活和工作中&#xff0c;我们可能需要远程控制电脑的开关机。下面就介绍几种常用的远程开关机方法。 方法一&#xff1a; 一、自行下载域之盾软件 https://www.yuzhidun.cn/https://www.yuzhidun.cn/ 二、在一台老板电脑上部署管理端&#xff0c;在想要远程开关机的电…

dcat admin日志扩展 dcat-log-viewer 遇到的问题记录

扩展地址&#xff1a; https://github.com/duolabmeng6/dcat-log-viewer 问题描述&#xff1a; 使用很简单&#xff0c;直接安装扩展包&#xff0c;开启扩展就可以了&#xff0c;会自动生成菜单。 之前在别的系统用过&#xff0c;没问题&#xff0c;今天在一个新的系统用的时…

shell脚本完成内容筛选并下载

(꒪ꇴ꒪ )&#xff0c;Hello我是祐言QAQ我的博客主页&#xff1a;C/C语言&#xff0c;数据结构&#xff0c;Linux基础&#xff0c;ARM开发板&#xff0c;网络编程等领域UP&#x1f30d;快上&#x1f698;&#xff0c;一起学习&#xff0c;让我们成为一个强大的攻城狮&#xff0…

最新AIGC创作系统ChatGPT系统源码+DALL-E3文生图+图片上传对话识图/支持OpenAI-GPT全模型+国内AI全模型

一、AI创作系统 SparkAi创作系统是基于ChatGPT进行开发的Ai智能问答系统和Midjourney绘画系统&#xff0c;支持OpenAI-GPT全模型国内AI全模型。本期针对源码系统整体测试下来非常完美&#xff0c;可以说SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。那么如何搭建部署AI…

打造独特封面:封面设计的关键要素与技巧解析!

书籍作品的封面设计非常精致。就像商品的包装一样&#xff0c;有助于提高书籍的销量。书封的设计表现主要从图像、文字、材质等方面进行设计。基本上所有的书都需要有文字&#xff0c;所以特别考验设计师的文字排版能力。今天就和大家分享一些书籍封面设计的小知识&#xff0c;…