ARMv8 异常模型

系列上篇:ARMv8指令集架构

Overview

在详细解释 AArch64 Exception 模型之前,我们需要引入权限的概念。

现代软件被开发成分成不同的模块,每个模块对系统和处理器资源的访问级别不同。这方面的一个例子是操作系统内核和用户应用程序之间的分离。操作系统需要执行我们不希望用户应用程序能够执行的操作。内核需要对系统资源进行高级访问,而用户应用程序需要有限的系统配置能力。特权决定软件实体可以查看和控制哪些处理器资源。

AArch64 架构通过实现不同级别的特权来实现这种划分。当前特权级别只能在处理器接受异常或从异常中返回时更改。因此,这些特权级别在 Arm 架构中被称为异常级别。

Exception levels

需要注意的一点在于:该体系结构没有指定什么软件使用哪个异常级别,只是常见或标准软件采用此模型。

:::warning
异常转移:

当出现异常时,异常级别可以增加或保持不变。您永远不能通过异常转移到较低的特权级别。从异常返回时,异常级别可以降低或保持不变。您永远不能通过从异常返回来移动到更高的特权级别。

:::

异常类型

同步异常

同步异常与当前正在执行的指令直接相关。例如,同步异常将由试图写入 MMU 定义的只读位置的指令触发。

有四种产生同步异常的原因

Invalid instructions and trap exceptions

尝试执行无效指令可能会导致同步异常。导致无效指令的原因有很多,包括未定义的指令、当前异常级别不允许的指令或已被禁用的指令。任何执行内核无法识别的指令的尝试都会生成UNDEFINED异常。

当执行特定操作(例如读取特定寄存器)时,陷阱会触发异常。

例如,EL1 的操作系统内核可能会禁用 EL0 的浮点指令,以节省应用程序之间上下文切换的时间。这被称为惰性上下文切换;例如,如果在上下文切换之前未使用 SIMD 或浮点 (FP) 单元,则可以减少压入堆栈的寄存器数量。然后可以使用陷阱异常来处理边缘情况。

在这种情况下,操作系统内核可以通过禁用 SIMD/FP 单元来监视 SIMD/FP 操作的状态。当执行 FP 或 SIMD 指令时,将在 EL1 处将陷阱异常带到操作系统内核。然后内核可以启用 SIMD/FP 单元,执行失败的指令并设置一个标志来声明 SIMD/FP 单元已被使用。这可确保在下一次上下文切换时将大型 SIMD/FP 寄存器文件包含在寄存器上下文中。如果在下一次上下文切换时没有断言标志,则不需要包括 SIMD/FP 寄存器。

内存访问

内存访问也可能导致同步异常。这可能是 MMU 执行检查的结果,也可能是由于内存系统返回的错误。

例如,当启用 MMU 时,将检查所有由加载和存储指令引起的内存访问。如果您尝试从非特权代码访问特权地址,或尝试写入只读地址,则触发异常。当然,内存访问也可以生成异步异常

异常生成指令/系统调用

Arm 架构包括异常生成指令SVC、HVC和SMC。这些指令的目的仅仅是为了生成异常并使 PE 能够在异常级别之间移动:

  • Supervisor Call ( SVC) 指令使 EL0 的用户程序能够请求 EL1 的 OS 服务
  • 如果实施了虚拟化扩展,则Hypervisor Call ( HVC) 指令可用,使操作系统能够在 EL2 上请求管理程序服务
  • Secure Monitor Call ( SMC) 指令,如果实现了安全扩展,则可用,使普通世界能够从 EL3 的固件请求安全世界服务

当 PE 在 EL0 执行时,它不能直接调用 EL2 的管理程序或 EL3 的安全监视器,因为这只能从 EL1 和更高版本调用。EL0 的应用程序必须使用 SVC 调用内核,并让内核执行调用更高异常级别的操作。

调试异常

调试异常是路由到托管调试器的异常级别的同步异常。然后调试器代码的执行很像异常处理程序代码。

有许多特定的同步调试异常,包括:

  • 断点指令异常
  • 断点异常
  • 观察点异常
  • 向量捕获异常
  • 软件步骤异常

异步异常

异步异常与当前正在执行的指令没有直接关联,通常是来自处理器外部的系统事件。这可能是软件需要响应的系统事件,例如计时器的活动或屏幕的触摸。我们不知道它们何时会发生。异步异常也称为中断。

物理中断

物理中断通常由外围设备产生。系统不是内核不断轮询外部信号,而是通过生成中断来通知内核必须发生某些事情。

例如,系统可能使用通用异步接收器/发送器 (UART) 接口与外界通信。当 UART 接收数据时,它需要一种机制能够告诉处理器新数据已经到达并准备好进行处理。UART 可以使用的一种机制是生成中断以向处理器发出信号。

复杂的系统可能有许多具有不同优先级的中断源,包括嵌套中断处理的能力,其中较高优先级的中断可以中断较低优先级的中断。内核响应此类事件的速度可能是系统设计中的一个关键问题,称为中断延迟。

错误SError

系统错误 (SError) 是一种异常类型,旨在由内存系统生成以响应意外事件。我们不希望发生这些事件,但需要知道它们是否已经发生。这些是异步报告的,因为触发事件的指令可能已经停用。

SError 的一个典型示例是以前称为外部异步中止的情况。SError 中断的示例包括:

     已通过所有 MMU 检查但随后在内存总线上遇到错误的内存访问
     在某些 RAM 上进行奇偶校验或纠错码 (ECC) 检查,例如内置高速缓存中的那些
     将脏数据从高速缓存行回写到外部存储器触发的中断

SErrors 被视为一个单独的异步异常类,因为您通常会对这些情况有单独的处理程序。SError 生成是实现定义的。

IRQ 和 FIQ

Arm 架构有两种异步异常类型,IRQ 和 FIQ,旨在用于支持外设中断的处理。这些用于发出外部事件信号,例如定时器关闭,并不表示系统错误。它们是与处理器指令流异步的预期事件。

在旧版本的 Arm 架构中,FIQ 被用作更高优先级的快速中断。这与 AArch64 不同,在AArch64 中,FIQ 与 IRQ 具有相同的优先级。

掩蔽

物理和虚拟异步异常都可以被临时屏蔽。这意味着异步异常可以保持在挂起状态,直到它们被取消屏蔽并采取异常。这对于处理嵌套异常特别有用。

不能屏蔽同步异常。这是因为同步异常是由指令的执行直接引起的,因此如果它们被挂起或忽略,将会阻止执行。

异常向量表

ARM v8有4个异常级别,每一个异常级别对应一个 VBAR(Vector Base Address Register) 寄存器,用来指向异常向量表的基地址,同时每一个异常向量表会分为4组,每一组包含4 种异常,

  • 如果发生异常并不会导致exception level切换,并且使用的栈指针是SP_EL0,那么使用第一组异常向量表。
  • 如果发生异常并不会导致exception level切换,并且使用的栈指针是SP_EL1/2/3,那么使用第二组异常向量表。
  • 如果发生异常会导致exception level切换,并且比目的exception level低一级的exception level运行在AARCH64模式,那么使用第三组异常向量表。
  • 如果发生异常会导致exception level切换,并且比目的exception level低一级的exception level运行在AARCH32模式,那么使用第四组异常向量表。



发生异常时,先根据所处异常级别,根据VBAR_ELx找到异常向量表,再根据发生的异常类型分组,有不同的偏移量。

相关推荐
搬砖的小码农_Sky1 小时前
C语言:数组
c语言·数据结构
朝九晚五ฺ2 小时前
【Linux探索学习】第十四弹——进程优先级:深入理解操作系统中的进程优先级
linux·运维·学习
自由的dream2 小时前
Linux的桌面
linux
xiaozhiwise2 小时前
Makefile 之 自动化变量
linux
周三有雨4 小时前
【面试题系列Vue07】Vuex是什么?使用Vuex的好处有哪些?
前端·vue.js·面试·typescript
意疏4 小时前
【Linux 篇】Docker 的容器之海与镜像之岛:于 Linux 系统内探索容器化的奇妙航行
linux·docker
BLEACH-heiqiyihu5 小时前
RedHat7—Linux中kickstart自动安装脚本制作
linux·运维·服务器
爱米的前端小笔记5 小时前
前端八股自学笔记分享—页面布局(二)
前端·笔记·学习·面试·求职招聘
一只爱撸猫的程序猿5 小时前
一个简单的Linux 服务器性能优化案例
linux·mysql·nginx