【嵌入式开发】ARM 处理器工作模式 及 修改方法 ( 处理器模式

您所在的位置:网站首页 寄存器v 【嵌入式开发】ARM 处理器工作模式 及 修改方法 ( 处理器模式

【嵌入式开发】ARM 处理器工作模式 及 修改方法 ( 处理器模式

#【嵌入式开发】ARM 处理器工作模式 及 修改方法 ( 处理器模式 | 来源: 网络整理| 查看: 265

一. 处理器工作模式相关介绍

1. 处理器模式简介 (1) 处理器工作模式分类(2) 处理器不同工作模式区别(3) Linux 系统运行的模式(4) 特权模式 说明(5) 异常模式(6) 系统模式2. 处理器模式 改变 (1) 处理器工作模式 改变 的前提条件(2) 处理器工作模式 修改方式 ( 程序状态字寄存器 工作模式修改 )(3) 程序状态字寄存器 位 类型(4) 程序状态字寄存器修改流程二. 处理器工作模式修改 代码示例 1. 汇编代码编写 (1) 代码 逻辑 分析(2) 汇编代码示例2. 链接器脚本3. Makefile 编译脚本4. 编译输出可执行文件

本博客的参考文章及相关资料下载 :

1.ARM 架构参考手册 ( ARM Architecture Reference Manual ) : https://download.csdn.net/download/han1202012/83246412.汇编参考手册 : https://download.csdn.net/download/han1202012/83283753.本博客代码下载 : https://download.csdn.net/download/han1202012/10400369一. 处理器工作模式相关介绍

参考手册 : A2.2 Processor modes

1.处理器工作模式位置 : ARM Architecture Reference Manual [ A 2.2 ] 章节;2.参考手册下载地址 : https://download.csdn.net/download/han1202012/83246411. 处理器模式简介(1) 处理器工作模式分类

处理器的 七种 工作模式 :

1.User ( 用户模式 usr ) : 普通的应用运行的模式 ; 2.FIQ ( 快速中断模式 fiq ) : 该模式下支持数据的高速传输 ;3.IRQ ( 普通中断模式 irq ) : 该模式常用于处理普通的中断 ; 4.Supervisor ( 管理模式 svc ) : 操作系统使用的一种保护模式 , 本节 BootLoader 就是需要设置这种 svc 模式; 5.Abort ( 终止模式 abt ) : 实现虚拟内存 和 存储器保护 ;6.Undefined ( 未定义模式 und ) : 硬件协处理器 的 软件仿真支持, 当执行的指令处理器不支持, 那么会进入该模式; 7.System ( 系统模式 ) : 该模式用于运行具有特权的操作系统任务, ARMv4 以上的架构才有; (2) 处理器不同工作模式区别

处理器 工作模式 区别 :

1.可运行的指令不同 : 不同的处理器工作模式下 可 运行的 处理器指令 是不同的; 2.可访问的寄存器不同 : 不同处理器模式下 可访问的 寄存器 也是有区别的; 3.分级别处理 : 7 种工作模式级别不同, 操作系统 一般在级别较高的模式下运行, 应用程序在级别较低的模式下运行; 4.用户模式说明 : ( 1 ) 应用运行 : 绝大多数 应用程序都运行在用户模式 ( User ) 下; ( 2 ) 资源限制 : 在 ① 用户模式下, 应用无法访问受保护的系统资源 , ② 系统资源的使用 是在操作系统的控制下; ( 3 ) 无法修改模式 : 在 用户模式 下, 应用也无法修改 处理器 的工作模式 ; (3) Linux 系统运行的模式

Linux 操作系统运行模式 :

1.应用程序 : Linux 系统的应用程序运行在 User 用户模式下; 2.内核 : Linux 系统 内核 运行在 Supervisor 管理模式下 ; (4) 特权模式 说明

特权模式 :

1.特权概念 : 除 用户模式 外, 其它的 6 种模式 都是特权模式 ; 2.特权模式 的 功能 : 特权模式 比 用户模式 拥有更大的权限, 可 ① 访问系统资源, ② 修改处理器工作模式 ; ( 1 ) 资源访问 : 特权模式 拥有访问系统资源的权限 ; ( 2 ) 模式修改 : 特权模式 下 可以 修改 处理器的工作模式 ; 3.五种异常模式 : 在 6 种 特权模式中, 有 5 种 是 异常模式 , 当对应的异常发生的时候, 就会进入对应的工作模式 ; 4.异常模式寄存器 : 每种异常模式都有一些附加的寄存器, 当异常发生的时候, 避免影响用户模式的状态; (5) 异常模式

五种 处理器工作模式 ( 异常模式 ) 对应的异常类型 :

1.FIQ ( 快速中断模式 fiq ) : 该模式下支持数据的高速传输 , 对应异常类型 为 快速中断 异常;2.IRQ ( 普通中断模式 irq ) : 该模式常用于处理普通的中断 , 对应异常类型 为 普通中断 异常 ; 3.Supervisor ( 管理模式 svc ) : 操作系统使用的一种保护模式 , 本节 BootLoader 就是需要设置这种 svc 模式, 对应异常类型 为 Reset 和 软中断 异常 ; 4.Abort ( 终止模式 abt ) : 实现虚拟内存 和 存储器保护 , 对应异常类型 为 预取指令失败 和 读取数据失败 异常 ;5.Undefined ( 未定义模式 und ) : 硬件协处理器 的 软件仿真支持, 当执行的指令处理器不支持, 那么会进入该模式, 对应异常类型 为 无法识别指令 异常;

七种 异常类型 对应的 处理器工作模式 : ARM 架构 支持 七种类型的异常,

1.Reset : 处理器在工作时, 突然 按下重启键, 就会触发该异常 , 该异常对应的处理器工作模式为 svc 模式;2.Undefined instructions : 处理器无法识别指令的异常, 处理器执行的指令是有规范的, 如果 尝试执行 不符合要求的指令, 就会进入到该异常指令对应的地址中, 该异常对应的处理器工作模式为 und 模式; 3.Software interrupt (SWI) : 软中断, 软件中需要去打断处理器工作, 可以使用软中断来执行 , 该异常对应的处理器工作模式为 svc 模式; 4.Prefetch Abort (instruction fetch memory abort) : 预取指令失败, ARM 在执行指令的过程中, 要先去预取指令准备执行, 如果预取指令失败, 就会产生该异常, 该异常对应的处理器工作模式为 abt 模式; 5.Data Abort (data access memory abort) : 读取数据失败, 该异常对应的处理器工作模式为 abt 模式;6.IRQ (interrupt) : 普通中断 , 该异常对应的处理器工作模式为 irq 模式;7.FIQ (fast interrupt) : 快速中断, 快速中断要比普通中断响应速度要快一些, 该异常对应的处理器工作模式为 fiq 模式;(6) 系统模式

系统模式 :

1.进入方式 : 任何异常都无法进入 系统 模式 ; 2.寄存器 : 从下面的寄存器截图可以看出, 系统模式 可 使用的 寄存器, 与 用户模式 可访问的寄存器 是一样的; 3.拥有特权 : 系统模式也是一种特权模式, 不受用户模式限制影响, 4.模式存在的目的 : 系统模式 主要 服务于 需要访问系统资源的 操作系统任务, 避免使用 与 异常相关的附加寄存器; ( 1 ) 避免被异常干扰 : 主要是为了 保证 任务状态, 避免 被 发生的异常 干扰 ; 2. 处理器模式 改变(1) 处理器工作模式 改变 的前提条件

修改 处理器 工作模式 的 前提条件 :

1.软件控制 : 在 软件控制下, 可以修改处理器的工作模式 ; 2.外部中断 : 外部中断也会改变处理器的工作模式; 3.异常处理 : 当异常发生的时候, 也会修改处理器的工作模式 ; 4.BootLoader 工作模式 : BootLoader 工作在 svc 模式 下, 该模式比较高级, 可以 访问较多的寄存器资源 , 执行更多的处理器指令 ; 5.如何修改工作模式 : 修改 程序状态 寄存器 ( CPSR ) 中的 0 ~ 4 位 即可改变处理器工作模式; 6.修改CPSR值 : 修改的 程序状态寄存器 0 ~ 4 位的值 为, 下面表中的 模式代码. 即 每行 第三列的 二进制码 ; 7.处理器工作模式 对应的 M 位 ( CPRS 0 : 4 ) 值 以及其对应的 可使用的寄存器 : (2) 处理器工作模式 修改方式 ( 程序状态字寄存器 工作模式修改 )

参考手册 : A2.5 Program status registers

1.处理器工作模式位置 : ARM Architecture Reference Manual [ A 2.5 ] 章节;2.参考手册下载地址 : https://download.csdn.net/download/han1202012/8324641

程序状态字寄存器 :

1.寄存器内容 : 该寄存器 中 包含 ① 状态码标志位, ② 中断标志位, ③ 当前处理器工作模式 和 其它一些 ④ 状态 与 ⑤ 控制信息 ; 2.CPSR 寄存器 : 全称 Current Program Status Register ( 当前程序状态字寄存器 ), 保存的是当前的程序状态 ; 3.SPSR 寄存器 : 全称 Saved Program Status Register ( 程序状态保存寄存器 ), 每个异常都有对应的独立的 SPSR 寄存器, 当异常发生的时候, 先将 CPSR 寄存器中的值 保存到 SPSR 寄存器中, 以便 异常处理完毕后 再回到原来断点处 继续运行 ; 4.SPSR 寄存器分布 : 用户模式 和 系统模式 没有 对应的 SPSR 寄存器, 只有 5 种 异常模式才有对应的 SPSR 寄存器 ; ( 1 ) SPSR 寄存器读写 : 在 用户模式 或 系统模式 读写 SPSR 指令 会出现不可预测的错误或行为 ; (3) 程序状态字寄存器 位 类型

参考手册 : A2.5 Program status registers

1.处理器工作模式位置 : ARM Architecture Reference Manual [ A 2.5 ] 章节;2.参考手册下载地址 : https://download.csdn.net/download/han1202012/8324641

程序状态字寄存器 位 类型简介 :

1.特权位 : 在 特权模式 下可进行修改 的 位数, 用户模式下不能修改特权位, 如 A, I , F, 和 M ( 0 :4 ) 位; 2.用户可写位 : 任何模式都可以修改的 数据位, 如 N, Z, C, V, Q, GE[ 3 : 0 ], E 数据位;3.执行状态位 : 可以从 任何特权模式修改, 用户模式不能修改 ; J 和 T 两位 是运行状态位, 在 ARM 状态下总是 0 ; ( 1 ) CPSR 运行状态位 : 使用 MSR 特权指令 将通用寄存器的值 保存到 CPSR 中, J 和 T 两位必须设置为 0 , 否则会出现不可预知错误; ( 2 ) SPSR 运行状态位 : 在 上面 的 限制中, 只针对 CPSR 寄存器, SPSR 没有这个限制, 4.保留位 : 为之后的功能扩展保留的位数 ; ( 1 ) 读取 : 保留位 读取时 都当做 0 值; ( 2 ) 写入 : 不能向 保留位 写出实际数据 ; (4) 程序状态字寄存器修改流程

参考手册 : arm汇编手册(中文版).chm

1.本节使用的汇编指令 : BIC, ORR, MSR, MRS;2.arm汇编手册下载地址 : https://download.csdn.net/download/han1202012/8328375

修改程序状态字寄存器 使用到的汇编指令 :

1.将处理器工作模式位 设置 0 : 将 CPRS 程序状态字 寄存器 中的 0 ~ 4 位 设置为 0 , 注意 CPRS 不能直接操作 ; 使用 BIC 指令进行设置; ( 1 ) BIC 汇编指令 语法 : bic 语法格式 bic , , , dest 存放位清除结果, op1 是被清除的对象, op2 是掩码; ( 2 ) BIC 指令 示例 : bic r0, r0, #0b1011, 清除 r0 中的 第0, 1, 3 位, 其余位保持不变, 结果放入 r0 中;( 3 ) 使用注意点 : dest op1 都不能使用立即数, 必须使用寄存器, op2 可以使用立即数; ( 4 ) 立即数进制 : 此处的的立即数必须使用二进制形式 ; 2.为 处理器工作模式位 设置 1 : 将 CPRS 程序状态字 寄存器 中的 0 ~ 4 位 设置为 指定的二进制数字 , 注意 CPRS 不能直接操作 ; 使用 orr 指令 进行设置 ; ( 1 ) ORR 汇编指令 语法 : ORR{条件}{S} , , , dest 结果是 op 1 与 op 2 进行或运算的结果; ( 2 ) ORR 指令 说明 : dest 必须是寄存器, 操作数 1 ( op 1 ) 必须是寄存器, 操作数 2 ( op 2 ) 可以是 ① 寄存器 ② 被移位寄存器 ③ 立即数; ( 3 ) ORR 示例 : ORR R0, R0, #3, 将 立即数 3 与 R0 寄存器中的值 进行 或 运算, 然后将运算结果存放到 R0 中;3.程序状态字寄存器 ( CPSR 和 SPSR ) 访问指令 : 使用 MRS MSR 指令, 程序状态字 不能使用 通用寄存器的语句 如 MOV 等访问, 必须使用 程序状态寄存器的 专用指令 读写; ( 1 ) 程序状态字寄存器 访问 流程 : 程序状态字寄存器不能直接访问, 需要先将程序状态字寄存器内容导出到通用寄存器中, 才能进行操作 , 不能直接修改 CPSR 和 SPSR 中的值 ; ( 2 ) MRS 指令 : MRS R0, CPSR , 将 CPRS 寄存器的值 复制 到 R0 寄存器中; ( 3 ) MSR 指令 : MSR CPSR, R0, 将 R0 寄存器中的值 设置 到 CPSR 寄存器中 ; 4.流程总结 : ( 1 ) 导出 CPSR 寄存器值 : 使用 MRS 将 CPSR 寄存器的值导出到通用寄存器中 ; ( 2 ) 将工作模式位置 0 : 将导出的 CPSR 寄存器的值的 0 ~ 4 位 设置为 0 ; ( 3 ) 将工作模式位置 1 : 将导出的 CPSR 寄存器的值的 0 ~ 4 位 设置 对应 的 模式代码 ; ( 4 ) 将设置好的 CPSR 寄存器值设置到 寄存器中 : 使用 MSR 指令, 将 在通用寄存器中 设置好的 CPSR 寄存器值 设置回 CPSR 寄存器中 ; 二. 处理器工作模式修改 代码示例1. 汇编代码编写(1) 代码 逻辑 分析

代码 逻辑 分析 :

1.设置 处理器工作模式 时机 : 进行 处理器工作模式 设置 是在 开发板上电后, 对应的 reset 异常向量处; 2.设置 指令标号 : 设置一个指令标号, 在标号下定义一组汇编指令, 当需要执行这一组指令的时候, 在跳转到该标号即可; ( 1 ) 定义标号 : set_svc :, 在标号下定义一组汇编指令; 3.导出 CPSR 寄存器值 : 使用 MRS 指令, 即 mrs r0 cpsr 将 CPSR 寄存器中的值导出到 R0 寄存器中; 4.将 R0 中的 M 位 清 0 : 在 R0 中将从 CPSR 中导出的寄存器值 对应的 0 ~ 4 位 清0, 使用 bic r0, r0, #0x1f, 将 R0 寄存器的值 与 #0x1f 进行 与操作, 即 后5 位都设置成0, 然后将 与 操作的结果保存到 R0 寄存器中 ; 5.将 R0 中的 M 位 设置 模式代码 : 在下图中, svc 的模式代码时 0b10011 ( 二进制 ), 即 0x13 ( 十六进制 ), 使用 orr r0, r0, #0xd3 语句设置, 将 R0 寄存器中的值 与 0x13 进行 或操作, 将 或操作的结果 存放到 R0 寄存器中; 6.将值写回 CPSR 寄存器 : 使用 MSR 指令 msr cpsr, r0 , 将处理完的 CPSR 寄存器值 设置给 CPSR 寄存器;(2) 汇编代码示例

汇编代码示例 :

@**************************** @File:start.S @ @BootLoader 初始化代码 @**************************** .text @ 宏 指明代码段 .global _start @ 伪指令声明全局开始符号 _start: @ 程序入口标志 b reset @ reset 复位异常 ldr pc, _undefined_instruction @ 未定义异常, 将 _undefined_instruction 值装载到 pc 指针中 ldr pc, _software_interrupt @ 软中断异常 ldr pc, _prefetch_abort @ 预取指令异常 ldr pc, _data_abort @ 数据读取异常 ldr pc, _not_used @ 占用 0x00000014 地址 ldr pc, _irq @ 普通中断异常 ldr pc, _fiq @ 软中断异常 _undefined_instruction: .word undefined_instruction @ _undefined_instruction 标号存放了一个值, 该值是 32 位地址 undefined_instruction, undefined_instruction 是一个地址 _software_interrupt: .word software_interrupt @ 软中断异常 _prefetch_abort: .word prefetch_abort @ 预取指令异常 处理 _data_abort: .word data_abort @ 数据读取异常 _not_used: .word not_used @ 空位处理 _irq: .word irq @ 普通中断处理 _fiq: .word fiq @ 快速中断处理 undefined_instruction: @ undefined_instruction 地址存放要执行的内容 nop software_interrupt: @ software_interrupt 地址存放要执行的内容 nop prefetch_abort: @ prefetch_abort 地址存放要执行的内容 nop data_abort: @ data_abort 地址存放要执行的内容 nop not_used: @ not_used 地址存放要执行的内容 nop irq: @ irq 地址存放要执行的内容 nop fiq: @ fiq 地址存放要执行的内容 nop reset: @ reset 地址存放要执行的内容 bl set_svc @ 跳转到 set_svc 标号处执行 set_svc: mrs r0, cpsr @ 将 CPSR 寄存器中的值 导出到 R0 寄存器中 bic r0, r0, #0x1f @ 将 R0 寄存器中的值 与 #0x1f 立即数 进行与操作, 并将结果保存到 R0 寄存器中, 实际是将寄存器的 0 ~ 4 位 置 0 orr r0, r0, #0xd3 @ 将 R0 寄存器中的值 与 #0xd3 立即数 进行或操作, 并将结果保存到 R0 寄存器中, 实际是设置 0 ~ 4 位 寄存器值 的处理器工作模式代码 msr cpsr, r0 @ 将 R0 寄存器中的值 保存到 CPSR 寄存器中2. 链接器脚本

gboot.lds 链接器脚本 代码解析 :

1.指明输出格式 ( 处理器架构 ) : 使用 OUTPUT_ARCH(架构名称) 指明输出格式, 即处理器的架构, 这里是 arm 架构的, OUTPUT_ARCH(arm) ;2.指明输出程序的入口 : 设置编译输出的程序入口位置, 语法为 ENTRY(入口位置), 在上面的 Start.S 中设置的程序入口是 _start, 代码为 ENTRY(_start) ;3.设置代码段 : 使用 .text : 设置代码段; 4.设置数据段 : 使用 .data : 设置数据段;5.设置 BSS 段 : 使用 .bss : 设置 BSS 段; ( 1 ) 记录 BSS 段的起始地址 : bss_start = .; ;( 2 ) 记录 BSS 段的结束地址 : bss_end = .; ;6.对齐 : 每个段都需要设置内存的对齐格式, 使用 . = ALIGN(4); 设置四字节对齐即可;7.代码示例 : OUTPUT_ARCH(arm) /*指明处理器结构*/ ENTRY(_start) /*指明程序入口 在 _start 标号处*/ SECTIONS { . = 0x50008000; /*整个程序链接的起始位置, 根据开发板确定, 不同开发板地址不一致*/ . = ALIGN(4); /*对齐处理, 每段开始之前进行 4 字节对齐*/ .text : /*代码段*/ { start.o (.text) /*start.S 转化来的代码段*/ *(.text) /*其它代码段*/ } . = ALIGN(4); /*对齐处理, 每段开始之前进行 4 字节对齐*/ .data : /*数据段*/ { *(.data) } . = ALIGN(4); /*对齐处理, 每段开始之前进行 4 字节对齐*/ bss_start = .; /*记录 bss 段起始位置*/ .bss : /*bss 段*/ { *(.bss) } bss_end = .; /*记录 bss 段结束位置*/ } 3. Makefile 编译脚本

makefile 文件编写 :

1.通用规则 ( 汇编文件编译规则 ) : 汇编文件 编译 成同名的 .o 文件, 文件名称相同, 后缀不同, %.o : %.S, 产生过程是 arm-linux-gcc -g -c $^ , 其中 ^ 标识是所有的依赖文件, 在该规则下 start.S 会被变异成 start.o ; 2.通用规则 ( C 文件编译规则 ) : C 代码编译成同名的 .o 文件, %.o : %.c , 产生过程是 arm-linux-gcc -g -c $^ ; 3.设置最终目标 : 使用 all: 设置最终编译目标; ( 1 ) 依赖文件 : 产生最终目标需要依赖 start.o 文件, 使用 all: start.o 表示最终目标需要依赖该文件; ( 2 ) 链接过程 : arm-linux-ld -Tgboot.lds -o gboot.elf ^, 需要使用链接器脚本进行连接, ①链接工具是 arm-linux-ld 工具, ②使用 -Tgboot.lds 设置链接器脚本 是刚写的 gboot.lds 链接器脚本, ③输出文件是 gboot.elf 这是个中间文件, ④ 依赖文件是 ^ 代表所有的依赖; ( 3 ) 转换成可执行二进制文件 : arm-linux-objcopy -O binary gboot.elf gboot.bin, 使用 -O binary 设置输出二进制文件, 依赖文件是 gboot.elf, 输出的可执行二进制文件 即 结果是 gboot.bin ;4.makefile 文件内容 : all: start.o #依赖于 start.o arm-linux-ld -Tgboot.lds -o gboot.elf $^ #使用链接器脚本, 将 start.o 转为 gboot.elf arm-linux-objcopy -O binary gboot.elf gboot.bin #将 gboot.elf 转化为可以直接在板子上执行的 gboot.bin 文件 %.o : %.S #通用规则, 如 start.o 是由 start.S 编译来的, -c 是只编译不链接 arm-linux-gcc -g -c $^ %.o : %.c #通用规则, 如 start.o 是由 start.c 编译来的, -c 是只编译不链接 arm-linux-gcc -g -c $^ .PHONY: clean clean: #清除编译信息 rm *.o *.elf *.bin 4. 编译输出可执行文件

编译过程 :

1.文件准备 : 将 汇编代码 ( start.S ) 链接器脚本 ( gboot.lds ) makefile 文件 拷贝到编译目录 ;2.执行编译命令 : make ; 3.编译结果 : 可以看到 生成了 编译目标文件 start.o, 链接文件 gboot.elf, 可执行的二进制文件 gboot.bin ;

本博客的参考文章及相关资料下载 :

1.ARM 架构参考手册 ( ARM Architecture Reference Manual ) : https://download.csdn.net/download/han1202012/83246412.汇编参考手册 : https://download.csdn.net/download/han1202012/83283753.本博客代码下载 : https://download.csdn.net/download/han1202012/10400369


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3