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找到异常向量表,再根据发生的异常类型分组,有不同的偏移量。

相关推荐
泽虞4 小时前
《STM32单片机开发》p7
笔记·stm32·单片机·嵌入式硬件
Yue丶越4 小时前
【C语言】数据在内存中的存储
c语言·开发语言·网络
田甲4 小时前
【STM32】 数码管驱动
stm32·单片机·嵌入式硬件
云计算练习生4 小时前
linux shell编程实战 10 Git工具详解与运维场景实战
linux·运维·git
up向上up4 小时前
基于51单片机垃圾箱自动分类加料机快递物流分拣器系统设计
单片机·嵌入式硬件·51单片机
虚伪的空想家6 小时前
KVM的ubuntu虚机如何关闭安全启动
linux·安全·ubuntu
t1987512812 小时前
在Ubuntu 22.04系统上安装libimobiledevice
linux·运维·ubuntu
skywalk816312 小时前
linux安装Code Server 以便Comate IDE和CodeBuddy等都可以远程连上来
linux·运维·服务器·vscode·comate
Yue丶越13 小时前
【C语言】字符函数和字符串函数
c语言·开发语言·算法
晚风吹人醒.13 小时前
缓存中间件Redis安装及功能演示、企业案例
linux·数据库·redis·ubuntu·缓存·中间件