LV04-07-中断与异常-02-异常处理实例
本文主要是中断与异常——Cortex A7异常处理实例的相关笔记,若笔记中有错误或者不合适的地方,欢迎批评指正😃。
点击查看使用工具及版本
Windows版本 | windows11 |
Ubuntu版本 | Ubuntu16.04的64位版本 |
VMware® Workstation 16 Pro | 16.2.3 build-19376536 |
终端软件 | MobaXterm(Professional Edition v23.0 Build 5042 (license)) |
Linux开发板 | 正点原子 i.MX6ULL Linux 阿尔法开发板 |
uboot | NXP官方提供的uboot,NXP提供的版本为uboot-imx-rel_imx_4.1.15_2.1.0_ga(使用的uboot版本为U-Boot 2016.03) |
linux内核 | linux-4.15(NXP官方提供) |
Win32DiskImager | Win32DiskImager v1.0 |
点击查看本文参考资料
分类 | 网址 | 说明 |
官方网站 | https://www.arm.com/ | ARM官方网站,在这里我们可以找到Cotex-Mx以及ARMVx的一些文档 |
https://www.nxp.com.cn/ | NXP官方网站 | |
https://www.nxpic.org.cn/ | NXP 官方社区 | |
https://u-boot.readthedocs.io/en/latest/ | u-boot官网 | |
https://www.kernel.org/ | linux内核官网 |
点击查看相关文件下载
分类 | 网址 | 说明 |
NXP | https://github.com/nxp-imx | NXP imx开发资源GitHub组织,里边会有u-boot和linux内核的仓库 |
https://elixir.bootlin.com/linux/latest/source | 在线阅读linux kernel源码 | |
nxp-imx/linux-imx/releases/tag/rel_imx_4.1.15_2.1.0_ga | NXP linux内核仓库tags中的rel_imx_4.1.15_2.1.0_ga | |
nxp-imx/uboot-imx/releases/tag/rel_imx_4.1.15_2.1.0_ga | NXP u-boot仓库tags中的rel_imx_4.1.15_2.1.0_ga | |
I.MX6ULL | i.MX 6ULL Applications Processors for Industrial Products | I.MX6ULL 芯片手册(datasheet,可以在线查看) |
i.MX 6ULL Applications ProcessorReference Manual | I.MX6ULL 参考手册(下载后才能查看,需要登录NXP官网) | |
ARM | Cortex-A7 MPCore Technical Reference Manual | Cortex-A7 MPCore技术参考手册 |
ARM Architecture Reference Manual ARMv7-A and ARMv7-R edition | ARM架构参考手册ARMv7-A和ARMv7-R版 | |
Arm Generic Interrupt Controller Architecture Specification- version 3 and version 4 | Arm通用中断控制器架构规范-版本3和版本4 | |
ARM Generic Interrupt Controller Architecture Specification - Version 2.0 | Arm通用中断控制器架构规范-版本2.0 | |
ARM Cortex-A Series Programmer's Guide for ARMv7-A | Cortex-A系列ARMv7-A编程指南 |
一、SVC异常
1. 软中断指令
前边其实有学习过SWI指令,我们可以通过这个指令,触发软中断,从而进入SVC模式,一般语法如下:
1 | SWI immed_24 |
immed_24是一个24位立即数,比如0x123些。注意:我们使用“ swi”指令,实际上我们可以在 .dis 中看到它被翻译为 SVC 指令。在老的芯片比如 S3C2440 中我们使用 SWI 指令,在IMX6ULL 中可以使用 SVC 代替它。
2. SVC异常处理
当使用SWI软中断的时候,就会产生SVC异常,进入这个模式,对应的CPSR的M[4:0]的值为10011,也就是0x13。关于SVC异常的汇编如下:
1 | /* SVC中断 */ |
在 SVC_Handler 里将 r0-r12 和 lr 保存在 SVC 模式的栈上,然后将 lr 的值移动到 R4,调用 printException 函数打印出当前的 CPSR 值,和产生异常的原因。将 R4 减去 4,赋值给 R0,这是 swi 指令所在的地址,然后调用printSWIVal 函数打印出 swi 指令的参数。最后将 r0-r12 从栈上恢复, lr 从栈上弹出到 PC,并同时将 SPSR 恢复到 CPSR,从而返回去执行 swi 指令的下一条指令。
3. 设置堆栈
注意一定要设置堆栈,否则进入对应的异常后,堆栈可能会异常。
1 | /* 进入SVC模式 */ |
4. 完整实例
完整的实例及修改可以看这里:08_EXCEPTION/SWI · sumumm/imx6ull-bare-demo - 码云 - 开源中国 (gitee.com)
5. 测试结果
我们可以在终端看到以下打印信息:
二、未定义异常
1. 怎么产生未定义异常?
前边已经学习过了,就是 CPU 或协处理器不认识这条指令,执行这样的指令时就会产生“未定义指令异常”。 我们可以这样产生一个未定义异常:
1 | .word 0xeeadc0de /* undefine instruction */ |
上边两条都可以产生未定义异常。
2. 未定义异常处理
1 | Undefined_Handler: |
在 Undefined_Handler 里将 r0-r12 和 lr 保存在 und 模式的栈上,然后调用 printException 打印当前的 CPSR 值,并打印一个字符串。最后将 r0-r12从栈上恢复, lr 从栈上弹出到 PC,并同时将 SPSR 恢复到 CPSR,从而返回去执行出现未定义异常指令的下一条指令。
3. 设置堆栈
1 | /* 进入undef模式 */ |
4. 完整实例
完整的实例和修改的地方可以看这里:08_EXCEPTION/UNDEF · sumumm/imx6ull-bare-demo - 码云 - 开源中国 (gitee.com)
5. 测试结果
最终我们可以在终端看到以下打印信息: