在Cortex-M0上从ISR中调用kill函数

3
我正在使用Cortex-M0处理器,使用裸机实现(没有操作系统)。我们有一个固件应用程序,希望允许第三方编写一个C函数,该函数将与其余固件分开构建并加载到内存中(类似于DLL),如果检测到,则由主固件调用。
我遇到的问题是,我希望在受保护的环境中运行此外部函数,以便如果它创建故障异常或执行时间过长,它不会干扰主固件。因此,我想要做的是,在硬故障ISR(用于故障异常)或计时器滴答ISR(用于执行时间问题)中,操纵堆栈以终止外部函数,并将执行返回到主固件。我意识到在RTOS中这将是简单明了的,但是主固件已经开发完成,目前切换将需要大量的努力。
我考虑使用C++中的try-catch,但编译器似乎不支持它。因此,我看到的另一种选择是编写一些汇编代码,在调用外部函数之前保存堆栈指针,并从ISR恢复SP和上下文,并跳转到主固件中的返回点。是否有更简单的方法来完成这项工作?能否给出如何最好地完成此操作的任何指针?

使用RTOS并不会更容易,因为它们没有动态加载/执行的规定。您仍然需要为该函数提供自己的包装器。问题不在于捕获异常并回滚堆栈,而在于防止该函数更改RAM。如果MPU足够完全取决于您的内存布局以及您想允许函数的内容。例如,如果它不仅有自己的堆栈,还可能破坏堆栈。 - too honest for this site
有没有可能使用一种小型的解释性语言来代替原生代码,以防止将直接的CPU/内存访问权限提供给第三方代码? - Brian McFarland
Brian - 我们实际上使用了一种解释汇编语言的初始实现,它使用Excel作为汇编器。然而,逻辑要求变得如此繁琐,以至于用汇编语言编写变得困难。因此,我们决定转换到C语言。第三部分将无法直接访问任何静态内存。他们将被给予访问固定大小控制值数组的函数。他们在堆栈上使用本地变量是一个问题。Cortex-m0确实有一个进程堆栈,我可以专门为此使用,但现在我认为我们将提供一些关于本地变量使用的规则。 - jdbk
我认为Cortex-M0没有完整的保护措施,因此这个重叠的应用程序可能会破坏一些东西,包括保护您免受其影响的内容。我认为RTOS无法发明您尚未拥有的东西(除非您的芯片中有PMSA,请参阅ARM文档),但实际上您正在创建某种操作系统。因此,您可以使用计时器检查您的代码是否有任何时间片,等等,或者通过某种方式检测程序是否丢失,但我认为一个行为不端的程序通常会使您崩溃。 - old_timer
1个回答

0

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

定时器滴答中断服务程序跟踪受保护函数运行的时间,如果超时或发生硬件故障中断,则执行故障处理程序。所需的第一件事是退出中断上下文(否则将从中断上下文执行主代码,阻止进一步的中断),因此我确定相对于SP的哪个堆栈位置保存ISR返回地址,并用故障恢复函数的地址覆盖它。请注意,定时器滴答中断服务程序的优先级最低,因此返回地址总是指向非中断代码。如果ISR优先级较高,则可能不是这种情况,但我没有验证。

从任一ISR退出时,将执行故障恢复函数。它需要两个指令:

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

这将SP和PC恢复到它们的正确状态,就像受保护的函数刚刚退出一样。但是,它不会恢复任何其他寄存器。如果返回点在函数末尾(且编译器不尝试内联它),那么应该没问题。在我的情况下,我需要将StackPtrSave设置为0,因为这是ISRs知道受保护函数正在运行的方式。我尝试使用易失性指针强制编译器在恢复后重新加载变量的地址到寄存器,但我无法使其工作。最后,我设置了一个属性来禁用函数上的优化,以便它始终在写入StackPtrSave之前加载地址。

正如评论中所指出的那样,这并不能提供完全受保护的环境。受保护的函数仍然可以使用指针来破坏静态变量或堆栈。我没有看到任何避免这种情况的方法,因为Cortex-m0没有内存保护单元。在我的情况下,负责受保护函数的第三方对产品的功能有着既得利益,因此我已经给出了指导方针,要求他们的代码避免使用指针或数组。我认为这提供了在此平台上可以提供的最高级别的保护。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接