ARM 中断状态和SVC状态的堆栈切换 (异常)

2023-05-16

ARM 中断状态和SVC状态的堆栈切换 (异常)

 

基础知识:

Arm的寄存器使用规则以及寻址指令:

R13  Sp     堆栈寄存器

R14  Lr     连接寄存器

R15  PC     程序计数器

 

多寄存器寻址:

LDMIA R0!,{R1-R4}

执行以后的效果

R1  <——[R0]

R2  <——[R0+4]

R3  <——[R0+8]

R4  <——[R0+12]

 

堆栈寻址:

STMFD入栈指令,相当于STMDB

STMFD SP!,{R2-R4} 注意这个“!”的使用,在使用和不使用的情况下会有不一样的效果,在后面的代码中具体分析。

[SP-4]  <­——R4

[SP-8]  <——R3 

[SP-12] <——R2   

 

LDMFD出栈指令,相当于LDMIA

LDMFD SP!,{R6-R8}

R6  <——[SP]

R7  <——[SP+4]

R8  <——[SP+8]

 

补充说明:

LDMIA / STMIA Increment After (先操作,后增加)

LDMIB / STMIB Increment Before(先增加,后操作)

LDMDA / STMDA Decrement After (先操作,后递减)

LDMDB / STMDB Decrement Before(先递减,后操作)

 

•STMFD (Push) 块存储- Full Descending stack [STMDB]

•LDMFD (Pop)  块装载- Full Descending stack [LDMIA]

 

这些使用规则以及默认的表达方法是给编译器使用。但是在开发底层语言的同时,有必要知道这个么命名的规则和使用方法。初始化代码和部分关键代码是靠汇编实现。这些代码的理解不免和汇编打交道。因此了解一下基本的汇编规则还是很有帮助。

 

 Arm的工作模式:

Arm的工作模式以及相关寄存器设置:

1,用户模式(usr)      [10000]:ARM处理器正常的程序执行状态

2,快速中断模式(fiq)  [10001]:用于高速数据传输或通道处理

3,外部中断模式(irq)  [10010]:用于通用的中断处理

4,管理模式(svc)      [10011]:操作系统使用的保护模式

5,中止模式(abt)          [10111]:当数据或指令预取终止时进入该模式,用于虚拟存

储及存储保护

6,未定义指令模式(und)[11011]:当未定义的指令执行时进入该模式,用于支持硬件

协处理器的软件仿真

7,系统模式(sys)      [11111]:运行具有特权模式的操作系统任务

 

设置方法:

MRS R14,CPSR       读取

MSR CPSR_c, R14     写入

 

以上几种模式存在的意义在于不同模式下特殊的几个寄存器使用是有区别的。再svc模式下堆栈指针为sp svc中断模式下sp指针为 sp irq等。同样lr连接寄存器的内容也是有不同的含义。再不同模式切换中,lr寄存器保存的地址是由硬件完成,但是表示的是不同模式下的下一条指令,既返模式切换后的返回地址。


每一种模式对应不同的bank register。中文官方翻译不详。但是每一种模式要拥有自己独立的寄存器组。并且每一种模式使用和可见寄存器的数量也是不相同的。

 

模式切换过程中其实只针对spsr进行操作,而未涉及cpsr是的操作。这个过程之所以这样主要是参考ARM cortex A8的TRM。其中这样描述离开异常的情况:

Typically the return instruction is an arithmetic orlogical operation with the S bit set to

1 and rd = r15, so the core copies the SPSR back to theCPSR.

 

也就是说离开异常,从异常情况返回以后会自动把spsr的内同拷贝到cpsr中。所以在执行BL Lr指令之前使用的堆栈其实并位切换。

 

Linux中初始化:

1,  Svc模式的堆栈初始化:

堆栈的概念是给C 语言编译以后的代码使用,因此从head.S一直到C语言的执行,就是start_kernel。

__mmap_switched:

    @注释 1:

    adr r3, __switch_data + 4

 

    ldmia   r3!, {r4, r5, r6, r7}

    cmp r4, r5              @ Copy datasegment if needed

1:  cmpne   r5, r6

    ldrne   fp, [r4], #4

    strne   fp, [r5], #4

    bne 1b

 

    mov fp, #0              @ Clear BSS(and zero fp)

1:  cmp r6, r7

    strcc   fp, [r6],#4

    bcc 1b

   

    @注释 2:

    ldmia   r3, {r4, r5, r6, r7, sp}

    str r9, [r4]            @ Saveprocessor ID

    str r1, [r5]            @ Savemachine type

    str r2, [r6]            @ Saveatags pointer

    bic r4, r0, #CR_A           @ Clear'A' bit

    stmia   r7, {r0, r4}            @Save control register values

    @注释 3:

    b   start_kernel

ENDPROC(__mmap_switched)

 

 

注释1:

    __switch_data这是以个地址。Linker会安排这个地址具体的数值。打开Sysmap可以发现这个数值为:c0008123 t __switch_data

注释 2:

    将r3所指的内容依次装入{r4– r6,sp},这个时候sp指针就有了具体的数值了。

注释 3:

    跳转指令,指向C函数的start_kernel。这时候栈针开始起效。因为C语言编译出来的代码参数传递,调用变量保存等都使用sp指针。这个指针仅仅是给初始化代码所使用。在进程的概念中还有进程堆栈的概念。这时候的sp具体指向的是描述进程结构的结构体task_info。

 

2,irq以及其他模式的初始化:

    /*

     * setup stacks for re-entrant exceptionhandlers

     */

    __asm__ (

    "msr    cpsr_c, %1\n\t"

    "add    r14, %0, %2\n\t"

    "mov    sp, r14\n\t"

    "msr    cpsr_c, %3\n\t"

    "add    r14, %0, %4\n\t"

    "mov    sp, r14\n\t"

    "msr    cpsr_c, %5\n\t"

    "add    r14, %0, %6\n\t"

    "mov    sp, r14\n\t"

    "msr    cpsr_c, %7"

        :

        : "r" (stk),

          PLC (PSR_F_BIT | PSR_I_BIT | IRQ_MODE),

          "I" (offsetof(struct stack,irq[0])),

          PLC (PSR_F_BIT | PSR_I_BIT | ABT_MODE),

          "I" (offsetof(struct stack,abt[0])),

          PLC (PSR_F_BIT | PSR_I_BIT | UND_MODE),

          "I" (offsetof(struct stack,und[0])),

          PLC (PSR_F_BIT | PSR_I_BIT | SVC_MODE)

        : "r14");

    函数:cpu_init()文件:setup.c

    通过msr设置了cpsr寄存器。然后通过mov指令把具体的参数地址写入sp寄存器。

其中offsetof(struct stack, irq[0])这个表达式表示的是偏移量。既是在结构体中的偏移量。

其实在这个函数中初始化的irq堆栈只有4 bytes x 3。这么小的堆栈空间是否可以满足中端的需求。答案是:可以。在中端进入的函数中其实并没有完全使用irq模式下sp_irq指向的堆栈空间。在进入函数中马上有利用了msr指令进行了模式切换,切换到了svc模式。并且放弃了irq的模式。从中端返回也是从svc模式返回,而非irq模式。

代码:

vector_\name:

    .if \correction

    sub lr, lr, #\correction

    .endif

 

    @

    @ Save r0, lr_<exception>(parent PC) and spsr_<exception>

    @ (parent CPSR)

    @

@ 注释 1:

stmia   sp, {r0, lr}        @ save r0,lr

    mrs lr, spsr

    str lr, [sp, #8]            @ save spsr

   

    @

    @ Prepare for SVC32 mode.  IRQs remain disabled.

    @

    mrs r0, cpsr

    eor r0, r0, #(\mode ^ SVC_MODE) 进入SVC模式

    msr spsr_cxsf, r0

 

    @

    @ the branch table mustimmediately follow this code

    @

    and lr, lr, #0x0f

    mov r0, sp

    ldr lr, [pc, lr, lsl #2]

    @注释 2:

    movs    pc, lr         @ branch tohandler in SVC mode

    参照ARM的参考

ENDPROC(vector_\name)

注释 1 :

保存irq模式下的sp和lr指针到前面初始的sp_irq中。记住只有4 bytes x 3大小的空间。在后面的代码中还会看到str  lr, [sp, #8]保存了最后一个参数到sp_irq的空间中。这里要注意:stmia  sp, {r0, lr}这条指令。没有使用“!”号。这样一来尽管指令执行后sp指针指向的地址不会自加。因此在正式切换到SVC模式之前sp_irq所指向的地址并没有变化。这样再次进入中断模式时候,sp_irq不需要调整,可以重复使用。

 

注释 2:

    参照ARM 的芯片设计手册可以发现,离开异常,从异常情况返回以后会自动把spsr的内同拷贝到cpsr中。所以在执行BL Lr指令之前使用的堆栈其实并位切换。

这样一来尽管是中断的模式进入系统,但是由中断模式切换至SVC模式。在SVC模式中完成了中断的后续相应和操作。


文章只是做了学习笔记已被后用,把这些思路罗列出来也给自己以后再回忆查找提供方便。

如果文章中有什么不对的地方,还请高手指正。

谢谢

edwardlu


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ARM 中断状态和SVC状态的堆栈切换 (异常) 的相关文章

随机推荐

  • 新手如何使用立创EDA完成电路设计

    软件简介 xff1a 立创EDA是一款基于浏览器的免费国产EDA绘图工具 下载方式 xff1a 百度 立创EDA 进入主页 xff0c 或主页点击 下载 客户端 xff0c 支持Wndows Luixus Mac系统下载安装 首先 xff0
  • Echart、Excel、highcharts、jfreechart对比

    Echart Excel highcharts jfreechart 柱状图 条形图 折线图 面积图 散点图 气泡图 K 线图 饼图 环形图 雷达图 力导布局图 和弦图 曲面图 地图
  • HAL库和标准库的区别

    本文回答来源于chat gpt4 xff0c 非原创 xff0c 也是我初学过程中所遇到的问题 xff0c 答案分享给大家 xff0c 如有侵权请联系删除 xff1a HAL 库 xff08 Hardware Abstraction Lay
  • 原来手机就能直接制作证件照,我也才知道,再也不用去照相馆了

    证件照选相信是我们大家日常所需 xff0c 但是去照相馆真的有点麻烦 xff0c 尤其是有时候仅仅只是需要换一个背景颜色 xff0c 其实不用这么麻烦 xff0c 现在手机上不仅能换背景颜色 xff0c 还能制作证件照 xff0c 还很简单
  • RTK基站 差分云共享技术,全套高精度定位解决方案

    针对区域内多个移动体高精度定位的需求 xff0c 为了最大程度的降低成本 xff0c FDISYSTEMS为DETA100系列具有联网功能的产品提供了免费的差分共享技术 xff0c 通过该技术可以将单一运载体从CORS服务器获取的差分修正R
  • STM32 Keil编程常见问题解决办法:(一)多行注释时出现红色下划线

    Problem xff1a 在STM32 Keil软件中进行多行注释时出现下图所示现象 xff0c 部分语句出现红色下划线 Solution xff1a 点击Keil软件上的小扳手 选择Text Completion 勾选ENTER TAB
  • 2017秋招求职历程总结

    2017秋招求职历程总结 从小的梦想就是有朝一日能够进入汽车行业工作 xff0c 很幸运刚毕业的第一份工作便实现了此梦想 xff0c 感谢大学遇到的那些人 终于在国庆之前拿到了一份还算满意的offer 9月1号从实习单位离职准备接下来的秋招
  • Win10常用命令:定时关机(shutdown命令)

    文章目录 一 单次 定时关机 xff1a Win 43 R 输入命令 xff1a 二 shutdown命令参数三 每天定时关机 一 单次 定时关机 xff1a Win 43 R 输入命令 xff1a 倒计时关机 xff1a shutdown
  • 如何实现超大文件(60G)传输给别人?

    2022 4 25 今天Ken问我要我工位上的一个虚拟机环境 xff0c 整个文件夹拷给他 但是这个CentOS的环境有60个G xff0c 我的U盘只有45G 想了几个办法 xff1a 压缩包 xff1a 用WinRAR压缩成压缩包 xf
  • CPU两大架构:X86与ARM的区别

    1 CPU 架构 Central Processing Unit Architecture X86 ARM MIPS PowerPC IA64 AMD64 x86 64 x64 是64位的CPU架构 区分ARM64 2 复杂指令集计算机CI
  • Linux(UOS、Ubuntu)虚拟机和Windows物理机之间无法复制粘贴

    我的UOS虚拟机和主机之间无法复制粘贴 xff0c 解决方案如下 xff1a 1 先更新一下软件列表 span class token function sudo span span class token function apt get
  • CMake、CMakeLists.txt

    2022 06 02 xff0c 今天开始研究cmake 不间断更新 一 说明 0 官方文档网址 xff1a www cmake org 1 cmake的定义 xff1a 高级编译配置工具 当多个人用不同的语言或者编译器开发一个项目 xff
  • ECMAScript6 入门 数组的扩展

    数组的扩展 1 xff1a 扩展运算符 xff1a 好比rest参数的逆运算 xff0c 将一个数组转换为用逗号分隔的参数序列 主要应用于函数调用 xff0c 将一个数组 xff0c 变为参数序列 如果扩展运算符后面是一个空的数组 xff0
  • CSDN排名记录

    文章目录 表格记录文字记录刷题记录 表格记录 时间 属性周排名总排名原创文章数收藏量粉丝数铁粉数2023年5月12日 xff1a 第20周3175593128893843912572023年5月6日 xff1a 第19周3211559128
  • 虚拟机使用的是此版本 VMware Workstation 不支持的硬件版本。 模块“Upgrade”启动失败。 未能启动虚拟机。

    问题 xff1a 虚拟机使用的是此版本 VMware Workstation 不支持的硬件版本 模块 Upgrade 启动失败 未能启动虚拟机 分析 xff1a 该虚拟机环境之前使用的VMware版本与你所使用的VMware版本不一致 大概
  • C++基础

    文章目录 推荐速成视频一 数据的输入输出cin xff1a 输入cin getline xff1a 读取一行内容cout xff1a 输出I O格式控制 二 C 43 43 函数重载三 类和对象1 struct与class 1 struct
  • Ch1. 逻辑结构、存储结构、时间复杂度、空间复杂度

    文章目录 一 逻辑结构 与 存储结构 1 逻辑结构 1 集合结构 2 线性结构 3 树形结构 4 图形结构 2 存储结构 物理结构 1 顺序存储 2 链式存储 3 索引存储 4 散列存储 概念 二 时间复杂度 空间复杂度
  • Ch2.线性表

    文章目录 第2章 线性表 一 顺序表 1 顺序表的定义 初始化 静态分配 动态分配 2 顺序表的插入 3 顺序表的删除 二 链表 1 单链表 1 单链表结点的数据类型定义 2 单链表的建立 头插法
  • FreeRTOS的源代码个人分析(基于KEIL下STM32F103的Demo) 四

    开始任务的实现分析 xff1a xPortStartScheduler 函数 FreeRTOS里开始任务是在main里调用vTaskStartScheduler函数来开始任务的 xff0c 在调用这个函数后 xff0c 系统会先自动的创建一
  • ARM 中断状态和SVC状态的堆栈切换 (异常)

    ARM 中断状态和SVC状态的堆栈切换 xff08 异常 xff09 基础知识 xff1a Arm的寄存器使用规则以及寻址指令 xff1a R13 Sp 堆栈寄存器 R14 Lr 连接寄存器 R15 PC 程序计数器 多寄存器寻址 xff1