Hercules(TMS570 和 RM4x/RM5x)器件上发生的中止调试指南
This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
1 什么是异常?
“异常”是一个事件,它使处理器暂时停止正常的程序执行流程,例如为来自外设的中断提供服务。在尝试处理异常之前,处理器会保留当前处理器状态的关键部分,以便在处理程序例程完成时原始程序能够恢复。
在实际情况中,异常主要可以分为以下几类:
2 什么是异常优先级顺序?
当多个异常同时发生时,系统会按照固定的优先级顺序来处理这些异常。系统依次处理每个异常,然后再继续执行用户程序。并非所有异常都会同时发生。例如,未定义指令和 SVC 异常是互斥的,因为它们都是通过执行指令触发的。
由于数据中止异常的优先级高于 FIQ 异常,因此在处理 FIQ 之前实际上会注册数据中止。然后会进入数据中止处理程序,但随后会立即将控制权传递给 FIQ 处理程序。处理 FIQ 后,将控制权返回给数据中止处理程序。这意味着数据传输错误不会像在首先处理 FIQ 时那样无法被检测到。
异常 |
优先级 |
复位 |
1 (最高) |
数据中止 |
2 |
FIQ |
3 |
IRQ |
4 |
预取中止 |
5 |
SVC |
6 |
未定义中止 |
6(最低) |
在进入所有异常时禁用 IRQ。在进入 FIQ 和复位时禁用 FIQ。
3 处理器对异常有何响应?
发生异常时,ARM CPU:
4 中止(DABT、PABT 和 UNDEF)之间的差异
如果从受保护或有故障的存储位置读取数据或向其中写入数据,则处理器会接收到数据中止异常。数据中止可以是同步的,也可以是异步的。
导致数据中止的指令位于 R14_ABT – 8,这意味着指针指向导致中止的指令之后的两条指令。
如果处理器尝试执行来自受保护或有故障的存储器位置的指令,则会接收到预取中止异常。所有预取中止都是同步的。
导致数据中止的指令位于 R14_ABT – 4。lr_ABT 指向导致异常的指令的下一条指令。处理程序必须返回到 lr_ABT – 4
当处理器遇到相应版本的 ARM 指令集中未定义的指令或者在 VFP 被禁用时用于 VFP 的指令时,处理器会接收到未定义指令异常。未定义指令异常可用于模拟未定义的指令,或仅用于处理故障情况。
导致 UNDEF 中止的指令位于 R14_und – 4。
5 预取中止和数据中止的返回地址为何不同?
对于预取,返回地址为:R14_abt = 已中止指令的地址 + 4;对于数据中止,返回地址为:R14_abt = 已中止指令的地址 + 8。
CPU 程序计数器 (PC) 会在执行期间的特定点更新。在提取/解码/执行的不同阶段都可能会发生异常。
对于预取中止,只有当处理器实际尝试执行指令时才会发生此异常。在发出预取中止命令时不会更新程序计数器,lr_ABT 指向导致异常的指令的下一条指令。
对于数据中止,指令正在执行并且指令的执行才导致出现此异常。当加载或存储指令尝试访问存储器时,程序计数器已更新。lr_ABT 中存储的值 (pc – 4) 指向生成异常的地址后的第二条指令。
请参阅 ARM TRM 中的表 3-4。该表总结了进入异常时相关的 R14 中保存的 PC 值以及 ARM 建议的用于退出异常处理程序的指令。
6 我如何知道存在中止?
发生中止时,程序会在异常向量表处停止。如果在异常向量地址处设置了断点,程序计数器会在地址 0x0C (PABT)、0x10 (DABT) 或 0x04 (UNDEF) 处停止。
有三个重要的 ARM Cortex-R4/R5 寄存器可用于确认处理器的当前状态:
CPSR:CPSR 可用于验证处理器的当前模式。CPSR 寄存器的模式位可用于检查当前模式是否为中止。
M[4:0] |
模式 |
10000 |
用户 |
10001 |
FIQ |
10010 |
IRQ |
10011 |
管理 |
10111 |
中止 |
11011 |
未定义 |
11111 |
系统 |
SPSR:SPSR 可用于检查进入异常之前的模式。例如,如果处理器从系统模式转换至中止模式,则 SPSR 将模式显示为“系统”,而 CPSR 将模式显示为“中止”。SPSR 寄存器的位定义与 CPSR 寄存器的位定义相同。
R14 寄存器:R14 寄存器用于查找导致同步中止的实际指令或函数调用。触发异常的指令的实际地址为 R14 - x,其中“x”取决于异常的类型。
有关详细信息、请参阅 Cortex-R4/R5 TRM 中的表 3.4“异常进入和退出”:https://developer.arm.com/documentation/ddi0363/e/
7 未定义指令异常 (UNDEF)
如果 CPU 不理解提取的指令,则可能会发生未定义指令异常。
该异常没有关联的故障状态和故障地址寄存器;只有连接寄存器 (R14_UND) 会提供相关信息。导致 UNDEF 中止的指令位于 R14_UND – 4。
7.1 执行错误指令的可能原因
7.2 处理未定义指令异常
a 如果该指令有效,则检查用于执行的模式(ARM 或 THUMB)是否正确(有效指令的模式不匹配可能会导致未定义指令异常)。
b 如果指令无效,则检查地址或 RAM 是否损坏。
7.3 示例:
如果 VFP 未启用,则在执行浮点运算时处理器会接收到未定义指令异常。CPSR[4:0] = b11011。
导致 UNDEF 异常的指令是位于 0x00007430 的 vldr s0, [r13, 0xc]。
r14_UND = 0x00007434。进入 UNDEF 中止前的模式为 SPSR_UND[4:0] = b11111(系统模式)。
8 数据中止异常 (DABT)
数据中止异常是对无效数据访问的响应。如果异常被确认为数据中止,则第一步应检查 Cortex-R CPU 的数据故障状态寄存器 (DFSR) 的值。
DFSR 寄存器下图显示了 DFSR 寄存器位分配:
通过“S”位 [10] 和“状态位”[0:3] 来了解数据中止的本质。有关状态说明,请参阅下表:
SD 位
SD 位用于区分发生外部中止时的 AXI 解码和从器件错误。该位仅对外部中止有效。对于所有其他类型的中止,该位被设置为零:
0 = AXI 解码错误 (DECERR) 或 AHB 错误导致了中止
1 = AXI 从器件错误 (SLVERR) 或不支持的独占访问导致了中止。示例:使用 AHB 外设端口的独占访问
RW 位
RW 位指示是读取访问还是写入访问导致了中止。
0 = 读取访问导致了中止
1 = 写入访问导致了中止
9 常见的数据中止类型
9.1 后台: 对于 CPU 要访问的任何区域,存储器保护单元 (MPU) 设置必须正确。如果 CPU 发出的地址不处于定义的任何区域之内并且 MPU 被启用,则 MPU 被硬接线以中止访问。也就是说,对未映射到 MPU 中某个区域的地址的所有访问都会产生一个后台故障。
如果后台区域被启用并且访问权限为特权,则不会发生后台故障。MPU
后台故障可能表明堆栈溢出,可以通过分配更多堆栈进行纠正。
9.2 权限:当 MPU 设置阻止区域访问时,可能会发生这种情况。例如,如果模式为用户的应用尝试访问仅限特权模式访问的区域,则会发生权限错误。
示例:
下面显示的写入操作触发了中止。0x08028008 处的存储器位置的 MPU 设置为只读。
如下图所示,DFAR 寄存器显示触发数据中止的地址,因为它是 BTCM(使用 ADFSR 进行验证)处的权限错误(使用 DFSR 进行验证)。R14_abt – 8 (0x000070E0) 指向导致该访问的指令。它显示了一个 STR 操作。
无法从具有器件或严格排序存储器类型属性的区域执行指令。
9.3 同步/异步外部中止:当访问已从 CPU 转移到 AXI/AHB 总线并遇到错误时,会发生此类数据中止。这是出现数据中止时的常见故障类型。如果中止是同步的,则可以使用数据故障地址寄存器 (DFAR) 检查访问时导致数据中止的实际存储器地址,DFAR 保存发生同步中止时的故障地址。
9.4 同步/异步 ECC:如果在 TCM 接口处或高速缓存中检测到 ECC 错误,则会发生此类数据中止。
10 数据中止异常示例
10.1 同步中止异常
一般而言,导致错误的从区域进行“加载”的指令或向存储器进行“存储”的指令是同步的。DFAR 显示了访问的目标地址。此外,如上一节所述,R14_abt – 8 指向导致该访问的指令。
示例 1:从具有 2 位 ECC 错误的存储器位置加载数据
下面显示的读取操作触发了中止。0x08000010 处的数据具有 2 位 ECC 错误。
如上图所示,DFAR 寄存器显示触发数据中止的地址,因为它是 BTCM(使用 ADFSR 进行验证)处的同步 ECC 错误(使用 DFSR 进行验证)。R14_abt – 8 (0x00001F7C) 指向导致该访问的指令。它显示了一个 LDM 操作。
示例 2:将数据写入未实现的存储器位置
下面显示的写入操作触发了中止。地址 0x08100018 超出了有效存储器范围。
如上图所示,DFAR 寄存器显示触发数据中止的地址,因为它是同步中止(使用 DFSR 进行验证)。R14_abt – 8 (0x000070CC) 指向导致该访问的指令。它显示了一个 STR 操作。
图:数据中止发生之前
图:数据中止发生之后
10.2 异步故障
异步故障很难分析,因为我们无法跟踪导致中止的确切位置。我们无法使用同步故障中使用的 DFAR 寄存器。一般而言,向具有“正常”或“器件”存储器属性的区域进行“存储”(从而导致错误)的指令是同步的。
通过 DFSR 寄存器,我们可以检查状态位、SD 位和 RW 位。SD:内部 AXI 解码错误或外部 AXI 从器件错误 RW:指示是读取访问还是写入访问导致了中止。有关详细信息,请阅读上面的第 8 节。
10.3 如何跟踪导致异步数据中止的指令
11 由于 MPU 问题而导致的数据中止
您应该为应用中访问的区域定义有效的 MPU 设置,以便 CPU 能够相应地访问该区域。如果您未定义所用区域的 MPU,该 MPU 可能会导致后台故障数据中止异常,具体取决于使用的是特权访问还是非特权访问:
11.1 对于特权访问:
如果 BR 位(SCTLR Arm 寄存器的第 17 位)被置位,则默认存储器映射将用作任何未命中指定区域的访问的后台区域;如果 BR 位为 0,则对于指定区域之外的任何访问都将发生后台故障异常。
11.2 对于非特权访问:
对于指定 MPU 区域之外的任何访问,都会发生后台故障异常。为了防止针对此类访问发生后台故障异常,请将区域 0 定义为涵盖整个存储器映射的后台区域,然后将其用作定义的 MPU 以外区域的后台区域。
12 预取中止异常
在指令提取导致错误时会发生预取中止 (PABT) 异常。当发生预取中止时,处理器将预取指令标记为无效,但在要执行指令之前不会接收到异常。如果未执行指令,例如因为指令在流水线中时产生分支,则不会发生中止。所有预取中止都是同步的。
未定义指令中止异常和预取中止异常的区别在于:对于预取,CPU 无法从地址中提取指令;对于未定义指令异常,CPU 不知道指令的功能是什么。
可以通过读取指令故障状态寄存器 (IFSR)、指令故障地址寄存器 (IFAR) 和辅助指令故障状态寄存器 (AIFSR) 来分析预取中止的原因。
IFAR 包含 CPU 尝试从中提取指令的地址。IFAR 的内容对于预取中止始终有效,因为所有预取中止都是同步的。
AIFSR 记录有关故障性质和位置的附加信息,例如 ATCM(闪存)或 BTCM (SRAM)。
12.1 预取中止的可能原因
读取指令时检测到 ECC 错误。IFAR 寄存器提供导致检测到错误的地址。辅助 IFSR 指示 ECC 错误的来源。
12.2 处理预取中止异常
对于“权限”故障,请找到从 IFAR 寄存器读取的地址所在的区域。可以检查该区域中是否存在针对代码区域的 MPU 违规情况。(禁止执行设置、器件、严格排序存储器)。
12.3 预取中止异常示例
示例 1:
以下示例演示了调试预取中止的步骤。在这里,CPU 执行滞留在预取中止处理程序中。相关的寄存器值如下所示:
SPSR_Abt:0x8000011F:模式 – (11111) 系统模式。这意味着当中止被触发时,CPU 处于系统模式。
IFSR:0x0000000D:该状态指示权限中止。在 IFAR 中捕获的地址是有效的,是导致中止的实际地址。
IFAR:0x0013F800:该地址位于具有严格排序属性的 MPU 区域下。
示例 2:
示例 2 的相关寄存器值如下所示:
SPSR_Abt:0x600001D1:模式 – (10001) FIQ 模式。这意味着当中止被触发时,CPU 处于 FIQ 模式。
IFSR:0x00000409:该状态指示同步外部中止或 ECC 中止。在 IFAR 中捕获的地址是有效的,是导致中止的实际地址。
IFAR:0x00009000:该地址不包含有效指令,并且具有错误的 ECC 值。
AIFSR:0x00400000:该状态表示错误源来自 ATCM(闪存)。