【ARMv8M Cortex-M33 系列 7.3 -- EXC_RETURN 与 LR 及 PC 的关系详细介绍】

这篇具有很好参考价值的文章主要介绍了【ARMv8M Cortex-M33 系列 7.3 -- EXC_RETURN 与 LR 及 PC 的关系详细介绍】。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


请阅读【嵌入式开发学习必备专栏 之 ARM Cortex-Mx专栏】


背景

接着上篇文章:【ARMv8M Cortex-M33 系列 7.2 – HardFault 问题定位 1】,后面定位到是在cortex-m33/context_gcc.S执行完 BX Lr之后就发生了 HardFault,通过JLink 发现 LR的值为0xfffffffd 所以又继续调查了EXC_RETURN 的具体含义。

pendsv_exit:
    /* restore interrupt */
    MSR PRIMASK, r2

    ORR lr, lr, #0x04
    BX  lr

EXC_RETURN 与 LR 及 PC

在 ARM Cortex-M33(以及其他Cortex-M系列)处理器中,异常返回值(EXC_RETURN)用于指示当处理器完成异常处理(例如中断或系统调用)后应如何返回到异常发生前的状态。这个值被自动加载到LR(链接寄存器)中,在异常返回时由处理器使用。

当发生异常时,处理器会自动将当前的程序状态保存到堆栈中,包括程序计数器(PC)的值和其他重要寄存器,并将特定的值加载到LR。这个LR中的值称为EXC_RETURN,它决定了异常返回时处理器的行为,如使用哪个堆栈指针(MSP或PSP),以及是否返回到Thread或Handler模式。

EXC_RETURN 的值如下:

  • 0xFFFFFFF1:返回到Handler模式,使用MSP(主堆栈指针)作为堆栈指针。
  • 0xFFFFFFF9:返回到Thread模式,使用MSP作为堆栈指针。
  • 0xFFFFFFFD:返回到Thread模式,使用PSP(进程堆栈指针)作为堆栈指针。
  • 0xFFFFFFBC 的设置表示返回时,处理器将:
    • 使用 PSP 作为栈指针,
    • 返回到线程模式而不是异常模式(如中断),
    • 恢复浮点上下文。

此外,当在硬件浮点单元(FPU)支持的设备上编译代码时,还会有以下EXC_RETURN值:

  • 0xFFFFFFE1:返回到Handler模式,使用MSP作为堆栈指针,并且需要恢复浮点状态。
  • 0xFFFFFFE9:返回到Thread模式,使用MSP作为堆栈指针,并且需要恢复浮点状态。
  • 0xFFFFFFED:返回到Thread模式,使用PSP作为堆栈指针,并且需要恢复浮点状态。

在异常处理完毕后,处理器将执行一个异常返回操作,这个操作会根据LR中的EXC_RETURN值来从堆栈恢复之前保存的状态,并将控制权交回到异常发生前的代码。这个恢复过程包括将之前保存在堆栈上的PC值重新加载到PC寄存器,这样程序就会从中断前被中断的点继续执行。

在实践中,异常处理函数通常不需要显式地处理这些细节,因为处理器硬件和操作系统的异常管理机制会自动处理这些过程。当开发裸机应用或自己的操作系统时,理解EXC_RETURN和异常返回机制将非常重要。在使用操作系统(如FreeRTOS或其他RTOS)时,上下文切换和异常返回通常由操作系统管理。

在异常处理函数中,你可以检查LR的值来确定异常发生时的上下文。例如,在异常处理函数中,你可以使用类似于以下的代码:

uint32_t lr_value; 
asm("MOV %0, lr" : "=r" (lr_value)); 
// lr_value 现在包含了 EXC_RETURN 值 

或者,如果你需要在你的异常处理函数中手动操作LR以改变返回行为,你也可以编写相应的汇编代码,但通常这样的操作是不必要的,而且需要对ARM架构有深入的理解。

cortex-m33 从异常返回后 各个寄存器出战顺序

由于上面问题涉及到了入栈出栈的问题,所以又温习了一遍栈的内容:

在 ARM Cortex-M33 微控制器上,从异常(如中断)返回时,处理器会从堆栈中出栈(pop)寄存器的值来恢复到异常发生之前的状态。这一过程发生在异常处理完成后,当执行异常返回序列时。异常返回过程是自动的,由处理器硬件管理。

当异常发生时,处理器会将当前的上下文(某些寄存器的值)压入当前使用的堆栈中(MSP 或 PSP)。在从异常返回时,处理器将这些值出栈到寄存器中。这些寄存器包括程序计数器(PC)、链接寄存器(LR)、程序状态寄存器(xPSR)以及可能的一些通用寄存器。

异常返回时的出栈顺序与入栈顺序相反。入栈顺序通常如下:

  1. xPSR 2. 返回地址(PC)
  2. LR
  3. R12
  4. R3
  5. R2
  6. R1
  7. R0
  8. 如果有浮点状态,会进一步保存 S16-S31 浮点寄存器

因此,异常返回时寄存器的出栈顺序是:

  1. R0
  2. R1
  3. R2
  4. R3
  5. R12
  6. LR
  7. PC(返回地址)
  8. xPSR
  9. 如果有浮点状态,会进一步恢复 S16-S31 浮点寄存器

在异常返回序列结束时,处理器从堆栈恢复了这些寄存器的值,并跳转到返回地址(之前的PC)继续执行程序。

值得注意的是,这里所说的 LR 寄存器在异常发生时会被自动设置为一个特殊的值(EXC_RETURN),该值包含了关于返回时所需使用的堆栈指针(MSP 或 PSP)以及是否使用了浮点寄存器等信息。异常返回时,处理器会检查 LR 中的 EXC_RETURN 值,以决定如何恢复上下文并从哪个堆栈指针出栈。

此外,浮点寄存器(如果有)的保存和恢复,取决于浮点单元(FPU)的使用以及处理器的配置。如果在异常发生时使用了 FPU,则会额外保存和恢复 S16-S31 寄存器。如果 FPU 未启用或未使用,则不会保存和恢复这些浮点寄存器。

ARM 栈增长方式

在 ARM Cortex-M33 微控制器(以及所有 ARM Cortex-M 系列处理器)中,栈是向下增长的。这意味着,当数据被压入栈(push)时,栈指针(SP)会递减;相应地,当数据从栈中弹出(pop)时,栈指针会递增

这个行为符合大多数现代处理器的常见约定,即栈空间的起始地址通常较高,随着数据的增加,栈指针向着较低的内存地址方向移动。这种设计可以有效利用内存空间,因为栈的最大尺寸通常是不确定的,而向下增长可以确保栈不会与静态分配或动态分配的内存空间发生冲突。

thread.c 中可以看到对栈的具体使用选择:

static rt_err_t _rt_thread_init(struct rt_thread *thread,
                                const char       *name,
                                void (*entry)(void *parameter),
                                void             *parameter,
                                void             *stack_start,
                                rt_uint32_t       stack_size,
                                rt_uint8_t        priority,
                                rt_uint32_t       tick)
{
    /* init thread list */
    rt_list_init(&(thread->tlist));

    thread->entry = (void *)entry;
    thread->parameter = parameter;

    /* stack init */
    thread->stack_addr = stack_start;
    thread->stack_size = stack_size;

    /* init thread stack */
    rt_memset(thread->stack_addr, '#', thread->stack_size);
#ifdef ARCH_CPU_STACK_GROWS_UPWARD
    thread->sp = (void *)rt_hw_stack_init(thread->entry, thread->parameter,
                                          (void *)((char *)thread->stack_addr),
                                          (void *)_rt_thread_exit);
#else
    thread->sp = (void *)rt_hw_stack_init(thread->entry, thread->parameter,
                                          (rt_uint8_t *)((char *)thread->stack_addr + thread->stack_size - sizeof(rt_ubase_t)),
                                          (void *)_rt_thread_exit);

所以宏ARCH_CPU_STACK_GROWS_UPWARD 处的内容不会编译进去,使用的是#else分支。文章来源地址https://www.toymoban.com/news/detail-822603.html

到了这里,关于【ARMv8M Cortex-M33 系列 7.3 -- EXC_RETURN 与 LR 及 PC 的关系详细介绍】的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【ARMv8M Cortex-M33 系列 1.1 -- SAU Non-secure Callable(NSC) 介绍 】

    请阅读 【嵌入式开发学习必备专栏 之Cortex-M33 专栏】 ARMv8-M 架构引入了 TrustZone 技术,它提供了一种机制来实现在单个处理器内部的安全隔离。这项技术定义了两种状态: 安全状态 (Secure state)和 非安全状态 (Non-secure state)。在此架构下,可以同时运行安全和非安全代码

    2024年02月04日
    浏览(43)
  • 【ARMv8M Cortex-M33 系列 7.4 -- 如何使能 usagefault | memmange fault | bus fault 中断】

    请阅读 【嵌入式开发学习必备专栏 之 ARM Cortex-Mx专栏】 由于文章【ARMv8M Cortex-M33 系列 7.2 – HardFault 问题定位 1】 中提到了HardFault 的发生是由于其它异常所升级导致的,所以就需要调查下如何是能其它异常中断。 在 ARM Cortex-M33 核心上启用 UsageFault 、 MemManageFault 和 BusFault 异

    2024年01月20日
    浏览(51)
  • 【ARMv8M Cortex-M33 系列 3 -- RT-Thread renesas/ra4m2-eco 移植编译篇】

    请阅读 【嵌入式开发学习必备专栏 之Cortex-M33 专栏】 本文以瑞萨的 ra4m2-eco 为例介绍如何下载rt-thread 及编译的设置。 RT-Thread 代码下载 : git clone 路径 :https://github.com/RT-Thread/rt-thread 代码下载下来后如下: 此外还需自行下载一套编译 arm gcc 编译工具,如 gcc-arm-none-eabi 。 编

    2024年02月03日
    浏览(53)
  • 【ARM Cortex-M 系列 3 番外篇 -- ARMv6, ARMv7, ARMv8, ARMv9 架构差异及精简指令集 与 复杂指令集 介绍】

    上篇文章:ARM Cortex-M 系列 2.1 – RT-Thread Cortex-M7 异常处理及 hardfault 处理分析 ARM架构是一种处理器架构,全称为高级精简指令集计算机(Advanced RISC Machine)。它是英国ARM公司设计的一种精简指令集( RISC )处理器架构,和复杂指令集( CISC )处理器架构相对。 CISC 与 RISC 差异

    2024年02月08日
    浏览(46)
  • 【ARM Cortex-M 系列 1.1 -- Cortex-M33 与 M4 差异 详细介绍】

    请阅读 【嵌入式开发学习必备专栏 之 Cortex-Mx 专栏】 在移植 RT-Thread 到 瑞萨RA4M2(Cortex-M33)上时,遇到了hardfault 问题,最后使用了Cortex-M4中的调度相关的函数后,OS 可以正常调度了。所以这里做下 M33与 M4的关系梳理。 ARM Cortex-M33 和 Cortex-M4 都是 ARM 公司设计的32位RISC微处理

    2024年01月21日
    浏览(46)
  • 【ARM Cortex-M 系列 1 -- Cortex-M0, M3, M4, M7, M33 差异】

    请阅读 【ARM Coresight | AMBA BUS| Armv8/v9 | GCC 专栏导读】 下篇文章:ARM Cortex-M 系列 2 – CPU 之 Cortex-M7 介绍 Cortex-M0/M0+ 介绍 Cortex-M0 是 ARM 公司推出的一款微控制器(MCU)核心。这个核心是基于 ARMv6-M 架构设计的, 只支持 56 条指 令的小指令集,大部分指令是 16 位指令, 是 ARM Cor

    2024年02月17日
    浏览(46)
  • 【ARM Cortex-M 系列 1 -- Cortex-M0, M3, M4, M7, M33, M35P 差异】

    请阅读 【ARM Coresight | AMBA BUS| Armv8/v9 | GCC 专栏导读】 下篇文章:ARM Cortex-M 系列 2 – CPU 之 Cortex-M7 介绍 Cortex-M0/M0+ 介绍 Cortex-M0 是 ARM 公司推出的一款微控制器(MCU)核心。这个核心是基于 ARMv6-M 架构设计的, 只支持 56 条指 令的小指令集,大部分指令是 16 位指令, 是 ARM Cor

    2024年02月05日
    浏览(44)
  • NXP i.MX 8M Mini工业核心板硬件说明书(四核ARM Cortex-A53 + 单核ARM Cortex-M4,主频1.6GHz)

    创龙科技SOM-TLIMX8是一款基于NXP i.MX 8M Mini的四核ARM Cortex-A53 + 单核ARM Cortex-M4异构多核处理器设计的高端工业级核心板,ARM Cortex-A53(64-bit)主处理单元主频高达1.6GHz,ARM Cortex-M4实时处理单元主频高达400MHz。处理器采用14nm最新工艺,支持1080P60 H.264视频硬件编解码、1080P60 H.265视频硬

    2024年02月11日
    浏览(50)
  • NXP i.MX 8M Plus工业开发板硬件说明书( 四核ARM Cortex-A53 + 单核ARM Cortex-M7,主频1.6GHz)

    本文主要介绍创龙科技TLIMX8MP-EVM评估板硬件接口资源以及设计注意事项等内容。 创龙科技TLIMX8MP-EVM是一款基于NXP i.MX 8M Plus的四核ARM Cortex-A53 + 单核ARM Cortex-M7异构多核处理器设计的高性能工业评估板,由核心板和评估底板组成。ARM Cortex-A53(64-bit)主处理单元主频高达1.6GHz,ARM

    2024年02月11日
    浏览(88)
  • ARM 学习笔记2 初识Cortex-M33与STM32G4

    ARM Cortex-M系列处理器的差异与联系:【ARM Cortex-M 系列 1 – Cortex-M0, M3, M4, M7, M33 差异】 两本书籍的英文版和中文版 Definitive Guide to Arm® Cortex®-M23 and Cortex-M33 Processors Arm Cortex-M23和Cortex-M33微处理器权威指南 ST的介绍页 Arm® Cortex®-M33概述 STM32G474RE 采用STM32G474RE MCU的STM32 Nucleo-64开

    2024年01月25日
    浏览(51)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包