赞
踩
本节主要介绍ARM处理器处理器模式、异常和异常向量表。
ARM寄存器通用寄存器、。程序状态寄存器cpsr描述当前寄存器的内容。
假设我们生活中一位母亲在照顾睡觉的小孩,并自己在看书,那么这种情况下面如何得知小孩是否醒来?
这个时候母亲可以通过不断的去查看孩子确认是否醒来,还可以是在孩子醒来的哭声打断看书的母亲。第一种方式简单,但是非常累,一般在小孩子很小的时候会这个样子。第二种方式复杂但是轻松,当孩子稍微大一些的时候这种方式比较好。对于这两种情况处理流程可以是:
1. 第一种轮训使用一个while循环,完成读书事情,然后接着查看孩子情况,如果没有醒返回继续while看书,如果醒来照顾孩子穿衣服,结束以后继续自己看书。
2. 第二种通过中断方式,在看书过程中,听外面发出来的各种声音。这个时候外界可能有门铃声、小孩哭声或者猫叫声。这个时候母亲在读书,如果发生了中断,母亲则放置书签合上书(保存现场),然后针对不同类型的中断产生不同的动作(中断处理)。对于第三种猫叫声可以不用做任何处理,其他几种类型可以产生不同的动作,门铃声打开门拿快递,孩子哭声则去照顾孩子。处理完事宜以后则继续回来看刚才书签确定的书籍位置(恢复现场)。
1.2. CPU中断
类比与母亲通过声音照顾孩子的场景,那么CPU是如何处理中断的?对于硬件类型的异常,包含中断和其他类型的异常,其中中断属于异常的一种。
ARM处理中断过程如下:
1. 初始化中断系统。a) 设置中断源,让外部器件能够产生中断。b) 设置中断控制器优先级和屏蔽情况。c) 设置CPU总开关,使能中断。
2. 程序正常执行。这个时候CPU处于中断检测当中,没运行完一条指令就确认是否有中断和异常产生。
3. 硬件中断被触发。这个时候一个打开了中断的按键被按下,触发的中断被传入中断控制器进而传导到CPU。
4. CPU感知到中断跳转固定中断向量表位置执行(这个是硬件约定,汇编语言固定在某个位置写定代码)。这个时候中断会跳转到中断处理分支开始执行中断处理程序。
5. 中断处理程序首先保存现场,然后分辨中断源处理中断,最后回复现场。
CPU的模式可以简单的理解为当前CPU的工作状态,比如:当前操作系统正在执行用户程序,那么当前CPU工作在用户模式,这时网卡上有数据到达,产生中断信号,CPU自动切换到一般中断模式下处理网卡数据(普通应用程序没有权限直接访问硬件),处理完网卡数据,返回到用户模式下继续执行用户程序。
特权模式,除用户模式外,其它模式均为特权模式(Privileged Modes)。ARM 内部寄存器 和一些 片内外设 在硬件设计上只允许(或者可选为只允许)特权模式下访问。此外,特权模式可以自由的切换处理器模式,而用户模式不能直接软件切换到别的模式。
异常模式,特权模式中除系统(system)模式之外的其他5种模式又统称为异常模式。它们除了可以通过在特权下的程序切换进入外,也可以由特定的异常进入。比如硬件产生中断信号进入中断异常模式,读取没有权限数据进入中止异常模式,执行未定义指令时进入未定义指令中止异常模式。其中管理模式也称为超级用户模式,是为操作系统提供软中断的特有模式,正是由于有了软中断,用户程序才可以通过系统调用切换到管理模式。
2.1. 7种工作模式介绍
(1)用户模式:
用户模式是用户程序的工作模式,它运行在操作系统的用户态,它没有权限去操作其它硬件资源,只能执行处理自己的数据,也不能切换到其它模式下,要想访问硬件资源或切换到其它模式只能通过软中断或产生异常。
(2)系统模式:
系统模式是特权模式,不受用户模式的限制。用户模式和系统模式共用一套寄存器,操作系统在该模式下可以方便的访问用户模式的寄存器,而且操作系统的一些特权任务可以使用这个模式访问一些受控的资源。
说明:用户模式与系统模式两者使用相同的寄存器,都没有SPSR(Saved Program Statement Register,已保存程序状态寄存器),但系统模式比用户模式有更高的权限,可以访问所有系统资源。
(3)一般中断模式:
一般中断模式也叫普通中断模式,用于处理一般的中断请求,通常在硬件产生中断信号之后自动进入该模式,该模式为特权模式,可以自由访问系统硬件资源。
(4)快速中断模式:
快速中断模式是相对一般中断模式而言的,它是用来处理对时间要求比较紧急的中断请求,主要用于高速数据传输及通道处理中。一般在单片机分秒必争的时候会使用这种中断模式。
(5)管理模式(Supervisor,SVC) :
管理模式是CPU上电后默认模式,因此在该模式下主要用来做系统的初始化,软中断处理也在该模式下。当用户模式下的用户程序请求使用硬件资源时,通过软件中断进入该模式。
说明:系统复位或开机、软中断时进入到SVC模式下。
(6)终止模式:
中止模式用于支持虚拟内存或存储器保护,当用户程序访问非法地址,没有权限读取的内存地址时,会进入该模式,linux下编程时经常出现的segment fault通常都是在该模式下抛出返回的。
(7)未定义模式:
未定义模式用于支持硬件协处理器的软件仿真,CPU在指令的译码阶段不能识别该指令操作时,会进入未定义模式。
2.3. 硬件资源
在 不同的工作模式下面,芯片内部有不同类型的寄存器资源可以利用。其中在特权模式r13(SP)用作栈指针,r14(LR)保存异常发生时对应的地址,方便处理完数据以后返回结果。下面SPARM 26(和以后)的 32 位模式下可获得的寄存器有:
User26 SVC26 IRQ26 FIQ26 User SVC IRQ ABT UND FIQ R0 ----- R0 ----- R0 ----- R0 -- -- R0 ----- R0 ----- R0 ----- R0 ----- R0 ----- R1 R1 ----- R1 ----- R1 ----- R1 -- -- R1 ----- R1 ----- R1 ----- R1 ----- R1 ----- R2 R2 ----- R2 ----- R2 ----- R2 -- -- R2 ----- R2 ----- R2 ----- R2 ----- R2 ----- R2 R3 ----- R3 ----- R3 ----- R3 -- -- R3 ----- R3 ----- R3 ----- R3 ----- R3 ----- R3 R4 ----- R4 ----- R4 ----- R4 -- -- R4 ----- R4 ----- R4 ----- R4 ----- R4 ----- R4 R5 ----- R5 ----- R5 ----- R5 -- -- R5 ----- R5 ----- R5 ----- R5 ----- R5 ----- R5 R6 ----- R6 ----- R6 ----- R6 -- -- R6 ----- R6 ----- R6 ----- R6 ----- R6 ----- R6 R7 ----- R7 ----- R7 ----- R7 -- -- R7 ----- R7 ----- R7 ----- R7 ----- R7 ----- R7 R8 ----- R8 ----- R8 R8_fiq R8 ----- R8 ----- R8 ----- R8 ----- R8 R8_fiq R9 ----- R9 ----- R9 R9_fiq R9 ----- R9 ----- R9 ----- R9 ----- R9 R9_fiq R10 ---- R10 ---- R10 R10_fiq R10 ---- R10 ---- R10 ---- R10 ---- R10 R10_fiq R11 ---- R11 ---- R11 R11_fiq R11 ---- R11 ---- R11 ---- R11 ---- R11 R11_fiq R12 ---- R12 ---- R12 R12_fiq R12 ---- R12 ---- R12 ---- R12 ---- R12 R12_fiq R13 R13_svc R13_irq R13_fiq R13 R13_svc R13_irq R13_abt R13_und R13_fiq R14 R14_svc R14_irq R14_fiq R14 R14_svc R14_irq R14_abt R14_und R14_fiq --------- R15 (PC / PSR) --------- --------------------- R15 (PC) --------------------- ----------------------- CPSR ----------------------- SPSR_svc SPSR_irq SPSR_abt SPSR_und SPSR_fiq
2.4. CPSR/SPSR寄存器
当前程序状态寄存器,mode给地当前模式状态,并且可以修改让CPU进入对应程序运行模式。对应的编码格式可以查看芯片硬件手册。条件编码标志位可以用来表示对应的汇编代码运行状态,
SPSR寄存器用来保存异常产生时,当前正在运行的模式下CPSR寄存器值,用户模式没有这个寄存器。
中断屏蔽与状态:控制寄存器中还存在一个状态为,和两个中断屏蔽位,这两个中断屏蔽位确定了当前内核是否相应外部中断信号。
状态与指令集:其中J(Jazelle)和T(Thumb)位反映了处理器的状态。当T位和J位都是0时,处理器处于ARM状态,执行ARM指令;当T置位,处理器处于Thumb状态。
条件标志:在后面ARM会汇编指令中会大量使用到这里的标志位,对应的条件指令可以通过英文确定其具体的含义。在ARM的条件执行指令中(EQ)这种类型的条件处理时,其真假结果确定了当前这条慧琳是否被执行。也就是说在执行前,处理器比较条件属性和cpsr的条件标志位,如果匹配指令就会被执行,否则指令就会被忽略。当然比方说teq这种指令其比较结果会决定下一条指令是否执行。
2.5. r15(PC)
用来表示当前指针所在的位置,即在内存中当前程序所在的地址位置。
中断产生时硬件会做哪些动作?
1. LR寄存器保存当前中断的下一条指令地址,PC+4、PC+8
2. 搬移CPSR寄存器值到SPSR寄存器
3. 修改CPSR寄存器模式,进入异常模式
4. PC值修改跳转向量表入口执行
异常程序返回执行原来程序模式
1. PC=LR减去某个值
2. SPSR赋值会CPSR寄存器
3. 最后清理中断
除了如上的寄存器资源外,CPU通过地址线访问外部的内存空间memory,这部分内存空间包含了指令也包含了数据。结合在一起,CPU通过PC指针在命令空间移动,通过命令解析将数据从数据内存空间获取,然后通过内部的寄存器进行计算以后将数据输出到外部数据内存空间当中。全局编制的情况下,我们可以认为所有的I/O设备等都是内存数据空间。
首先,ARM开发板在刚上电或复位后都会首先进入SVC即管理模式,此时、程序计数器R15-PC值会被赋为0x0000 0000;bootloader就是在此模式下,位于0x0000 0000的NOR FLASH或SRAM中装载的,因此、开机或重启后bootloader会被首先执行。
接着,bootloader引导Linux内核,此时、Linux内核一样运行在ARM的SVC即管理模式下;当内核启动完毕、准备进入用户态init进程时,内核将ARM的当前程序状态CPSR寄存器M[4:0]设置为10000、进而用户态程序只能运行在ARM的用户模式。
由于ARM用户模式下对资源的访问受限,因此、可以达到保护Linux操作系统内核的目的。
需要强调的是:Linux内核态是从ARM的SVC即管理模式下启动的,但在某些情况下、如:硬件中断、程序异常(被动)等情况下进入ARM的其他特权模式,这时仍然可以进入内核态(因为就是可以操作内核了);同样,Linux用户态是从ARM用户模式启动的,但当进入ARM系统模式时、仍然可以操作Linux用户态程序(进入用户态,如init进程的启动过程)。
即:Linux内核从ARM的SVC模式下启动,但内核态不仅仅指ARM的SVC模式(还包括可以访问内核空间的所有ARM模式);Linux用户程序从ARM的用户模式启动,但用户态不仅仅指ARM的用户模式。
arm处理器包含了32为和16位两种工作状态指令集模式。其中,ARM状态32位,ARM状态执行字对齐的32位ARM指令;Thumb状态,16位,执行半字对齐的16位指令。汇编通过用Bx Rn指令来进行两种状态的切换:其中Bx是跳转指令,而Rn是寄存器(1个字,32位),如果Rn的位0为1,则进入Thumb状态;如果Rn的位为0,这进入ARM状态。(原 因:ARM指令的后两位始终为0,没有用,而Thumb指令的后一位始终为0,没有用,因此采用位0来表示ARM指令与Thumb指令的切换标志位。)
工作状态只是命令的实行方式,ARM和Thumb两种状态之间的切换不影响处理器的工作模式和寄存器的内容。ARM处理器在处理异常时,不管处理器处于什么状态,则都将切换到ARM状态。ARM的M系列主要用Thumb指令,ARM9和A系列主要用ARM指令。S3C2440.S启动代码中根本就没用Thumb指令。
也就是对于同样一条mov r0, r1,在ARM指令集下面是4个字节表示,在Thumb指令集下面这条指令是用2个指令。在单片机下面,硬件flash空间寸土寸金,这个时候thumb会进一步减少代码指令的空间。当然thumb指令集没有没有办法单独存在,一般情况下是结合部分ARM指令集实现功能。
ARM芯片在初始化启动是芯片会处于SVC系统管理模式下,如果存在uboot情况下会引导内核切换到用户模式。如果用户模式程序通过软件中断的方式进入到系统模式,ARM在探测到这种中断发生会自动从user模式切换到svc模式。因此,在user模式不能通过代码手动切换到其他任何模式,而其他特权模式可以任意切换同时可以切换到用户模式。对于其他类型的异常会对应的将ARM芯片切换到对应的异常工作模式,切换过程是芯片遇到某种类型的异常时自动产生。
不同用户模式下面寄存器资源的访问形式和数量都有差别,同时不同用户模式下面硬件的访问权限也是不一样的。尤其为了防止用户直接进行硬件行为的修改,user模式对硬件的操作往往没有办法直接操作,同时硬件也会支持不同的用户模式访问行为。
用户空间的时候,处于user的工作模式,访问内存地址的时候,MMU会检查页表的权限;同时,内核空间对应ARM的特权模式,访问内存地址的时候,MMU也会检查页表的权限。这个时候页表的访问权限就起作用了。
具体可以看下面这个表:AP是页表的访问权限项,S和R是CP15的C1系统控制寄存器的两个特性位,后面是分别在特权模式和用户模式下的访问权限。
AP S R Privileged permissions User permissions
0 0 0 0 No access No access
0 0 1 0 Read-only No access
0 0 0 1 Read-only Read-only
0 0 1 1 Unpredictable Unpredictable
0 1 x x Read/write No access
1 0 x x Read/write Read-only
1 1 x x Read/write Read/write
CPU工作模式、寄存器资源、外部内存资源确定下来以后,后面给出ARM处理器常用的汇编指令进行说明,实际工作中遇到具体的问题,直接查看命令手册即可。
3. 异常向量表
异常向量表基本实验
1. 运行需要寄存器
ARM 处理器共有 9种不同的处理器运行模式:
用户模式(User),快速中断模式(FIQ),普通外部中断模式(IRQ),超级管理模式(Svc,裸机就是跑的这个模式,cpu复位也是这个模式),数据访问中止模式(Abort),未定义指令中止模式(Und),系统模式(Sys),监视模式(Mon),超级监视模式(Hyp)
当某个触发满足了,arm自动进入那个模式,比如外部中断来了,arm自动跳转进入IRQ_Handler向量地址,这时候就是自动进入了IRQ模式(在下面介绍的CPSR状态寄存器对应的位可以查询知道当前所处模式,确实改变了)。
除了用户模式,其它所有模式都是特权模式,如果跑了OS,大多数的程序都运行在用户模式,用户模式下是不能访问系统所有资源的,而且不能修改某些资源(比如程序状态寄存器CPSR只能被访问,不能被修改,而该寄存器低5位表示CPU运行模式状态,因此用户模式没法直接发生运行模式切换,保障了系统安全,比如用户模式不能直接开关某某中断),有些资源是受限的,要想访问这些资源,就必须发生模式切换,只能是通过借助异常(比如SWI软中断,将进入SVC模式)来完成模式切换,当要切换模式的时候,应用程序可以产生异常,在异常的处理过程中完成处理器模式切换。
任意一种模式都可以运行程序,因此每种模式,按原则来说会有自己的一组寄存器来实现代码运行,但是有些寄存器是共用的,有些是仅自己用的(从物理上的寄存器不同)。如下图所示(只画出了7种运行模式):
上面可以看出系统模式,用户模式,都是正常模式,完全共用寄存器组,而其它模式都属于异常模式。
总结一下,CortexA 内核运行所需寄存器组成如下:
①、34 个通用寄存器,包括 R15 程序计数器(PC),这些寄存器都是 32 位的。
②、8 个状态寄存器,包括 CPSR 和 SPSR。
③、Hyp 模式下独有一个 ELR_Hyp 寄存器。
注:Thumb 程序中(arm指令集的一个子集,大大的节省了系统的存储空间,不是一个完整的体系结构,不能指望处理器只执行thumb指令集而不支持arm指令集),通常只能使用 r4~r7 来保存局部变量。
r12:内部程序调用暂存寄存器,也成为ip寄存器,我不知道是干嘛的,网上解释也模棱两可。
运行寄存器特定功能寄存器主要是三个:
r13:栈指针,也称为sp寄存器,保存处理器模式的堆栈的栈顶
cr14:连接寄存器,也称为lr寄存器,程序跳转(子程序调用,中断跳转)后,arm自动在该寄存器中存入原程序(未跳转)的下一条指令的地址。
r15:程序计数器,也称为pc寄存器,保存的是当前正在取指的指令的地址(arm采用2级流水线,因此是当前正在执行指令的地址+8)。
除了上述每种模式所需寄存器外,还有6状态寄存器,最主要的就是两个CPSR和SPSR,arm进入异常模式后,SPSR自动保存进入异常前的CPSR的值,以便异常返回后恢复异常发生时的工作状态。因此主要看CPSR中的位都是什么作用:
常用于MRS或MSR指令,用于spsr中的值转移到寄存器或把寄存器的内容加载到spsr中,如:
mrs r0, spsr /* 读取spsr寄存器 */
msr spsr_cxsf, r0 /* 恢复spsr */
2. 系统管理控制寄存器
关 于 CP15 协处理 器和其 相关寄存 器的详细 内容 请参考下 面两份文 档:《ARM
ArchitectureReference Manual ARMv7-A and ARMv7-R edition.pdf》第 1469 页“B3.17 Oranization of the CP15 registers in a VMSA implementation”。《Cortex-A7 Technical ReferenceManua.pdf》第55 页“Capter 4 System Control”。
CP15 协处理器一般用于存储系统管理,但是在中断中也会使用到,CP15 协处理器一共有
16 个 32 位寄存器。CP15 协处理器的访问通过如下另个指令完成:
MRC: 将 CP15 协处理器中的寄存器数据读到 ARM 寄存器中。
MCR: 将 ARM 寄存器的数据写入到 CP15 协处理器寄存器中。
MCR{cond} p15, <opc1>, <Rt>, <CRn>, <CRm>, <opc2>
这个指令很难理解,还好的是所有控制寄存器,官方文档给出了库函数(通过c语言中嵌入汇编实现的),例如:
- /* C语言实现MCR指令 */
- #define __MCR(coproc, opcode_1, src, CRn, CRm, opcode_2) \
- __ASM volatile ("MCR " __STRINGIFY(p##coproc) ", " __STRINGIFY(opcode_1) ", " \
- "%0, " __STRINGIFY(c##CRn) ", " __STRINGIFY(c##CRm) ", " \
- __STRINGIFY(opcode_2) \
- : : "r" (src) )
-
- /*******************************************************************************
- * CP15 访问函数
- ******************************************************************************/
-
- FORCEDINLINE __STATIC_INLINE uint32_t __get_SCTLR(void)
- {
- return __MRC(15, 0, 1, 0, 0);
- }
-
- FORCEDINLINE __STATIC_INLINE void __set_SCTLR(uint32_t sctlr)
- {
- __MCR(15, 0, sctlr, 1, 0, 0);
- }
-
- 我学的是正点原子的MX6ULL教程,上述不知道是原子自己写的还是官方SDK里面都有的,在正点原子工程的imx6ul/core_ca7.h文件里,此外里面还有读取cpsr等寄存器的函数,非常方便。
-
- 其中比较重要的是,cp15的SCTLR寄存器
-
- /* CP15的SCTLR寄存器
- * 参考资料:Cortex-A7 Technical ReferenceManua.pdf P105
- */
-
- typedef union
-
- {
- struct
- {
- uint32_t M:1; /*!< bit: 0 MMU enable */
- uint32_t A:1; /*!< bit: 1 Alignment check enable */
- uint32_t C:1; /*!< bit: 2 Cache enable */
- uint32_t _reserved0:2; /*!< bit: 3.. 4 Reserved */
- uint32_t CP15BEN:1; /*!< bit: 5 CP15 barrier enable */
- uint32_t _reserved1:1; /*!< bit: 6 Reserved */
- uint32_t B:1; /*!< bit: 7 Endianness model */
- uint32_t _reserved2:2; /*!< bit: 8.. 9 Reserved */
- uint32_t SW:1; /*!< bit: 10 SWP and SWPB enable */
- uint32_t Z:1; /*!< bit: 11 Branch prediction enable */
- uint32_t I:1; /*!< bit: 12 Instruction cache enable */
- uint32_t V:1; /*!< bit: 13 Vectors bit */
- uint32_t RR:1; /*!< bit: 14 Round Robin select */
- uint32_t _reserved3:2; /*!< bit:15..16 Reserved */
- uint32_t HA:1; /*!< bit: 17 Hardware Access flag enable */
- uint32_t _reserved4:1; /*!< bit: 18 Reserved */
- uint32_t WXN:1; /*!< bit: 19 Write permission implies XN */
- uint32_t UWXN:1; /*!< bit: 20 Unprivileged write permission implies PL1 XN */
- uint32_t FI:1; /*!< bit: 21 Fast interrupts configuration enable */
- uint32_t U:1; /*!< bit: 22 Alignment model */
- uint32_t _reserved5:1; /*!< bit: 23 Reserved */
- uint32_t VE:1; /*!< bit: 24 Interrupt Vectors Enable */
- uint32_t EE:1; /*!< bit: 25 Exception Endianness */
- uint32_t _reserved6:1; /*!< bit: 26 Reserved */
- uint32_t NMFI:1; /*!< bit: 27 Non-maskable FIQ (NMFI) support */
- uint32_t TRE:1; /*!< bit: 28 TEX remap enable. */
- uint32_t AFE:1; /*!< bit: 29 Access flag enable */
- uint32_t TE:1; /*!< bit: 30 Thumb Exception enable */
- uint32_t _reserved7:1; /*!< bit: 31 Reserved */
- } b; /*!< Structure used for bit access */
-
- uint32_t w; /*!< Type used for word access */
- } SCTLR_Type;
-
- 还有FPU的3个相关寄存器:NSACR、CPACR、FPEXC寄存器
msr cpsr_cxsf,r1 ;这里的cxsf表示从低到高分别占用的4个8bit的数据域
指令中有时还有出现cpsr_cf, cpsr_all, cpsr_c等,这里:
c 指 CPSR中的control field ( PSR[7:0])
f 指 flag field (PSR[31:24])
x 指 extend field (PSR[15:8])
s 指 status field ( PSR[23:16])
其中cpsr的位表示为:
深入分析:
对于MSR(寄存器到状态寄存器)的指令,
MSR CPSR, r0
MSR CPSR_all, r0
MSR CPSR_flg, r0
对于MRS(状态寄存器到寄存器)的指令,
MRS R0, CPSR 等同于MRS R0, CPSR_cxsf
MRS R0, CPSR_all 会有waring
MRS R0, CPSR_flg 会有错误
上述都是已经过时的表示方法。
在ADS中使用c,f,x,s表示cpsr的各个部分是推荐的。从指令来说:
MSR CPSR_f, r0机器码为0xe128f000
MSR CPSR_c, r0机器码为0xe121f000
MSR CPSR_x, r0机器码为0xe122f000
MSR CPSR_s, r0机器码为0xe124f000
可见机器码中用bit[29:16]4bit表示是f,c,x,s的。所以能够在机器执行的时候,
给予不同的执行结果。为了代码向后兼容性,建议使用f,c,x,s尾缀
这里举个例:(关于c语言嵌入汇编,汇编和c语言混合编程更多知识,看我这篇ARM中C语言和汇编语言的混合编程)从上面说的cpsr各状态位意思,就可以知道下面程序如何打开和关闭中断的了。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。