机器模式最重要的特性是拦截和处理异常(不寻常的运行时事件)的能力。
RISC-V将 异常分为两类。
- 一类是同步异常,这类异常在指令执行期间产生,如访问了无效的存储器 地址或执行了具有无效操作码的指令时。
- 另一类是中断,它是与指令流异步的外部事件, 比如鼠标的单击。
RISC-V中实现精确例外:保证异常之前的所有指令都完整地执行了,而后续的指令都没有开始执行(或等同于没有执行)
在M模式运行期间可能发生的同步例外有五种:
- 访问错误异常 当物理内存的地址不支持访问类型时发生(例如尝试写入ROM)。
- 断点异常 在执行ebreak指令,或者地址或数据与调试触发器匹配时发生。
- 环境调用异常 在执行ecall指令时发生。
- 非法指令异常 在译码阶段发现无效操作码时发生。
- 非对齐地址异常 在有效地址不能被访问大小整除时发生,例如地址为0x12的 amoadd.w。
Machine Mode下的异常处理
必须要处理如下的8个寄存器:
- mtvec(Machine Trap Vector)
- 保存发生异常时处理器需要跳转到的地址;
- mepc(Machine Exception PC)
- 对于同步异常,指向发生异常的指令
- 对于中断,执行中断处理后,应该恢复执行的位置;
- mcause(Machine Exception Cause)
- 指示发生异常的种类
- mie(Machine Interrupt Enable)
- 指出处理器目前能处理和必须忽略的中断。
- mip(Machine Interrupt Pending)
- 列出目前正准备处理的中断。
- mtval(Machine Trap Value)
- 保存了陷入(trap)的附加信息:地址例外中出错的地址、发生非法指令例外的指令本身;
- 对于其他异常,它的值为0。
- mscratch(Machine Scratch)
- 暂时存放一个字大小的数据。
- mstatus(Machine Status)
- 保存全局中断使能,以及许多其他的状态;
- 处理器在M模式下运行时,只有在全局中断使能位mstatus.MIE置1时才会产生中断.此外,每个中断在控制状态寄存器mie中都有自己的使能位
发生异常时,硬件自动经历如下状态转换
- 异常指令的PC被保存在mepc中,并将PC值设置为mtvec;
- 根据异常来源设置mcause;
- 将mtval设置为出错的地址或 者其它适用于特定异常的信息字;
- 将mstatus中的MIE位置零以禁用中断,并将先前的MIE值保留到MPIE中;
- 将发生异常之前的权限模式保留在mstatus的MPP域中,再把权限模式更改为 M。
- 此时可以进入异常服务程序;
异常服务程序
- 在异常服务程序中,为了避免int reg中的值被覆盖,会先用mscratch和整数寄存器(例如a0)中的值交换;
- 通常,软件会让mscratch包含指向附加临时内存空 间的指针,处理程序用该指针来保存其主体中将会用到的整数寄存器;
- 在主体执行之 后,中断程序会恢复它保存到内存中的寄存器,然后再次使用mscratch和a0交换, 将两个寄存器恢复到它们在发生异常之前的值。
- 此时可以正常执行服务程序;
- 最后,处理程序用mret指令(M模 式特有的指令)返回。此过程为上述硬件执行过程的逆操作;
有个问题:
有时需要在处理异常的过程中转到处理更高优先级的中断。mepc, mcause,mtval 和mstatus 这些控制寄存器只有一个副本,那么在处理第二个中断的时候,怎么处理这些寄存器呢?
解决方式:
可抢占的中断处理程序可以在启用中断之前把这些寄存器保存到内存中的栈,然后在退出 之前,禁用中断并从栈中恢复寄存器。