异常与中断
概述
异常和中断是处理器从正常程序执行流跳转到特权模式的一种机制,用于应对各种意外或预期的事件。这些机制帮助处理器解决执行过程中遇到的问题,维护系统的稳定性,处理外部事件的响应。
-
异常(Exception)是指处理器在执行当前指令时遇到无法继续执行的情况,需要立即暂停正常的程序流,并进入异常处理程序。异常通常是同步的,即它们与当前正在执行的指令直接相关。常见的异常类型包括:
-
非法指令:当处理器遇到无法识别或执行的指令时,会产生非法指令异常。
- 地址未对齐异常:当执行加载或存储操作时,访问的内存地址未对齐,处理器会引发异常。
- 页面错误:在虚拟内存系统中,当页表缺失或内存访问权限不足时,会发生页错误异常。
- 环境调用(系统调用):应用程序通过特定指令请求内核服务时,也会触发异常。
- 硬件错误:当处理器执行加载或存储操作时,总线地址请求对应数据不存在时,处理器会引发异常。
- 双重陷入:当处理器执行异常/中断处理程序时,再次发生异常/中断,处理器会引发异常进行双重陷入处理。
-
中断(Interrupt)是由外部硬件设备(如计时器、外设等)触发的信号,要求处理器暂停当前执行的程序,去处理这些外部事件。中断是异步的,即它们与当前指令执行无关,可能在任何时刻发生。根据中断来源的不同,可以分为以下几类:
-
硬件中断:由外部硬件设备产生,如外设的输入输出请求、定时器中断等。
- 软件中断:由软件触发,用于与操作系统交互或执行某些系统级别的任务。
- 陷入(Trap)是一种处理器从用户模式或较低特权级别切换到特权模式(如内核模式)处理事件的机制。处理器通过陷入机制捕获异常或中断,保存上下文信息,并跳转到相应的处理程序。处理完成后,处理器通过返回指令(如 mret 或 sret)恢复之前的执行状态,继续执行原来的程序。
异常
昆明湖 V2R2 支持多种异常,如下表所示:
| 异常编号 | trap原因 | tval更新值 | tval2更新值 |
|---|---|---|---|
| 0 | 指令地址非对齐 | 0 | 0 |
| 1 | 取指令权限异常(非跨页) | 指令起始地址 | 0 |
| 1 | 取指令权限异常(跨页) | 下一页首地址 | 0 |
| 2 | 非法指令 | 非法指令编码 | 0 |
| 3 | 断点 | 异常指令地址 | 0 |
| 3 | EBREAK 指令 | 0 | 0 |
| 4 | LOAD 地址非对齐 | 访存的起始地址 | 0 |
| 5 | LOAD 权限异常 | 实际 fault 的起始地址 | 0 |
| 6 | STORE/AMO 地址非对齐 | 访存的起始地址 | 0 |
| 7 | STORE/AMO 权限异常 | 实际 fault 的起始地址 | 0 |
| 8 | U-ECALL | 0 | 0 |
| 9 | S-ECALL | 0 | 0 |
| 10 | VS-ECALL | 0 | 0 |
| 11 | M-ECALL | 0 | 0 |
| 12 | 指令页表异常(非跨页) | 指令起始地址 | 0 |
| 12 | 指令页表异常(跨页) | 下一页首地址 | 0 |
| 13 | LOAD 页表异常(非跨页) | 访存的起始地址 | 0 |
| 13 | LOAD 页表异常(跨页) | 实际 fault 的起始地址 | 0 |
| 15 | STORE/AMO 页表异常(非跨页) | 访存的起始地址 | 0 |
| 15 | STORE/AMO 页表异常(跨页) | 实际 fault 的起始地址 | 0 |
| 16 | 双重陷入异常 | 0 | 第二次异常的编号 |
| 19 | 硬件错误 | 实际 fault 的起始地址 | 0 |
| 20 | 客户机指令页表异常(非跨页) | 指令起始地址 | 对应的 GPA |
| 20 | 客户机指令页表异常(跨页) | 下一页首地址 | 实际 fault 的 GPA |
| 21 | 客户机 LOAD 页表异常(非跨页) | 访存的起始地址 | 对应的 GPA |
| 21 | 客户机 LOAD 页表异常(跨页) | 实际 fault 的起始地址 | 实际 fault 的 GPA |
| 22 | 虚拟化指令异常 | 非法指令编码 | 0 |
| 23 | 客户机 STORE/AMO 页表异常(非跨页) | 访存的起始地址 | 对应的 GPA |
| 23 | 客户机 STORE/AMO 页表异常(跨页) | 实际 fault 的起始地址 | 实际 fault 的 GPA |
注意:香山实际上不存在指令地址非对齐异常。
我们以机器模式为例,介绍异常处理的步骤。
异常响应
第一步:处理器保存发生异常的 PC 到 mepc 中。
第二步:将 mcause 的中断标志位置为 0 ,同时将异常编号写入 mcause ,并修改对应的 mtval。
第三步:将 mstatus 的 MIE 位保存到 MPIE 位,然后将 MIE 位清零。将 mstatus 的 MPV 位与 MPP 位分别置为当前的 Virtual Mode 和 Privilege Mode,并根据条件修改对应的 GVA位。
第四步:根据 mtvec 取对应的指令并执行。
异常返回
异常返回通过 mret 指令实现,该指令执行下列操作。
- 根据 mepc 恢复 PC。
- 根据 mstatus 的 MPIE 位恢复 mstatus 的 MIE 位。
- 将当前的 Privilege Mode 改为 mstatus 的 MPP 位,且如果 MPP 位为机器模式,则将 Virtual Mode 置为 0,否则置为 mstatus 的 MPV 位。
中断
昆明湖 V2R2 支持多种中断,如下表所示:
| 中断编号 | trap原因 |
|---|---|
| 1 | 监管模式软件中断(SSI) |
| 2 | 虚拟监管模式软件中断(VSSI) |
| 3 | 机器模式软件中断(MSI) |
| 5 | 监管模式定时器中断(STI) |
| 6 | 虚拟监管模式定时器中断(VSTI) |
| 7 | 机器模式定时器中断(MTI) |
| 9 | 监管模式外部中断(SEI) |
| 10 | 虚拟监管模式外部中断(VSEI) |
| 11 | 机器模式外部中断(MEI) |
| 12 | 监管模式客户机外部中断(SGEI) |
| 13 | 本地计数器溢出中断(LCOFIP) |
| 16-23 | 标准本地中断 |
| 24-31 | 自定义中断 |
| 32-47 | 标准本地中断 |
| 48-63 | 自定义中断 |
我们以机器模式为例,介绍中断处理的步骤
中断优先级
昆明湖 V2R2 的中断优先级,如下表所示:
| 中断优先级 | 组别 | 编号 | 描述 |
|---|---|---|---|
| 最高 | Custom Group 0 | 63, 31, 62 | 最高优先级 Custom 中断 |
| 61, 30, 60 | |||
| Local Group 0 | 47, 23, 46 | 高优先级 Local 中断 | |
| 45, 22, 44 | |||
| 43, 21, 42 | |||
| 41, 20, 40 | |||
| Custom Group 1 | 59, 29, 58 | 次高优先级 Custom 中断 | |
| 57, 28, 56 | |||
| TSEO Group | 11, 3, 7 | 机器模式中断:外部、软件、时钟 | |
| 9, 1, 5 | 监管模式中断:外部、软件、时钟 | ||
| 12 | 监管模式客户机外部中断 | ||
| 10, 2, 6 | 虚拟监管模式中断:外部、软件、时钟 | ||
| 13 | 本地计数器溢出中断 | ||
| Custom Group 2 | 55, 27, 54 | 中等优先级 Custom 中断 | |
| 53, 26, 52 | |||
| Local Group 1 | 39, 19, 38 | 低优先级 Local 中断 | |
| 37, 18, 36 | |||
| 35, 17, 34 | |||
| 33, 16, 32 | |||
| Custom Group 3 | 51, 25, 50 | 最低优先级 Custom 中断 | |
| 最低 | 49, 24, 48 |
中断响应
第一步:处理器执行完当前指令后,将下一条指令的 PC 存入 mepc。
第二步:将 mcause 的中断标志位置为 1 ,同时将异常编号写入 mcause ,并将 mtval 置为 0。
第三步:将 mstatus 的 MIE 位保存到 MPIE 位,然后将 MIE 位清零。将 mstatus 的 MPV 位与 MPP 位分别置为当前的 Virtual Mode 和 Privilege Mode,并根据条件修改对应的 GVA位。
第四步:根据 mtvec 取对应的指令并执行。
中断返回
- 根据 mepc 恢复 PC。
- 根据 mstatus 的 MPIE 位恢复 mstatus 的 MIE 位。
- 将当前的 Privilege Mode 改为 mstatus 的 MPP 位,且如果 MPP 位为机器模式,则将 Virtual Mode 置为 0,否则置为 mstatus 的 MPV 位。