我试图在ARM Cortex-M3上生成总线故障、使用故障等异常。我的启用异常代码:
void EnableExceptions(void)
{
UINT32 uReg = SCB->SHCSR;
uReg |= 0x00070000;
SCB->SHCSR = uReg;
//Set Configurable Fault Status Register
SCB->CFSR = 0x0367E7C3;
//Set to 1 DIV_0_TRP register
SCB->CCR |= 0x00000010;
//Set priorities of fault handlers
NVIC_SetPriority(MemoryManagement_IRQn, 0x01);
NVIC_SetPriority(BusFault_IRQn, 0x01);
NVIC_SetPriority(UsageFault_IRQn, 0x01);
}
void UsageFault_Handler(void){
//handle
//I've set a breakpoint but system does not hit
}
void BusFault_Handler(void){
//handle
//I've set a breakpoint but system does not hit
}
字符串
我试图生成除零异常,并看到变量值为“无穷大”。但是系统在继续运行时没有生成任何异常。还尝试生成总线故障异常,但发生了相同的情况。
另外,当我注解EnableExceptions函数时,系统正常工作。我的代码有什么问题?ARM是否在微处理器内部处理此类错误?
3条答案
按热度按时间q3aa05251#
Cortex-M设备专门使用Thumb-2指令集,ARM使用分支/跳转/调用地址的最低有效位来确定目标是Thumb还是ARM代码,由于Cortex-M无法运行ARM代码,因此可以通过创建到 * 偶数 * 地址的跳转来生成BusFault异常。
字符串
下面的代码也可以工作,因为调用会在执行任何指令之前失败,所以它不需要指向任何有效的代码。
型
您可以通过强制 integer 除以零来生成使用错误:
型
hec6srdp2#
从您的评论问题:如何生成任何异常。
下面是文档中的一个:
字符串
...
型
我可以通过搜索SVCall找到它。
ARM对异常有很好的记录,有一些方法可以在不破坏总线的情况下引起你列出的异常(需要一个sim an fpga或创建自己的芯片),你已经知道文档的搜索词来查找busfault和usagefault。
ARM如何处理这些(内部或外部)都有文档记录。在这种情况下,内部意味着锁定或不锁定,否则它们将执行错误处理程序(当然,除非有错误获取错误处理程序)。
大多数你可以在C中创建,而不需要借助汇编语言指令,但你必须小心,它正在生成你认为它正在生成的东西:
型
相反,您需要的是实际生成可能导致错误的指令的东西:
型
但如图所示,你必须小心在哪里以及如何调用它。在这种情况下,调用是在同一个文件中完成的,因此优化器可以看到这是一个死代码,并对其进行优化,因此这样的测试将由于多种原因而无法生成错误。
这就是为什么OP需要提供一个完整的最小示例,没有看到故障的原因不是处理器。而是软件和/或测试代码。
编辑
一个完整的最小示例,除了一个GNU工具链(没有。这是在一个stm32蓝色药丸一个stm32f103.
闪光
型
flash.ld
型
fun.c
型
建造
型
所有这些命令行选项都不是必需的arm-linux-gnueabi-和其他版本的gnu工具链从几个版本到现在都工作得很好,因为我把它们用作编译器,汇编器和链接器,而不会弄乱库或其他不同版本的东西。
型
...
型
所以这里的测试分支到手臂地址和拇指地址,这导致了usagefault。(也可以在文档中阅读有关BX指令psr.t位如何以及何时更改等内容)
支持这一点的是stm32蓝色药丸。PC 13上有一个led,代码启用usagefault,将PC 13配置为输出, Flink 一次,这样我们就可以看到程序启动,然后如果它命中usagefault处理程序,它就会永远 Flink 。
型
如果你注解掉这个,它会继续分支到重置,重置会再次执行所有操作,一个缓慢的 Flink ,你会看到永远重复。
在自然运行之前,您检查构建以查看它是否有可能工作:
型
向量表是正确的,正确的向量指向正确的地方.
型
HFSR是CFSR的高位
型
那就是
型
现在开始
型
CCR的重置值是IMPLEMENTATION DEFINED,因此它可能只是为您启用或不启用,可能需要查看Cortex-m3 TRM或只需读取它:
型
所以它的0和我的一样
所以增加乐趣。c:
型
更改so.c:
型
建造
型
确认实际上有一个除法指令,我们将命中
型
加载并运行,并调用处理程序。
这表示它被零除。
所以你需要知道/做的一切都在文档中,一个文档。
99.999%的裸机编程是阅读或做实验来验证读取的内容,几乎没有工作是编写最终的应用程序,这只是工作的一小部分。
在你开始裸机编程之前,你必须掌握工具链,否则什么都不会工作。掌握工具链可以在没有任何目标硬件的情况下完成,使用免费工具,所以这只是一个坐下来做的问题。
如果你想在一个没有硬件除零功能的内核上进行浮点除零,你需要看看软浮点数,例如libgcc:
这应该在反汇编中可见,我没有立即看到强制异常(故意未定义的指令,swi/svc或类似的东西)。这只是一个可能的库,现在我想它看起来像手臂而不是拇指,所以必须去寻找,更容易只看拆卸。
根据你的评论,如果我再读一遍另一个问题,我假设,因为它没有引发异常,除以零的正确结果是一个正确的有符号的无穷大。但如果你切换到cortex-m4或m7,那么你可能会触发硬件异常,但....阅读文档来找出答案。
编辑2
这意味着
因此volatile未能使用gcc产生预期的结果
产生
你也可以通过别人的方式来实现你的目标。
是的,产生了一个错误,这是使用错误,但这将是另一个堆栈溢出问题,为什么我没有得到一个除以零。盲目地使用volatile来划分是行不通的。
使这三个都变得不稳定
将产生所需的故障。
而且没有任何优化
也会产生所需的故障
所以首先掌握语言(读),然后掌握工具链(读),然后是裸机编程(读)。这一切都是关于阅读,而不是编码。如上所示,即使在这个级别上有几十年的经验,您也不能完全预测这些工具将产生什么;你必须尝试一下,但最重要的是,因为你一天一次在一台机器上为一个工具弄明白了没有理由在你的假设中变得太宽泛。必须尝试它并检查编译器产生的内容,重复该过程,直到获得所需的效果。到了紧要关头,写几行asm就可以了。
您没有看到错误,因为您没有生成任何错误和/或没有捕获它们,或者两者都没有。根据提供的代码,可能的原因列表很长,但是这些例子,你应该没有问题移植到你的平台,也应该证明你的硬件工作,然后你可以通过连接代码和代码之间的点来找出为什么你的软件没有。我所做的就是遵循文档,并检查编译器的输出,一旦我启用了最少数量的东西,就调用了错误处理程序。如果未启用,则不会触发使用故障。
r8xiu3jd3#
总线故障、硬故障、MemmanageFault、UsageFault、SVC调用、NMI,这些是arm cortex-M微处理器的内部异常。这实际上取决于您使用的处理器,但让我们假设您使用的是cortex-m3:
要生成故障,您可以尝试:
USGFAULTACT、BUSFAULTACT、MEMFAULTACT在系统处理程序控制和状态寄存器=>中,这肯定会生成异常
详情请参阅:https://developer.arm.com/documentation/dui0552/a/cortex-m3-peripherals/system-control-block/system-handler-control-and-state-register?lang=en