CR3 值与 pgd_t 的区别

4

我在玩耍,试图在我的安装了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);

4.15.0-45通用版,KPTI已关闭(i9-9900K具有硬件缓解措施) - user1637056
@user1637056:所以第一个 pr_err 在你读取 current->mm->pgd->pgd 之前运行。如果您使用一个调用该函数的格式字符串来处理两个操作数,会发生什么? - Peter Cordes
1
你提供的参考资料没有涉及到四级页表。你有没有其他的参考资料可以说明在x86-64中如何使用pgd? - prl
所有的代码都在Linux内核中运行。 如果我将两者放在同一行pr_err中,那么它们是相同的。 就我所理解的而言,我所提供的参考是通用的Linux处理分页的参考。 - user1637056
我看到了,但是我至少应该有40位是相同的(这40位是我需要找到PML4的),但我甚至没有看到那些。 - user1637056
显示剩余8条评论
1个回答

3
从Linux 4.14开始,可以通过调用__sme_pa并将pgd传递给__sme_pa来将pgd转换为要在cr3中使用的页面全局目录的物理页面地址。请注意,返回值的最低有效12位(表示ASID)为零。因此,必须将ASID与其进行OR运算。
在Linux 4.14之前,可以使用__pa代替不支持的__sme_pa。请注意,在Intel处理器上,__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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接