Arm64体系结构简介
- 中断管理
- 2023-03-04
- 218热度
- 0评论
ARM简介
ARM版本 | 典型处理器 | 主要特性 |
---|---|---|
v1 | 26位地址空间 | |
v2 | 增加乘法、乘加法、支持协处理指令等 | |
v3 | 地址空间扩展到32位,增加SPSP和CPSR等 | |
v4 | ARM7TDMI/ARM920T | 增加Thumb指令等 |
v5 | ARM926EJ-S | 增加Jazelle和VFPv2等 |
v6 | ARM11 MPCore | 增加SIMD、TrustZone以及Thumb-2等 |
v7 | Cortex-A8/Cortex-A9 | 增加NEON和VFPv3/v4扩展 |
v8 | Cortex-A72 | 支持32位和64位指令集处理器体系结构 |
v9 | Cortex-x2 | 支持可伸缩矢量扩展计算、机密计算体系结构 |
- A系列:面向性能密集型系统的应用处理器内核。
- R系列:面向实时应用的高性能内核。
- M系列:面向各类嵌入式应用的微控制器内核。
Armv8体系结构
通用寄存器
AArch64状态下支持31个64位通用寄存器,分别是X0~X30,而AArch32状态支持16个32位通用寄存器。在AArch64状态下使用X表示64位寄存器,另外还可以使用W来表示32位的数据。X29(FP)是栈帧寄存器,指向栈的顶部(SP指向栈的当前位置),X30(LR)是链接寄存器,保持函数返回地址。
下图是AArch32状态下AArch64到AArch32状态的寄存器mapping。
处理器状态
Aarch64使用了PSTATE寄存器来表示当前处理器的状态(armv7使用的是CPSR),上图中I和F表示cpu本地中断的屏蔽位。SP为选择SP寄存器,在不同的异常等级下,SP寄存器是不一样的(见下小节),当运行在EL0是即为SP_EL0。
特殊寄存器
除了31个通用的寄存器外,还有上面的特殊寄存器。不同特权模式下的寄存器有所差别。
- XZR/WZR:两个零寄存器。WZR是32位零位寄存器,XZR是64位零位寄存器。
- PC:指向当前运行指令的下一条指令地址。
- SP:每个异常等级都有一个专门的SP寄存器SP_ELn。高等级的特权模式可以访问低等级的SP寄存器。
- SPSR:备份程序状态寄存器,运行一个异常程序是,处理器的一些状态信息会保存在备份程序状态寄存器里,如会将处理器的PSTATE寄存器的值暂时保存到SPSR里,当处理完成返回时,再把SPSR的值恢复到PSTATE寄存器。
- ELR:存放异常返回地址。
异常
异常类型
- 中断
- 中止
- 复位
- 系统调用
异常等级
Armv8支持aarch64和aarch32两种执行状态,aarch64是64位执行状态,运行A64指令集;aarch32是兼容armv7架构32位执行状态,运行A32的指令集。aarch64有4中异常等级。
- EL0:用户特权,用于运行普通的用户程序。
- EL1:系统特权,用于操作系统内核。如果使能虚拟化,则运行虚拟机操作系统内核。
- EL2:运行虚拟化扩展的虚拟机监控器(hypervisor)。
- EL3:运行安全os下的监控器(secure monitor)。
除了EL0以外,每个异常等级都有两个选择,选择自己等级或使用EL0等级,如果选用自己等级SP为SP_ELn(SP_ELnH),如果使用EL0那么SP为SP_EL0(SP_ELnt)。
ARMv8有4种以上等级,只有在获取异常或异常返回发生等级的变化。当处理器从较高等级切换到较低等级时,执行状态可以不变或者可以从aarch64切换到aarch32。当处理器从较低等级切换到较高等级时,执行状态可以不变或从aarch32切换到aarch64。
中断发生硬件处理过程
当事件触发异常发生时,处理器硬件会自动的执行以下动作。
1. 进入异常:
(1)将PC保存到ELR_ELx
(2)PSTATE保存到SPSR_ELx,会关闭到cpu本地的IRQ和FIQ中断,防止中断嵌套
1. 退出异常:
(1)将ELR_ELx的数据保存到PC
(2)将SPSR_ELx的数据保存到PSTATE,打开中断。
以上过程都是硬件自动完成。硬件处理完成后,就进入程序处理阶段,分为三个阶段保存上下文、中断处理、恢复上下文。
- 上下文:进入中断后,需要将打断的应用当前的相关寄存器保存起来,一般是存储在当前任务内核堆栈里面,当中断退出时,再从堆栈中获取恢复。
- 中断处理:包括确定中断源,将触发的中断源屏蔽,接着再处理中断服务程序。
异常向量表
异常发生时,处理器会跳转到相应位置执行异常相关指令。异常相关的处理指令通常存储在内存种,这个存储位置为异常向量,在ARMv8体系结构中,EL1、EL2、EL3都有一个异常向量表,每个异常向量表存储的基地址在VBAR_ELx寄存器中,EL0没有异常向量表,那是因为EL0的异常发生在用户态,当用户态发生发生异常时系统会跃迁到内核态EL1处理,所以EL0没有异常向量表,也可以认为EL0和EL1是共用EL1的异常向量表。
下图是一张异常向量表的示例,可以看到异常向量表分为4组,每组有4种类型。
异常向量表为什么分为4组?
(1)当系统的发生异常处于内核态,异常等级为ELx(EL1/EL2/EL3)时,可以选择使用SP_EL0或SP_ELx来作为栈指针,所以分为Current EL with SP0和Current EL with SPx两组。目前对于arm64的嵌入式设备来说,通常只有到EL1等级,EL2用于虚拟化,EL3用于安全基本,所以EL2和EL3基本没有用。
(2)当系统的发生在用户态(EL0),会下陷到内核变为EL1,但是会根据执行状态是aarch64或者aarch32来区分两组,Lower EL using AArch64或Lower EL using AArch32。
arch/arm64/kernel/entry.S
SYM_CODE_START(vectors)
#内核态发生异常,异常等级为EL1,但是栈依旧使用的是SP_EL0
kernel_ventry 1, t, 64, sync // Synchronous EL1t
kernel_ventry 1, t, 64, irq // IRQ EL1t
kernel_ventry 1, t, 64, fiq // FIQ EL1h
kernel_ventry 1, t, 64, error // Error EL1t
#内核态发生异常,异常等级为EL1,但是栈使用是SP_EL1
kernel_ventry 1, h, 64, sync // Synchronous EL1h
kernel_ventry 1, h, 64, irq // IRQ EL1h
kernel_ventry 1, h, 64, fiq // FIQ EL1h
kernel_ventry 1, h, 64, error // Error EL1h
#用户态发生异常,异常等级为EL0(切到内核会转为EL1),到内核后执行状态是aarch64
kernel_ventry 0, t, 64, sync // Synchronous 64-bit EL0
kernel_ventry 0, t, 64, irq // IRQ 64-bit EL0
kernel_ventry 0, t, 64, fiq // FIQ 64-bit EL0
kernel_ventry 0, t, 64, error // Error 64-bit EL0
#用户态发生异常,异常等级为EL0(切到内核会转为EL1),到内核后执行状态是aarch32
kernel_ventry 0, t, 32, sync // Synchronous 32-bit EL0
kernel_ventry 0, t, 32, irq // IRQ 32-bit EL0
kernel_ventry 0, t, 32, fiq // FIQ 32-bit EL0
kernel_ventry 0, t, 32, error // Error 32-bit EL0
SYM_CODE_END(vectors)