【问题标题】:'Usage fault exception' in ARM Cortex MARM Cortex M 中的“使用错误异常”
【发布时间】:2017-05-09 19:30:36
【问题描述】:
我参加了一个关于 FreeRtos 和 Cortex M 的讲座,讲师建议如果 ISR 不使用 ISR 安全版本的 API,它可能会导致 Cortex M 处理器中的使用错误异常。这会发生因为这可能涉及从中断上下文(中断处理程序)到任务上下文(线程处理程序)
我的问题是为什么这个任务切换会被认为是非法的,这样的切换会产生什么影响?
【问题讨论】:
标签:
arm
rtos
freertos
cortex-m
【解决方案1】:
在 Cortex-M(某些)上,当前上下文将存储在中断之前使用的堆栈中(在中断进入时),因此如果您在执行任务并且它被中断,则将存储一些当前上下文在任务堆栈上(通过 PSP)。中断本身总是在 MSP 上运行。如果中断没有返回到它中断的任务,那么被中断的任务将有一个混乱的堆栈(因为它在退出时恢复存储的上下文)以及试图为切换到的任务恢复一个不正确的上下文。
在上下文切换(发生在中断中)时,一些上下文会自动存储在任务堆栈中,但操作系统也会将其余上下文存储在任务堆栈中。当它进行切换并退出中断时,操作系统会恢复它自己为任务存储的上下文,然后通过退出中断自动恢复上下文的其余部分。这是有效的,因为它确保堆栈以正确的格式保留。查看 Cortex-M4 通用用户指南中的中断进入/退出。
并非所有处理器都这样工作。
【解决方案2】:
这个答案是通用的,不是 FreeRTOS 也不是 Cortex-M 特定的 - 它适用于任何平台上的任何典型 RTOS:
导致调度程序运行的 RTOS API 调用不能从中断服务例程中调用。例如,如果您提供一个信号量,通常调度程序会运行以切换到该信号量上挂起的任何任务;这在中断上下文退出时调度程序必须运行一次的 ISR 中是不合适的;显然,您不希望在中断完成之前进行上下文切换,并且可能存在其他 API 调用或更高优先级中断的抢占,从而导致不同的任务变得可运行;仅在上下文切换发生时进行一次评估可以保持确定性行为。
ISR 特定版本的函数不会立即调用调度程序;相反,他们设置了一个标志来指示调度程序必须在退出中断上下文时运行。
通常,进行 RTOS API 调用的 ISR 必须有 prologue 和 epilogue;特定的进入/退出中断调用或宏。这个序言增加了一个在结尾处递减的计数器;如果计数器为零并且设置了调度标志,调度程序将运行。计数器是为了防止调度程序在退出嵌套中断时运行。这可确保调度程序仅在从最低优先级挂起中断退出时运行一次。
是否或为什么会发生“uasge 错误”是 FreeRTOS 特定的实现细节,主要是学术性的。 RTOS 同样可以在 ISR 中捕获非 ISR 安全调用的使用并运行更具体的错误处理程序,如果它不费心这样做,那么由此产生的行为可能会触发使用错误;这似乎是一种有点粗糙的依赖机制; 使用错误是一个非常广泛的陷阱,可能由于多种原因而发生:
使用错误:检测到未定义指令的执行,未对齐
加载/存储多个内存访问。启用时,除以零
和其他未对齐的内存访问也会被检测到。
一些 RTOS 没有特定于 ISR 的功能,而是导致调度的 API 调用在内部检测 ISR 上下文并在该上下文中表现不同 - 这对程序员来说更简单、更安全,但需要少量开销来测试上下文每一个这样的电话。在内部处理 ISR 安全性的 API 还意味着调用本身可能进行 OS API 调用的函数更简单,因为这些函数本身不需要特定于 ISR。