从皮质-m0上的ISR中杀死函数

时间:2015-06-08 16:32:21

标签: c stack embedded cortex-m

我正在使用裸机实现的Cortex-M0处理器(无操作系统)。我们有一个固件应用程序,我们希望允许第三方编写一个C函数,该函数将与其余固件分开构建并加载到内存中(有点像DLL),如果检测到,则由主固件调用。

我遇到的问题是我想在受保护的环境中运行此外部函数,因此如果主要固件产生故障异常或执行时间过长,它不会中断主要固件。所以我想做的是,从硬故障ISR(用于故障异常)或计时器滴答ISR(用于执行时间问题),操纵堆栈以终止外部功能并将执行返回到主固件。我意识到这在RTOS中是直截了当的,但主固件已经开发出来,此时需要花费大量精力才能将其切换。

我在c ++中使用了try-catch,但编译器似乎并不支持它。所以我看到的另一个选项是在调用外部函数之前编写一些程序集以保存堆栈指针,并从ISR恢复SP和上下文,并转移到主固件中的返回点。任何人都可以提供关于如何最好地做到这一点的任何指示,或者有更简单的方法来实现这一目标吗?

1 个答案:

答案 0 :(得分:0)

这是我最终使用的实现。我利用CMSIS内部函数__get_MSP()和__set_MSP()来访问SP。在调用受保护的功能之前,我保存了当前的SP。返回地址是函数在堆栈上推送的第一项,因此我将保存的SP递增一个位置,以便它指向要在故障恢复情况下使用的返回地址。

计时器标记ISR跟踪受保护功能运行了多长时间,如果超时或发生硬故障中断,则执行故障处理程序。首先需要的是退出中断上下文(否则你将从中断上下文执行主代码,防止进一步的中断),所以我确定哪个堆栈位置相对于SP保存了ISR返回地址,我用它覆盖它故障恢复功能的地址。请注意,Timer Tick ISR的优先级最低,因此返回地址始终为非中断代码。如果ISR优先级较高,可能不是这种情况,但我没有验证它。

从任一ISR退出时,将执行故障恢复功能。它需要两条指令:

__set_MSP( StackPtrSave );
__asm volatile ("pop {pc}");

这会将SP和PC恢复到正常状态,就像保护功能刚刚退出一样。但是,它不会恢复任何其他寄存器。如果返回点位于函数的末尾(并且编译器没有尝试内联它),那么它应该没问题。在我的例子中,我需要设置StackPtrSave = 0,因为ISR知道保护功能何时运行。我尝试使用易失性指针强制编译器在恢复后将变量的地址重新加载到寄存器,但我无法使其工作。最后,我设置了一个属性来禁用函数优化,因此它总是在写入StackPtrSave之前加载地址。

如评论中所述,这并未提供完全受保护的环境。受保护的函数仍然可以使用指针来破坏静态变量或堆栈。由于Cortex-m0没有内存保护单元,我认为没有办法避免这种情况。在我的情况下,负责受保护功能的第三方确实对产品的功能感兴趣,因此我给出了他们的代码避免使用指针或数组的准则。我认为这提供了可在此平台上提供的最高级别的保护。