CR3值与pgd_t之间的差异

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

我正在玩,并试图在安装了Linux的x86_64 CPU上手动执行页表行走。

我想通过使用Linux API并手动查看页表值来尝试获得相同的值。

我在这里找到:https://www.kernel.org/doc/gorman/html/understand/understand006.html,CR3的值应该等于current-> mm-> pgd。但它不是:

current->mm->pgd = 0x457ec6067
cr3 = 0x45700a006

current-> mm-> pgd似乎在运行中保持不变。我错过了什么?

谢谢!

编辑。这是我的代码:

 __asm__ __volatile__ (
    "mov %%cr3, %%rax\n\t"
    "mov %%rax, %0\n\t" 
    : "=m" (cr3)  
    :
    : "%rax"  
     );
pr_err("cr3 = 0x%lx ", (long)cr3);
pr_err("\tcurrent->mm->pgd = 0x%lx\n", current->mm->pgd->pgd);
linux linux-kernel x86 x86-64 kernel-module
1个回答
3
投票

从Linux 4.14开始,pgd可以通过调用cr3并传递给它__sme_pa,转换为pgd中使用的页面全局目录的物理页面地址。请注意,返回值的最低有效12位(表示ASID)为零。所以ASID必须与它进行“或”运算。

在Linux 4.14之前,可以使用__pa代替不支持的__sme_pa。请注意,__pa相当于英特尔处理器上的__sme_pa,因为SME仅适用于AMD处理器。

至少从Linux 2.6开始,pgdcr3可能会或可能不会取决于两个因素:

  • pgd是否大于内核映像__START_KERNEL_map的虚拟基址。
  • phys_base,它是内核映像的编译时物理基地址与映像的运行时物理基地址之间的差异。如果图像已经重新定位,phys_base将不会为零。

翻译过程由名为__phys_addr的函数执行,您可以参考以下示例。

我在两个系统上测试了这个。在Linux 4.4.0上,我得到以下值:

cr3                 = 0x3581E000
pgd                 = 0x3581E000
__pa(pgd)           = 0x3581E000
__START_KERNEL_map  = 0x80000000
phys_base           = 0x00000000

在这种情况下,pgdcr3是等价的。在Linux 4.15上:

cr3                 = 0x8980A005
pgd                 = 0xC980A000
__pa(pgd)           = 0x8980A000
__START_KERNEL_map  = 0x80000000
phys_base           = 0xEC000000
© www.soinside.com 2019 - 2024. All rights reserved.