在当前的 Linux 中,请参阅arch/x86/entry/calling.h
asm.macro SWITCH_TO_USER_CR3_NOSTACK
和其他内容来了解 Linux 如何在内核与用户 CR3 之间切换。以及之前对其使用的常量的评论:
/*
* PAGE_TABLE_ISOLATION PGDs are 8k. Flip bit 12 to switch between the two
* halves:
*/
#define PTI_USER_PGTABLE_BIT PAGE_SHIFT
#define PTI_USER_PGTABLE_MASK (1 << PTI_USER_PGTABLE_BIT)
#define PTI_USER_PCID_BIT X86_CR3_PTI_PCID_USER_BIT
#define PTI_USER_PCID_MASK (1 << PTI_USER_PCID_BIT)
#define PTI_USER_PGTABLE_AND_PCID_MASK (PTI_USER_PCID_MASK | PTI_USER_PGTABLE_MASK)
Run Code Online (Sandbox Code Playgroud)
看起来内核 CR3 始终是较低的,因此设置当前 CR3 中的位 12 始终使其指向用户空间页目录。 (如果当前任务有用户空间,并且启用了 PTI。这些 asm 宏仅在即将返回用户空间的代码路径中使用。)
.macro SWITCH_TO_USER_CR3_NOSTACK scratch_reg:req scratch_reg2:req
...
mov %cr3, \scratch_reg
...
.Lwrcr3_\@:
/* Flip the PGD to the user version */
orq $(PTI_USER_PGTABLE_MASK), \scratch_reg
mov \scratch_reg, %cr3
Run Code Online (Sandbox Code Playgroud)
这些宏用在entry_64.S
、entry_64_compat.S
、 和entry_32.S
返回用户空间的路径中。
大概有一种更简洁的方法可以从 C 访问用户空间页表。
最好的选择可能是查看页面错误处理程序以了解它如何访问进程的页表。(或者mmap
的实现MAP_POPULATE
)。