Blog icon indicating copy to clipboard operation
Blog copied to clipboard

aarch64体系结构与编程6--ARM64的异常处理(Exception Model)

Open jason--liu opened this issue 4 years ago • 0 comments

ARM64的异常等级

ARM64异常等级:

  • EL0:非特权模式,例如应用程序
  • EL1:特权模式,例如OS内核
  • EL2:虚拟化监控程序,例如hypervisor
  • EL3:安全模式,例如secure monitor

image

ARM64异常的一些基本概念

  • Taking an exception:正在处理一个异常
  • Returning from an exception:从一个异常中返回
  • Exception levels:异常等级
  • Precise exception:精准异常
  • Synchronous and asynchronous exception:同步异常与异步异常

同步异常和异步异常

同步异常:

  • 系统调用:svc,hvc,SMC等
  • MMU引发的异常
  • SP和PC对齐检查
  • 未分配的指令

image image

异步异常:

  • IRQ中断
  • FIQ中断
  • SError

异常入口(Exception entry)

当异常发生时刻,CPU硬件做了哪些事情?

  • PSTATE保存到SPSR_ELx
  • 返回地址保存ELR_ELx
  • PSTATE寄存器里的DAIF域都设置为1,相当于把调试异常、系统错误(SError)、IRQ中断以及FIQ中断都关闭了
  • 更新了ESR_ELx寄存器,里面包含了同步异常发生的原因
  • SP切换到SP_ELx
  • 切换到对应的EL,然后跳转到异常向量表里执行

image

当异常发生后,操作系统需要做哪些事情?

操作系统需要做事情:根据异常发生的类型,跳转到合适的异常向量表。 异常向量表的每个表项会保存一个异常处理的跳转函数,然后跳转到恰当的异常处理函数并处理异常。

异常返回

操作系统执行一条eret语句, 硬件会做如下事情:

  • 从ELR_ELx寄存器中恢复PC指针
  • 从SPSR_ELx寄存器恢复处理器的状态

image

异常返回地址

返回地址两个寄存器:

  • X30:子函数的返回地址。使用ret指令来返回
  • ELR_Elx:异常返回地址。使用eret指令来返回 ELR_Elx寄存器保存了异常返回地址:
  • 对于异步异常,它的返回地址是中断发生时的下一条指令,或者没有执行的第一条指令
  • 对于不是system call的同步异常,返回的是 触发同步异常的那一条指令
  • 对于system call,它是返回svc指令的下一条指令

image

异常处理的路由

  • 异常发生的时候,异常处理可以在当前EL也可以在更高的EL
  • EL0不能用来处理异常
  • 同步异常是可以在当前的EL里处理的,比如在EL1里发生了同步异常
  • 对于异步异常,可以路由到EL1, EL2, EL3处理,需要配置HCR以及SCR相关寄存器

栈的选择

  • 每个异常等级EL都有对应栈指针寄存器SP(SP_EL0,SP_EL1,SP_EL2,SP_EL3)
  • 栈必须16字节对齐。硬件可以检测栈指针是否对齐
  • 当异常发生时,并跳转到目标异常等级时,硬件会自动选择SP_ELx
  • 操作系统负责分配和保证 每个异常等级EL对应的栈,是可用的

异常处理的执行模式

  • 当异常发生时,切换到高级别的EL,这个EL运行在哪个模式?Aarch64 or aarch32?
    • HCR_EL2.RW记录了 EL1要运行在哪个模式? 1:表示aarch64, 0:表示aarch32
  • 当异常发生后,执行模式可以发生改变 一个aarch32位的应用程序正在运行,这时候来了一个中断,它可能会跑到 aarch64执行状态下的 EL1里处理 这个中断

异常返回的执行模式

从一个异常返回是,SPSR寄存器记录了:

  • 返回到哪个EL? SPSR.M[3:0]
  • 返回目标EL的执行模式?SPSR.M[4]
  • M[4] = 0,表示aarch64;M[4] = 1,表示aarch32

image image See armv8.6手册的第D1.6.4章

异常向量表(Exception vectors)

  • 每个异常等级EL都有自己的异常向量表,EL0除外
  • 异常向量表的基地址需要设置到VBAR_ELx寄存器中
  • VBAR_EL1寄存器见armv8.6手册的第D13.2.137章 image VBAR寄存器的Bit[10:0] 是保留的, 也就是说 异常向量表的起始地址必须以2KB字节对齐
  • 每个表项可用存放32条指令,一共128个字节 异常向量表: image 对应内核代码实现: image
  • kernel_ventry是一个宏,它的实现在同一个文件里,简化后的代码片段如下 image
  • align 7表示按照2的7次方大小来对齐,2的7次方是128个字节。
  • sub指令是让栈指针sp减去一个S_FRAME_SIZE,其中S_FRAME_SIZE称为寄存器框架大小,也就是struct pt_regs数据结构的大小
  • 以发生在EL1的IRQ中断为例,这条语句变成了“b el1_irq”

保存异常上下文

栈框:Linux内核中定义了一个struct pt_regs的数据结构来描述内核栈上保存寄存器的排列信息,通常用于保存中断上下文等信息。 image 栈框保存 image

同步异常的解析

异常综合信息寄存器ESR_ELx

image 见armv8.6手册的第D13.2.36章 ESR寄存器一共包含4个字段(域),其中:

  • Bit 32~63,是保留的比特位
  • Bit 26-31,是异常类型(Exception Class,简称EC),这个字段指示发生异常的类型,同时用来索引ISS域(Bit 0-24)
  • Bit 25,IL,表示同步异常的指令长度
  • Bit 0~24,ISS(Instruction Specific Syndrome)具体的异常指令编码。这个异常指令编码表依赖不同的异常类型,不同的异常类型有不同的编码格式

异常类型EC

比如 EC == 0b000000 Unknown reason. EC == 0b000001 Trapped WFI or WFE instruction execution. ... EC == 0b100000 Instruction Abort from a lower Exception level. EC == 0b100001 Instruction Abort taken without a change in Exception level. EC == 0b100100 Data Abort from a lower Exception level

ISS字段的编码方式

每个异常类型(EC)对应不同的ISS字段的编码方式 image

数据异常的ISS域的解析

比如: EC == 0b100100 Data Abort from a lower Exception level. image

失效地址寄存器FAR寄存器

image FAR寄存器保存了发生异常时刻的虚拟地址。

jason--liu avatar Dec 23 '20 12:12 jason--liu