Introduce riscv mxr bit.
Normal MXR
MXR(Make eXecutable Readable)是mstatus中的一个bit。
RISCV SPEC规定:
- MXR=0, 只有PTE.R=1,load才能成功
- MXR=1,PTE.R=1或者PTE.X=1,load都能成功
- 当基于页面的虚拟内存无效时,MXR不起作用
所以它只影响DTLB,而不影响ITLB。
场景:
- LOAD指令,M模式,或者S模式Bare模式,MXR不起作用
- LOAD指令,S模式SV39/SV48,MXR==0,PTE.R==0 & PTE.X==1,产生load page fault
- LOAD指令,S模式SV39/SV48,MXR==1,PTE.R==0 & PTE.X==1,成功,不产生load page fault
Hypervisor MXR
在Hypervisor的情况下,不光mstatus中有mxr,vsstatus中也有mxr。
RISCV SPEC规定:
- HS-level status.MXR影响所有stage(VS-STAGE and G-STAGE)
- vsstatus.MXR只影响第一级stage(VS-STAGE)
补充说明hypervisor下:
- VS STAGE 发生FAULT报 page fault
- G STAGE 发生FAULT 报 guest page fault
场景:
- vsstatus.MXR=0, sstatus.MXR=0
- vs-stage: PTE.R==1, g-stage: PTE.R=1, 成功
- vs-stage: PTE.R==0 & PTE.X==1, g-stage: PTE.R=1, 失败,page fault
- vs-stage: PTE.R==1, g-stage: PTE.R==0 & PTE.X==1, 失败,guest page fault
- vs-stage: PTE.R==0 & PTE.X==1, g-stage: PTE.R==0 & PTE.X==1, 失败,page fault
- vsstatus.MXR=0, sstatus.MXR=1
- vs-stage: PTE.R==1, g-stage: PTE.R=1, 成功
- vs-stage: PTE.R==0 & PTE.X==1, g-stage: PTE.R=1, 成功
- vs-stage: PTE.R==1, g-stage: PTE.R==0 & PTE.X==1, 成功
- vs-stage: PTE.R==0 & PTE.X==1, g-stage: PTE.R==0 & PTE.X==1, 成功
- vsstatus.MXR=1, sstatus.MXR=0
- vs-stage: PTE.R==1, g-stage: PTE.R=1, 成功
- vs-stage: PTE.R==0 & PTE.X==1, g-stage: PTE.R=1, 成功
- vs-stage: PTE.R==1, g-stage: PTE.R==0 & PTE.X==1, 失败,guest page fault
- vs-stage: PTE.R==0 & PTE.X==1, g-stage: PTE.R==0 & PTE.X==1, 失败,guest page fault
- vsstatus.MXR=1, sstatus.MXR=1
- vs-stage: PTE.R==1, g-stage: PTE.R=1, 成功
- vs-stage: PTE.R==0 & PTE.X==1, g-stage: PTE.R=1, 成功
- vs-stage: PTE.R==1, g-stage: PTE.R==0 & PTE.X==1, 成功
- vs-stage: PTE.R==0 & PTE.X==1, g-stage: PTE.R==0 & PTE.X==1, 成功
判断条件:
- vs-stage时:拿来判断的mxr = sstatus.mxr | vsstatus.mxr
- g-stage时:拿来判断的条件 mxr = sstatus.mxr
spike hypervisor mxr处理
来看看在spike中对mxr的处理。
1 | reg_t mmu_t::s2xlate(reg_t gva, reg_t gpa, access_type type, access_type trap_type, bool virt, bool hlvx) |
从代码上可以看出:
- walk 执行的是vs-stage,s2xlate执行的是g-stage。
- proc->state.v表示当前是在vs/vu虚拟状态下
这里奇怪的是:会根据proc->state.v来决定选vsstatus还是mstatus。比如在g-stage时,v=1,选vsstatus,v=0,选mstatus。这里和上面spec规定的好像相反了,spec规定g-stage只和mstatus.MXR相关,为什么v=1时要选vsstatus呢??
这是因为在spike中,当切换virtualization时(需要满足一定条件),会调换mstatus和vsstatus。具体参见processer.cc
- 当HS时,mstatus就是mstatus,vsstatus就是vsstatus
- 当从HS切换到VS时,将mstatus和vsstatus调换。变成了:mstatus其实是vsstatus,vsstatus其实是mstatus。
- 当VS切换回HS时,再将mstatus和vsstatus调换。变成了:mstatus就是mstatus,vsstatus就是vsstatus
这么做的目的是:在VS模式下,软件仍然会访问sstatus,但这是访问的sstatus其实是需要访问vsstatus。所以如果按照上述规则,做个调换,在VS模式下访问的sstatus其实就是vsstatus,这样简化了设计。
因此,如果设计也按照上述规则来做的话,逻辑会变成这样:
V=0时:
- 和vsstatus.MXR不相关,都使用sstatus.MXR,只会有一个stage页表转换。
- sstatus.MXR==0,PTE.R==0 & PTE.X==1,产生load page fault
- sstatus.MXR==1,PTE.R==0 & PTE.X==1,成功,不产生load page fault
V=1时:
- sstatus.MXR(其实是vsstatus.MXR)=0, vsstatus.MXR(其实是sstatus.MXR)=0
- vs-stage: PTE.R==1, g-stage: PTE.R=1, 成功
- vs-stage: PTE.R==0 & PTE.X==1, g-stage: PTE.R=1, 失败,page fault
- vs-stage: PTE.R==1, g-stage: PTE.R==0 & PTE.X==1, 失败,guest page fault
- vs-stage: PTE.R==0 & PTE.X==1, g-stage: PTE.R==0 & PTE.X==1, 失败,page fault
- sstatus.MXR(其实是vsstatus.MXR)=0, vsstatus.MXR(其实是sstatus.MXR)=1
- vs-stage: PTE.R==1, g-stage: PTE.R=1, 成功
- vs-stage: PTE.R==0 & PTE.X==1, g-stage: PTE.R=1, 成功
- vs-stage: PTE.R==1, g-stage: PTE.R==0 & PTE.X==1, 成功
- vs-stage: PTE.R==0 & PTE.X==1, g-stage: PTE.R==0 & PTE.X==1, 成功
- sstatus.MXR(其实是vsstatus.MXR)=1, vsstatus.MXR(其实是sstatus.MXR)=0
- vs-stage: PTE.R==1, g-stage: PTE.R=1, 成功
- vs-stage: PTE.R==0 & PTE.X==1, g-stage: PTE.R=1, 成功
- vs-stage: PTE.R==1, g-stage: PTE.R==0 & PTE.X==1, 失败,guest page fault
- vs-stage: PTE.R==0 & PTE.X==1, g-stage: PTE.R==0 & PTE.X==1, 失败,guest page fault
- sstatus.MXR(其实是vsstatus.MXR)=1, vsstatus.MXR(其实是sstatus.MXR)=1
- vs-stage: PTE.R==1, g-stage: PTE.R=1, 成功
- vs-stage: PTE.R==0 & PTE.X==1, g-stage: PTE.R=1, 成功
- vs-stage: PTE.R==1, g-stage: PTE.R==0 & PTE.X==1, 成功
- vs-stage: PTE.R==0 & PTE.X==1, g-stage: PTE.R==0 & PTE.X==1, 成功
- 判断条件:
- vs-stage时:拿来判断的mxr = vsstatus.mxr | sstatus.mxr
- g-stage时:拿来判断的条件 mxr = vsstatus.mxr