RiscV 中从超级用户模式到用户模式的地址转换

问题描述 投票:0回答:1

假设我们在支持 M、S 和 U 模式的 HART 上,并且当前处于启用虚拟地址的 S 模式,并且

satp
指向当前 PTE 表(内核 PTE 表)。

现在假设我们要在 U 模式下启动一个进程,那么我首先分配所有所需的页面并填充新的进程 PTE 表(通过手动将主管虚拟地址转换为物理地址)。然而,在使用

sret
切换到 U 模式之前,我们首先需要加载进程 PTE 表的地址,因为在 U 模式下
satp
将无法访问。

但是当我们使用用户 PTE 表更新

satp
时,我们将无法访问我们的内核代码,因为
satp
立即开始转换虚拟地址,并且从现在起我们将只访问进程内存而不访问内核内存
 satp
不再指向内核 PTE 表。

我们也应该无法访问下一条指令,因为

pc
持有由旧PTE表管理的虚拟地址,因此不再有效,因为现在
satp
指向新的PTE表。

我找到的唯一解决方案是暂时关闭内核虚拟内存,手动翻译内核虚拟地址来存储内核内容,跳转到新PTE表指向的页面,在

satp
中加载新进程PTE表从而进入在用户进程虚拟内存中,然后发出
sret
进入 U 模式。

为用户进程启用虚拟内存而不干扰内核虚拟内存的正确方法是什么?

当我们想要管理在 S 模式下在 U 模式下发出的中断时,也会出现同样的问题。如果管理程序中断向量表存储在内核虚拟内存中而不是物理内存中,那么当用户进程引起中断时,MMU 将使用虚拟地址通过

satp
查找中断向量表,但
satp
现在指向不映射 IVT 的用户进程 PTE 表。

即使在这种情况下,我找到的唯一解决方案是在管理模式下暂时禁用虚拟内存,以便找到应该存储在众所周知的物理地址的内核 PTE 表的位置,以便在没有 MMU 的情况下找到该表。

有不依赖于禁用内核虚拟内存的解决方案吗?为什么 RiscV 规范没有添加新的 CSR 来仅在用户模式下管理地址转换?

riscv mmu supervisor-mode
1个回答
0
投票

但是当我们使用用户 PTE 表更新 satp 时,我们将无法访问内核代码,因为 satp 立即开始翻译虚拟地址,并且我们将仅访问进程内存而不是内核内存,因为现在 satp 不指向不再查看内核 PTE 表。

...

为用户进程启用虚拟内存而不干扰内核虚拟内存的正确方法是什么?

...

我可以想到两种方法:

解决方案1

将内核页面映射到每个用户进程的页表中,并清除内核页面 PTE 中的

U
位。这允许在 S 模式下运行的内核访问这些页面(在处理异常或中断时),并且如果在 U 模式下运行的进程尝试执行相同操作,则会触发页面错误。设置
SUM
位还可以让内核访问进程页面。

可以为内核 PTE 设置

G
(全局)位,以便在上下文切换之间在 TLB 中维护内核页面映射,从而提高性能。

这是在 Linux 内核和 egos-2000 端口

中完成的

解决方案2

内核有单独的页表。但保留一个映射到内核和进程页表的 trampoline 页,并保存修改

satp
和特权模式的代码。当切换到用户进程时,内核会跳转到该蹦床,并且异常和中断从蹦床中的某些代码开始,这些代码在跳转到相应的处理程序之前指向内核页表。
这节省了空间(更少的页表映射),但使上下文切换的成本更高一些。

xv6 操作系统的人们选择了这种方法。

© www.soinside.com 2019 - 2024. All rights reserved.