我正在玩耍,尝试在安装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);
答案 0 :(得分:3)
从Linux 4.14开始,可以通过调用pgd
并将其传递给{{1},将cr3
转换为要在__sme_pa
中使用的页面全局目录的物理页面地址。 }。请注意,返回值的最低有效12位(代表ASID)为零。因此,必须对ASID进行“或”运算。
在Linux 4.14之前,可以使用pgd
代替不受支持的__pa
。请注意,__sme_pa
与Intel处理器上的__pa
等效,因为SME仅在AMD处理器上可用。
至少从Linux 2.6开始,__sme_pa
和pgd
可能相等,也可能不同,这取决于两个因素:
cr3
是否大于内核映像pgd
的虚拟基址。__START_KERNEL_map
,它是内核映像的编译时物理基址与映像的运行时物理基址之间的差。如果图像已重定位,则phys_base
不会为零。翻译过程由称为__phys_addr的函数执行,可以参考以下示例。
我已经在两个系统上对此进行了测试。在Linux 4.4.0上,我得到以下值:
phys_base
在这种情况下,cr3 = 0x3581E000
pgd = 0x3581E000
__pa(pgd) = 0x3581E000
__START_KERNEL_map = 0x80000000
phys_base = 0x00000000
和pgd
是等效的。在Linux 4.15上:
cr3