首页 > 解决方案 > 如何直接从 32 位切换到 PAE 分页?

问题描述

我正在为我的个人研究开发一个微内核。我选择在 运行我的内核0xf0000000,为用户空间程序留下 3.75 GiB。当我的内核启动时,它会设置 32 位分页(带有硬编码的页目录和页表)。然后它检查主机是否支持 PAE 并设置页面目录指针表 (PDPT)。但是当我尝试将其加载到%cr3. 根据英特尔软件开发人员手册:

软件可以通过将带有 MOV 的 CR4.PAE 的值更改为 CR4 来在 32 位分页和 PAE 分页之间转换。

于是尝试使用如下代码切换到PAE分页:

movl %cr4, %eax
orl $(1 << 5), %eax
movl %eax, %cr4
movl %ebx, %cr3 // %ebx holds physical address to PDPT

或者,在 Intel 语法(或 NASM)中:

mov eax, cr4
or eax, 1 << 5
mov cr4, eax
mov cr3, ebx // ebx holds physical address to PDPT

但它失败了(在 QEMU 上)。它写入%cr4,设置%eip到下一条指令,执行它(至少 GDB 这么说),然后重置。%cr3我之前尝试写信%cr4,但结果仍然相同。

然后我尝试通过以下方式切换到 PAE 分页:unset PG -> set PAE -> write to %cr3-> set PG,我成功了。但我想直接切换到 PAE 分页。这怎么可能?

标签: assemblyx86pagingosdevpage-tables

解决方案


最后,感谢@Brendan和他的宝贵评论,我找到了直接切换到 PAE 分页的方法。要直接从 32 位分页切换到 PAE 分页,我不得不欺骗 CPU。我的内核的虚拟基础位于0xf0000000. 所以在我跳到更高的一半之后,前 960 个 PDE 没有被使用。因此,我将新的 PDPT(页面目录指针表)复制到了我最初的 32 位页面目录。然后我设置了 PAE 位,CPU 很高兴,因为它只读取了保存 PDPT 的初始页面目录的前 32 个字节。

过程是这样的:

  1. memcpy (initial_page_directory, new_pdpt, 32);
  2. 启用 PAE 位%cr4。CPU 愉快地从您在步骤 1 中覆盖的初始页面目录的前 32 个字节读取 PDPT。
  3. 将您的新 PDPT 加载到%cr3.

注意:如果您尝试在第 1 步和第 2 步之间访问前 32 MiB 的映射内存(如果您已映射它)(可能是未定义的行为或可能是三重故障和重置),则此过程将不起作用。


推荐阅读