nemu-riscv 特权指令杂谈
做PA的时候忽略了讲义上的一段话,导致做PA的时候苦苦调试了好两天的nemu/Spike(www)
如果你仔细RTFM, 你会发现标准RISC-V的分页机制需要在S模式及U模式下才能开启, 而在M模式下的访存并不会进行MMU的地址转换. 但我们在NEMU中进行了简化, 允许M模式的访存也进行地址转换, 这样可以避免引入S模式相关的细节, 让大家把注意力集中在分页机制本身.
但是, 既然踩了很久的坑, 那么还是写一下吧
mstatus
寄存器
讲义上说可以把mstatus设置成0x1800(pass difftest),但实际上仔细研读手册/spike代码发现mstatus的初始值应该是0
ecall/mret行为:
ecall
的时候保存当前状态进mstatus.MPP
;设置MIE
mret从mstatus.MPP
恢复当前状态并清除位
嵌套中断?
有几个比较重要的位:
MPP (Machine Previous Privilege) (11:12)
保存进入异常前的特权级别
00:用户模式(U-mode)
01:监督模式(S-mode)
11:机器模式(M-mode)
这里是保存了previous_privilege, 也就是执行ecall时候的特权记别, 之前以为他保存了当前的特权基本导致调试了很久
当前的特权级应该不是由csr/通用寄存器来存储的,应该是硬件内部的行为->看见spike的源代码里面获取特权级是reg_t mode = proc->state.prv;
, 并不是通用寄存器
MPRV(Modify PRiVilege)
这个位会修改加载和存储操作的有效权限级别
- 当 MPRV=0 时,加载和存储操作按照当前权限模式的翻译和保护机制执行,行为正常。
- 当 MPRV=1 时,加载和存储的内存地址会被翻译和保护,且应用字节序,就好像当前权限模式被设置为 MPP(Machine Previous Privilege)一样。
- 指令地址的翻译和保护不受 MPRV 设置的影响。
- 如果不支持 U-mode,MPRV 是只读的 0。
- 执行 MRET 或 SRET 指令且权限模式降级到比 M 模式更低时,MPRV 会被设置为 0。
SUM
怪怪的,手册上似乎没有说相关的内容
MIE(Global interrupt-enable bits)
M-Mode 的中断使能位
P.s. SIE是S-Mode的中断使能位
mcause
mcause 非常多, PA中能用到的就下面几个
- 0xb
- 0x8
- timer-interrupt
虚拟内存
页表转换就不详细写了, 操作系统基础(^-^)
来聊一聊PTE的权限位把
1 |
|
V:valid,有效
X W R Meaning
0 0 0 Pointer to next level of page table.
0 1 1 Read-only page.
1 1 0 Reserved for future use.
0 1 1 Read-write page.
0 0 1 Execute-only page.
1 0 1 Read-execute page.
0 1 0 Reserved for future use.
1 0 1 Read-write-execute page.
U:User 用户权限能访问
G:Global mapping
A:Accessed 被访问过
D:Ditry 被写入过
emm, 这一段非常曲折, 我没有认真看讲义, 也没有很认真看rv手册, 调试了很久Spike后反回来看手册, 然后发现M-Mode是不会进行虚拟地址转换的!
对于S-Mod, 可以设置SUM位来允许M-Mod访问用户态的页表
一开始没看手册, debug调试到这里发现反回levels是0(页表极数为0),就不进行地址转换
1 |
|
一种(投机取巧)的difftest方案
由于nemu-spike没有设置对于csr的difftest,就有一个投机取巧的方案(感觉也不是很好)
就是逐个把csr寄存器都出来,然后就可以diff出问题了
1 |
|
1 |
|
关于gdb调试NEMU-Spike
spike的代码还是很庞大的,如果没有gdb调试很难找到关键位置
但是在gdb里面默认调试spike的时候是”NO SOURCE AVAILABLE”
尝试把编译选项加上了-g -O3
后依旧没有用
检查编译的elf:
1 |
|
发现有绝对路径,能正常调试
1 |
|
发现能正常查看共享库
1 |
|
发现(Objfile has no debug information.)
如果太长了想记录一下输出可以
1 |
|
最后检查发现是有一个参数
1 |
|
这个参数隐藏了符号