RISCV中CSRR指令访问机器模式只读CSR异常触发不一致问题
RISC-V架构下S模式访问机器模式只读CSR异常触发不一致问题分析
问题现象
在验证RISC-V架构CSR访问模式时,测试监管者模式(S模式)下访问机器模式只读CSR的权限,发现异常触发存在不一致:
- 连续执行两条
CSRR指令时,第一条触发异常,第二条未触发; - 当
CSRR指令放在代码末尾时,未触发异常; - 执行
CSRRW指令时,能正常触发预期异常。
测试代码
机器模式初始化代码
la x6, supervisor_exception_handler csrw mtvec, x6 ## 写入异常处理程序地址到MTVEC csrr x30, 0x341 ## 读取初始MEPC值 csrr x31, 0x342 ## 读取初始MCAUSE值 # 保存当前MSTATUS到x28 csrr x28, 0x300 # 设置MPP字段为S模式(0b1) li x29, 0b1 slli x29, x29, 11 addi x28, x29, 0 # 将修改后的MSTATUS写回CSR csrw 0x300, x28 # 设置MEPC为S模式代码入口 la x28, supervisor_code csrw 0x341, x28 csrr x31, 0x300 mret
S模式测试代码
supervisor_code: csrr x6, 3860 li x7, 0x00000000 bne x6, x7, csr_fail csrr x6, 3860 li x7, 0x00000000 bne x6, x7, csr_fail li x5, 0xa5a5a5a5 csrrw x1, 3860, x5 li x5, 0x00000000 bne x5, x1, csr_fail li x5, 0x5a5a5a5a csrrw x1, 3860, x5 li x5, 0x00000000 bne x5, x1, csr_fail
异常处理程序代码
supervisor_exception_handler: csrr x30, 0x341 ## 读取异常触发地址MEPC csrr x31, 0x342 ## 读取异常原因MCAUSE li x2, 2 beq x31, x2, next_iter1 ## 检查是否为预期的非法指令异常 j csr_fail next_iter1: csrw 0x342, 0 ## 重置MCAUSE为0 beq x30, x0, csr_fail addi x7, x30, 12 jr x7 ## 跳转到MEPC + 12的位置
问题原因分析
异常返回的PC偏移错误
异常处理程序中,addi x7, x30, 12的偏移量不符合指令长度规范。RISC-V的CSRR指令长度为4字节,触发异常后MEPC指向该指令的地址,正确的跳过逻辑应该是addi x7, x30, 4。当前代码直接跳转到MEPC+12,会跳过后续两条指令(包括第二条CSRR),导致第二条指令未被执行,自然不会触发异常。代码末尾指令的执行机制问题
若CSRR指令放在代码末尾,部分处理器的指令提交机制可能因检测到后续无指令而提前终止执行,导致该指令未实际被硬件执行,因此不会触发异常。可在末尾添加nop指令验证该推测。硬件对不同CSR指令的权限检查差异
CSRR是只读指令,部分RISC-V硬件实现中,可能对无副作用的非法只读访问做了优化(比如预取阶段过滤但未触发异常);而CSRRW包含写操作,属于有副作用的指令,硬件必须严格执行权限检查,因此能稳定触发异常。根据RISC-V特权架构规范,任何非机器模式访问机器模式CSR(无论读写)都必须触发非法指令异常(Exception Code 2),此现象属于硬件实现的合规性问题。
内容的提问来源于stack exchange,提问作者Krishna
相关产品推荐
相关产品推荐

