1、异常和中断的概念
(AArch64 Exception and Interrupt Handling)
异常是指需要特权软件(an exception handler))采取某些操作,以确保系统的平稳运行
中断有时用作异常的同义词。但是对于ARM的术语来说,中断是异步异常,只是异常的一种;
异常是一个事件(而不是分支或跳转指令)导致指令的正常顺序执行被修改。
一个中断是一个异常,它不是由程序执行直接引起的。通常情况下,硬件外部到处理器核心信号中断,如一个按钮被按下
ARM-A架构异常分为两组,同步和异步的。
同步异常类型可以有很多原因,但是它们是以类似的方式处理。
异步异常类型被细分为三个中断:IRQ, FIQ和SError(系统错误)。
2、异常产生的方法:
(1)、Abort :
指令获取失败时生成中止(指令中止)
失败的数据访问(数据中止)
它们可以来自外部记忆系统在内存访问上给出错误响应(指示可能指定的地址与系统中的实际内存不对应)。或者,核心的内存管理单元(MMU)生成中止
在AArch64中,同步中止会导致同步异常。异步中止会导致SError中断异常
(2)、Reset
重置是一种特殊情况,因为它总是有自己的向量以最高的实现异常级别为目标
地址可以从重置向量基地址寄存器中读取RVBAR_ELn,其中n是实现的最高异常级别的数目。
所有的核心都有一个重置输入,并在它们被重置后接受重置异常重置。它是最高优先级的异常,不能被掩盖。这个异常是用来在内核上执行代码来初始化它,在系统通电后向上
(3)、同步异常
• The Supervisor Call (SVC) instruction enables User mode programs
to request an OS service.
• The Hypervisor Call (HVC) instruction enables the guest OS to
request hypervisor services.
• The Secure monitor Call (SMC) instruction enables the Normal
(4)、异步异常(中断)
中断有三种类型,IRQ, FIQ和SError。IRQ和FIQ是与SError相比,一般用途是与外部异步数据中止。所以通常,术语“中断”仅指到IRQ和FIQ。
3、同步异常和异步异常的处理
(1)、处理一个同步异常
Exception Syndrome Register (ESR_ELn)
Fault Address Register (FAR_ELn)
The Exception Link Register (ELR_ELn)
异常综合征寄存器(ESR_ELn)和错误地址寄存器(FAR_ELn)是提供用于向异常处理程序提供有关同步异常原因的信息
ESR_ELn提供异常原因的信息,而FAR\_ELn保存所有同步指令和数据中止和对齐错误的错误虚拟地址。
对于实现了EL2 (Hypervisor)或EL3(安全内核)的系统,同步异常通常在当前或更高的异常级别中获取。异步异常可以(如果)),将被路由到更高的异常级别,由Hypervisor或安全程序处理
内核。SCR_EL3寄存器指定哪些异常被路由到EL3,类似地,HCR_EL2指定将哪些异常路由到EL2。有一些单独的位允许独立控制IRQ, FIQ和SError的路由。
(2)、ESR_ELn - 异常综合征寄存器
包含允许异常的信息
处理程序来确定异常的原因。它只针对同步异常进行更新
和SError。它不为IRQ或FIQ更新,因为这些中断处理程序通常获得状态
来自通用中断控制器(GIC)寄存器的信息
(3)、Unallocated instructions
Unallocated instructions cause a Synchronous Abort in AArch64. 该异常产生的原因:
• An instruction opcode that is not allocated.
• An instruction that requires a higher level of privilege than the current Exception level. //比如你在EL1中操作了SCR_EL3寄存器
• An instruction that has been disabled.
• Any instruction when the PSTATE.IL field is set.
(4)、System calls
4、异常处理
ARMv8-A体系结构有四个异常级别:EL0、EL1、EL2和EL3。处理器执行
只能通过获取异常或从异常返回来在异常级别之间移动。
需要注意的是:
- When the processor moves from a higher to a lower Exception level, the Execution state can stay the same, or it can switch from AArch64 to AArch32.
- When moving from a lower to a higher Exception level, the Execution state can stay the same or switch from AArch32 to AArch64
也就是说,如果高级别的level为aarch32,那么低级别的level一定得为aarch32
如果高级别的level为aarch64,那么低级别的level一可以为aarch32或aarch64
当一个异常发生时, the processor自动执行了如下动作:
- The SPSR_ELn is updated (where n is the Exception level where the exception is taken), to store the PSTATE information that is required to correctly return at the end of the exception.
- PSTATE is updated to reflect the new processor status (and this can mean that the Exception level is raised, or it can stay the same).
- The address to return to at the end of the exception is stored in ELR_ELn.
The _ELn suffix on register names denotes that there are multiple copies of these registers
existing at different Exception levels. This means, for example, that SPSR_EL1 is a different
physical register to SPSR_EL2.
而我们在异常处理中,又会调用下一级的函数来干活,图形也就如下所示:
当异常处理完成后,processor由高级别返回低级别时,使用ERET指令返回
5、异常向量表
每个异常级别都有自己的一套向量表,这些表的基地址分别写在VBAR_EL3, VBAR_EL2 and VBAR_EL1系统寄存器中.
向量表中的每个条目有16 instructions long(0x80字节)(在ARMv7-A和AArch32中,每个条目只有4个字节)。这意味着在AArch64中顶层处理程序可以直接在向量中,而不是跳转到其它地址处执行.
VBAR_ELn执行的每个table中,定义了16个entries,具体走哪一个entry是由下面几个因素决定的:
• The type of exception (SError, FIQ, IRQ, or Synchronous)
• If the exception is being taken at the same Exception level, the stack pointer to be used (SP0 or SPn).
• If the exception is being taken at a lower Exception level, the Execution state of the next lower level (AArch64 or AArch32).
一张经典的向量表,如下所示:
举一个超级简单的例子:
kernel code执行在EL1,这时来了一个IRQ,该中断没有配置到hypervisor和secure environment中,所以它的处理仅仅是在kernel中完成,程序跳转到VBAR_EL1+0x280,栈使用sp_el1(将SPSel设置程sp_el1)
6、异常返回
软件必须告诉处理器何时从异常中返回。这是通过代码完成的使用ERET指令。这将从SPSR_ELn中恢复异常前的PSTATE并返回通过从ELR_ELn恢复PC,将程序执行返回到原始位置。
在A64指令集中,使用寄存器X30(与RET指令一起)返回子例程
ELR_ELn寄存器用于存储来自异常的返回地址。它的价值寄存器是自动写入的入口异常,并被写入到PC作为其中之一执行用于从异常中返回的ERET指令的效果。
除了SPSR和ELR寄存器之外,每个异常级别都有自己专用的堆栈指针登记。它们是SP_EL0、SP_EL1、SP_EL2和SP_EL3。这些寄存器用来指向专用的栈。堆栈可以,例如,用来存储寄存器被损坏异常处理程序,使它们可以在返回之前恢复到原来的值原始代码
处理程序代码可以从使用SP_ELn切换到使用SP_EL0。例如,SP_EL1可能指向存储小堆栈的内存块,内核可以始终保证该小堆栈是有效的。SP_EL0可能指向较大的内核任务堆栈. 但不能保证不发生溢出。这切换通过写入SPSel寄存器来控制。
7、PSTATE
当前processor的状态保存在PSTATE,当异常到来时,PSTATE的值会自动保存在SPSR中。 aarch64中由三个SPSR : SPSR_EL3, SPSR_EL2, and SPSR_EL1
例如,如果发生了一个异常target到EL1,那么当前处理器的状态会自动保存到SPSR_EL1中;
7、中断的处理流程
作者:代码改变世界ctw
文章来源: https://blog.csdn.net/weixin_42135087/article/details/109025760/
推荐阅读
欢迎大家点赞留言,更多Arm技术文章动态请关注极术社区Arm技术专栏欢迎添加极术小姐姐微信(id:aijishu20)加入技术交流群,请备注研究方向。