我一直在研究分页和访问控制如何在 x86-64 上工作,并且试图了解用于页面条目的 USER 标志与用户模式进程的内存访问之间的交互。
据我所知,在页表条目中设置 USER 标志允许从用户模式(环 3)访问页面。然而,我的问题是:
如果地址空间上半部分(通常由内核使用)中的页面与 PML4、PML3、PML2 和 PT 条目中设置的 USER 标志进行映射,这是否意味着用户模式进程可以访问该地址,或者在 CPU 级别是否有额外的强制措施(例如,规范地址限制)来阻止用户模式代码访问该区域,即使它被标记为 USER?
用户空间可以访问设置了 USER 位的高半页。
这在实践中通常在 32 位内核中完成,例如 Linux 的常见配置是 3:1 用户:内核分割,以允许单个用户空间进程拥有高达 3 GiB 的虚拟地址空间。
高半内核只是一种软件约定,并未纳入 ISA。
x86-64 Linux 将
[vsyscall]
页映射到所有用户空间进程的相同高地址;此机制已被 vDSO 废弃,vDSO 在下半部分顶部附近使用随机地址的页面(0x00007ff ...),允许它们纯粹在用户空间中运行 clock_gettime
和 getpid
,而无需缓慢的 syscall
指令进入内核。 在我的桌面上,cat /proc/self/maps
在 7ffc149f4000 处显示靠近下半部分顶部的 [vdso]
页面,但在 [vsyscall]
处显示 ffffffffff600000-ffffffffff601000
。 (vdso 和 vsyscall 是什么?)。 显然,[vsyscall]
页面仍然可以向后兼容,因此我们有一个在 x86-64 上的高半地址运行代码的用户空间的真实示例。
我知道 x86-64 假设 MSB-set = kernel 的一个情况是在 Intel 的 LAM(线性地址屏蔽)中,这是一项可选功能,可以通过使硬件忽略一些高位来加速标记指针。 它可用于用户空间地址、内核地址或两者,您可以选择 48 位或 57 位地址。 最高位必须与位 #47 或位 #56 匹配,留下 6 或 15 位供其他用途。 (使用 64 位指针中额外的 16 位 / https://lwn.net/Articles/902094/)。
AMD 的 UAI(高位地址忽略)忽略前 7 位;我还没有深入研究过它,所以不知道它是否在硬件中基于符号扩展低 57 位来区分内核与用户。
ARM TBI(顶部字节忽略)也类似,但如果它根据高位对地址进行用户与内核分类,则再次 IDK。 (或者不被忽略的最高位。)