Blogs

Cortex-M例外处理(第2部分)

伊万 Cibrario Bertolotti.2016年2月1日9评论

本文的第一部分  描述了Cortex-M接受的例外请求的条件 处理器主要关于其优先级与当前执行优先级的关系。这部分 将描述会发生什么 接受异常请求并变为活动状态。

处理器操作和特权模式

在详细讨论后,在接受异常请求之后处理器内发生的操作序列是必要深入进入处理器的概念 执行模式.

从这个角度来看,Cortex-M处理器的方法非常简单比其前辈更简单。例如, ARM7TDMI处理器,一旦像微控制器的建筑块一样受欢迎并且根据 ARM架构的版本5,有七种不同的操作模式(其中两个, 打断快速中断,用于中断处理)。相比之下,Cortex-M处理器只有 总共两种模式,称为 线处理程序 mode.

本文以PDF格式提供,便于打印

值得一提的另一点是Cortex-M处理器实施了两个不同的 堆栈指针,称为主堆栈指针(MSP)和进程堆栈指针(PSP),并引用内存中的不同堆栈。在任何给定的时间,处理器利用其中一个,选择也取决于执行模式。

知道究竟是哪个堆栈指针对于嵌入式软件开发人员来说非常重要,因为堆栈保持关键数据结构,例如函数参数和返回值。此外,当系统支持多个任务的并发执行时,正确的堆栈管理(每个任务数据结构)对于避免内存损坏并确保系统正常运行至关重要。

线程模式

线程模式是正常任务执行模式,而作为稍后讨论的一般规则的例外 - 也是处理器在接受重置异常时输入的模式。从执行权限的角度来看,线程模式可以是 一个不史分比的 或者 特权,取决于如何 npriv. 一点点 控制 register is set.

执行权限确定当前正在执行的代码允许访问和使用系统资源的程度,即某些批判性的指令,寄存器和内存区域。例如, 控制 寄存器本身只能通过特权代码编写。这是有道理的,否则,非特权代码可以通过覆盖当前内容来轻松地以无法控制的(甚至无法检测)的方式提高其特权级别 控制 具有更有利的价值。

相反,只有处理器硬件本身 - 根据机制,我们将在下面更彻底地描述 - 以及允许特权代码进行修改 控制。当该特征伴随着合适的存储器保护机制时(如本文第一部分简要概述的MPU),可以在代码之间保持明确和不可用的分离,这意味着不平等(不受信任的应用程序级别代码)和具有完全访问系统的特权代码(可信组件,通常是操作系统的一部分)。

另一点了 控制 注册 - 即 Spsel. 位 - 在线程模式下决定处理器是否使用MSP或PSP作为堆栈指针。

处理程序模式

据名称说明,处理器使用此模式来执行除上面的重置处理程序之外的所有异常处理程序。在处理程序模式下执行的代码本质上是特权,并且始终利用MSP,无论设置如何 控制 register.

如下面的更多细节中所述,当处理器接受异常请求时,从线程到处理模式的转换会自动发生,使其成为活动状态,同时在线程模式下执行。反向转换,返回到线程模式发生在异常处理程序返回时,没有其他活动异常,并且异常处理在线程模式下在执行时中断处理器。

当在线程模式下运行的未体现代码执行SVC组件指令时,发生了模式转换的特殊情况,如本文的第一部分所述, 无条件地触发异常请求。对于当前的指令流,并且通过通常在操作系统内实现的可信软件例程,对当前的指令流程同步接受异常的例外,并且授予未经特权的代码控制访问权限执行模式。

异常变为活动状态时会发生什么?

构成异常处理条目序列的主要阶段 - 即处理器执行以开始处理异常的操作序列在如下图所示 and then 详细讨论。图中的数字对应于解释中的数字。

  1. 这 first action performed by the processor is to 保存当前执行上下文的一部分。此信息存储在 当前堆栈也就是说,当接受异常请求时,处理器使用的堆栈。保存到a的最小信息量 基本堆栈框架 由寄存器组成 R0 通过 R3, R12,链接寄存器 LR. (也可用 R14),程序计数器 个人电脑 (R15)和程序状态寄存器 XPSR.,总共32个字节。
    当处理器实现可选的浮点扩展时,浮点单元的上下文也被保存到 延长 堆栈框架。上下文的这一部分可以在进入序列期间立即保存,如上所述,或者尽可能地推迟,直到当执行浮点指令时上下文即将修改。这是因为浮点上下文相当大,需要68个额外的字节。
    有关此形式的更多信息 懒惰的 上下文保存和恢复技术 - 这也是广泛的,在其他处理器的其他家庭中具有轻微变化 - 留下作为未来帖子的主题。相反,在下文中,我们只关注处理器的方式 没有 浮点延期行为。
    在这两种情况下,取决于该值的值 Stkalign. 配置和控制寄存器的位 CCR.,处理器可以调整堆栈指针以确保保存的堆栈帧对齐到8个字节的倍数。
    保存执行上下文背后的原因是接受和处理异常,不一定会阻止处理器在以后稍后回到其当前活动。这尤其如此 中断 以及发生的其他异常请求 异步 关于当前的处理器活动,通常与他们完全无关。因此,他们将被处理 透明地 关于在到达时发生的任何代码。
    另一方面,选择 哪一部分 保存的上下文是通过使结果堆栈框架布局符合符合的目标 ARM架构程序调用标准 (aapcs)。通过这种方式,符合AAPCS的函数可以用作异常处理程序。当异常处理程序以高级语言编写异常时,这尤其重要,因为编译器默认能够生成符合AAPCS兼容代码,因此,它们还可以生成异常处理代码,而不将其视为特殊情况。
    换句话说,处理器硬件将堆栈上的上下文完全像AAPCS-Pressult软件程序一样,它即将调用另一个。因此,硬件执行的异常处理程序呼叫无法区分 来自常规软件管理的函数调用。
  2. 设置链接寄存器 LR. 适合 例外回报 价值(称为 exc_return. ARM文档中的价值)。由于以下内容更好地讨论,因此将异常返回值加载到程序计数器中时 个人电脑作为函数ePilogue的一部分,它指示处理器启动异常处理程序返回序列,而不是简单地返回到呼叫者。
    实际上,AAPC规定函数调用必须保存到链接寄存器中 LR. 在设置程序计数器之前,返回地址 个人电脑 到函数入口点。这通常是通过执行分支和链接指令来完成的 bl 与A. 个人电脑 - 目标地址。值得一提的是,当处理器支持多个指令集时,位0 LR. 假设特殊含义,并指示在呼叫时使用的指令。但是,Cortex-M处理器中的情况并非如此,它只支持拇指-2指令集。
    在所谓的函数的外表中,然后可以通过存储回来返回到呼叫者 个人电脑 存储到的值 LR. 在呼叫时。例如,这可以通过分支和交换指令来完成 BX., 使用 LR. 作为论据。因此,异常条目序列的这一方面已经归属于允许任何符合AAPCS的函数直接用作异常处理程序。
    这 information provided by the exc_return. 值允许处理器定位要恢复的堆栈帧,以正确的方式解释它,并在接受异常时将处理器带回执行模式。为此目的,如表1所示,5个低位位 exc_return. value encode:
    • 处理器是否使用主(MSP)或进程堆栈指针(PSP);
    • 保存的堆栈帧是基本的(不包括浮点上下文的空间)或扩展(包括它);
    • 当前处理器执行模式(线程或处理程序模式)。
    4位高阶位 exc_return. 必须设置为 0xF。他们指定了加载的值 个人电脑 不是常规的内存地址,但它确实是一个 exc_return. 处理器必须特别处理的代码。
    此时,剩余的位,即第27位下降到5位,未使用。他们所有人都读为一个目前,但软件必须在写作时保持其价值。应该注意的是,处理器分析加载的值 个人电脑 并且可能会将其解释为一个 exc_return. 只有在特定情况下的价值,更好地详细说明 Cortex-M架构文档 并关联与异常处理程序结尾。
    在其他情况下,例如何时 个人电脑 在处理器处于线程模式时加载(因此,没有异常处理程序可能是有效的),在字面上拍摄该值作为存储器地址。如果是避免行为不当 exc_return. value is mistakenly loaded into 个人电脑 在这些情况下,硬件保护地址范围 0xf0000000-0xffffffff. 反对指令执行。
  3. 可能切换到 处理程序 执行模式,如果接受异常时处理器在线程模式下执行。与这一一般规则的显着偏差是 重置异常,它以线程模式处理。与执行模式开关相关联,处理器也可以转换以使用新堆栈。实际上,如前所述,处理程序模式执行始终利用MSP,而线程模式执行可以使用MSP或PSP,具体取决于处理器配置。重置后,执行在线程模式下启动,处理器自动配置为使用MSP。
    处理器执行的其他操作,既不在上图中显示, 这里也没有进一步讨论,包括存储刚刚接受的异常的例外数量 IPSR. 子寄存器 - 这是部分 XPSR. 注册和更新多个系统控制空间(SCS)寄存器以反映异常接受。另一种动作是接受异常清除任何待处理同步指令的本地每核状态,即, Ldrex.斑点。因此,在执行恢复后,需要重复使用诸如异常条目的指令的任何同步过程。对于多核系统中的适当核心同步非常重要。
  4. 这 非常最后的行动 by the processor upon exception entry 是检索目标 个人电脑 - 是,异常处理程序的入口点 - 来自 矢量表 和 jump to it.
    向量表是一个非常简单,内存居民数据结构,并且由32位整数的数组组成,保持了名为的存储器地址 vectors.。更具体地说, i表的-Th条目包含处理程序的入口点以查找异常编号 i。此分配不会出现模糊性,因为异常编号是固定的,并且与优先级不同,唯一地标识每个异常。
    仅由架构规范明确定义了前16个异常编号。此外,向量的总数不固定,取决于Cortex-M系列的特定成员支持的例外数量,以及配置和实现选项。首次进入(索引0)以一种特殊方式使用,因为实际上,没有分配异常数为零。 相反,此条目包含重置时加载到MSP中的初始值。
    向量表的起始地址保持在名为Vector Table Offset寄存器的寄存器中(vtor.)。 7个低位位 vtor. 保留并始终解释为零,因为导航表中的导航表中的最小对齐是128字节。另外,根据表中的条目总数,进一步的对准约束可能生效。
    与此前提到的不同 控制 注册 - 这是 紧密耦合 到处理器,通过专业说明直接可访问它 太太MSR.vtor. 是一个内存映射的寄存器,处理器通过常规内存负载和存储指令访问它,如 LDR.str..
    出于这个原因,要保护 vtor. 针对未经授权的写访问(例如,通过虚拟代码进行的写尝试)必须启用本文的第一部分中提到的合适的内存保护机制,并适当地配置。或者,一些处理器,如 Cortex-M3不实现这些可编程机制的,可能仍然支持不可编程的保护,并防止不受控制的访问 vtor.以及来自未经特权的代码的其他关键记忆映射寄存器。
    另一点值得一提的是 vtor. 当处理器接受重置异常时,寄存器被重置为零。结果,初始值 个人电脑MSP. 在重置时未从当前向量表中检索,即,当接受重置异常时的一个实际情况,但从地址零时的矢量表。
    还应注意,根据特定设备,矢量表的物理地址可以通过处理器外部的地址重新映射来进一步影响。在这些情况下,有必要指代设备 - 而不是处理器文档,以确定哪个寄存器控制映射以及如何。
    例如,在恩智浦 LPC17xx. 微控制器家庭 可以在地址上映射 0x00000000 (默认情况下,其中矢量表开始)引导程序ROM(通常可在物理地址访问 0x1FFF0000.)而不是片上闪存(其实际上存在于地址 0x00000000)。重新映射由特定于设备的位0控制 Memmap. register.

表格1
编码EXC_RETURN值

Exc_Return值(5位低位) 堆栈指针 帧类型 执行模式

11101(0x1D)

过程 基本的 线

11001(0x19)

主要的 基本的 线

10001(0x11)

主要的 基本的 处理程序

01101(0x0d)

过程 延长 线

01001(0x09)

主要的 延长 线

00001(0x01)

主要的 延长 处理程序
其他 预订的 预订的 预订的

例外回报

如前所述,处理器启动 例外回报 序列当特殊值表征模式时 0xF 在4个高阶位和调用 exc_return. 在下面的 - 装入 个人电脑 在异常处理程序结束时。

非正式地说,在这些情况下,而不是简单地覆盖旧内容 个人电脑 并跳转到新地址,处理器“撤消”先前描述的异常处理程序激活步骤,以便透明地恢复其在异常处于活动状态时执行的活动。进一步来说:

  1. 首先,处理器检查和解释 exc_return. 根据表1的价值 以上。更具体地,该值确定将使用哪个堆栈指针(MSP或PSP)在下一步骤中恢复处理器上下文,要恢复的堆栈帧的结构和内容(基本或扩展)和处理器模式(处理程序或螺纹)恢复后。
  2. 然后,处理器执行多个完整性检查,以确保从异常返回返回的是考虑当前执行上下文。任何失败的检查都会提出一个 UsageFault. 例外,然后像往常一样处理。
    例如,目前正在处理的异常,其数量已被记录 IPSR. 在异常条目后,必须有效,以便合法地从中返回。此外,处理器目前必须在处理程序模式下执行,如果它即将返回线程执行模式,则要恢复的值 IPSR. 必须是零,从而表明没有任何例外都有活动。对所有支票的彻底讨论超出了本书的范围,兴趣的读者应该参考 Cortex-M架构文档 for further details.
  3. 最后,处理器恢复存储在上一步骤中标识的堆栈指针所示的堆栈帧中的上下文。除此之外,上下文包括当前例外被接受时处理的异常编号 IPSR. 分寄存器 XPSR.,而且 个人电脑 被接受的例外被接受。
    因此,上下文恢复的直接后果是处理器恢复从预先暂停的位置的执行 IPSR. 包含恢复处理的异常的例外,如果有的话。如果不嵌套异常, IPSR. 恢复为零。

[]
评论 QL.2016年2月1日
如果有人希望在CORTEX-M中断处理期间实际上看到CPU和堆栈中发生的事情,则有一个YouTube视频课程。特别是第17和18课解释了Cortex-M异常处理。课程的完整播放列表在这里:

//www.youtube.com/playlist?list=PLPW8O6W-1chwyTzI3BHwBLbGQoPFxPAPM
[]
评论 Yuvraj.252016年12月30日

你好,


我正在使用Cortex M4控制器。 

我处于低优先级ISR的情况下,高优先级ISR和HPI中断,我想去下一个现成的任务。

但是,当我尝试从处理程序模式转到新的任务(线程模式)时,LPI仍然处于活动状态,因此我获得了一个使用率。 

在这种情况下,我如何进入线程模式?

如何在HPISR中更改低优先级ISR的活动状态?


问候,

Yuvraj.

[]
评论 伊万 Cibrario Bertolotti.2016年12月31日

你好,

当您指出时,处理器通常不会支持返回异常以外的至少一个异常时支持返回线程模式,如“异常返回”的“完整性检查”中所示,ARMV7-M架构参考的第B1.5.8节。手动的。

这是出于充分的理由,更好地说明了与堆栈管理/完整性以及任务和中断处理程序优先级的一致处理相关的B1.5节。

可以通过设置配置和控制寄存器(CCR)的位非粘液仪(CCR),第B3.2.8节中的BIT NONASETHRDENA。

但是,在这样做之前,我会仔细考虑这一决定的副作用。例如,LPI何时将被恢复并如何?它的执行上下文在哪里保持在同时?优先级反转怎么样?

我希望至少部分地答案,你的问题。

问候,
ICB.

[]
评论 Yuvraj.252017年1月3日

你好,


非常感谢您的建议。

是的,我尝试了设置nongasethrdena位,但正如您所说,这不会停用中断,并且LPI将无法再次激活。

我看到的另一个解决方案是在HPI中设置标志,然后切换到LPI的开始并检查标志,然后将上下文切换到下一个就绪任务。


问候,

Yuvraj.

[]
评论 伊万 Cibrario Bertolotti.2017年1月3日

你是对的,有副作用,这就是为什么我有点不愿意建议这种方法。我确实铭记了几个情景,确实有必要,但它们非常复杂,我不确定这是您的情况。

如果我正确地理解你的解决方案,可能会有副作用,具体取决于LPI的复杂程度。例如,如果LPI更新(非原子上)复杂的数据结构并且它从开始重新启动(而不是恢复),这可能很容易导致不一致,因为LPI可能会使更新“中途”。

这就是为什么在几乎所有传统的RTOS中,中断以优先顺序接受,处理程序以LIFO时尚执行(在单个中断堆栈上保持其上下文),在抢占时,它们将恢复,并且始终运行到完成。它们都隐含地具有比系统中的任何任务高的优先级。

假设您的问题是,任务T需要低于HPI但高于LPI的执行优先级,“教科书”解决方案是将LPI分为两部分:中断处理程序LPI'和任务LPT。 LPI'只唤醒LPT,非常短,因此其执行不会破坏时间。然后,您可以提供您更喜欢的优先级,低于T.

大多数RTOS提供支持此机制(ECO中的所有ISR / DSR的一个示例),但它也可以使用信号量/事件标志。大多数RTOS可以在几个装配说明中唤醒在几个汇编指令中的信号量/事件标志上等待,因此,LPI确实非常短。

祝你今天过得愉快,
伊万

[]
评论 Yuvraj.252017年1月5日

你好伊万,

非常非常感谢你。

问候,

Yuvraj.

[]
评论 Yuvraj.252017年1月12日

你好,

我正在研究Cortex M4,目前我在中断(例外)例程中的情况下我要进入线程模式并执行函数,然后再次返回处理程序模式。当我进入线程模式时(通过更改PSR寄存器并使用BX指令),IPSR寄存器被清除,但活动异常变为待定。 

有效例外变得待处理的原因是什么?

问候,

Yuvraj.

[]
评论 Stephane.b.2017年1月12日

嗨yuvraj,

一个更好的地方提出这样的问题就是在 论坛。也许Ivan会在这里回答你,但我相信Ivan也关注论坛,你会得到有助于讨论的其他用户的额外利益。

Stephane.

[]
评论 Yuvraj.252017年1月12日

你好斯蒂芬,


是的,我将使用论坛进行讨论。

非常感谢你提供的信息。


问候,

Yuvraj.

要发布回复评论,请单击连接到每个注释的“回复”按钮。发布新的评论(不是回复评论),请在评论的顶部查看“写评论”选项卡。

注册将允许您参加所有相关网站的论坛,并为您提供所有PDF下载。

注册

我同意 使用条款隐私政策.

尝试我们偶尔但流行的时事通讯。非常容易取消订阅。
或登录