2

在 Linux 源代码(版本 2.6.18)中:

movl $swapper_pg_dir-__PAGE_OFFSET,%eax
movl %eax,%cr3
movl %cr0,%eax
orl $0x80000000,%eax
movl %eax,%cr0          /* ..and set paging (PG) bit */
ljmp $__BOOT_CS,$1f     /* Clear prefetch and normalize %eip */

还有load_cr3(pgdir)andwrite_cr3(x)宏:

#define load_cr3(pgdir) write_cr3(__pa(pgdir))

#define write_cr3(x) \
__asm__ __volatile__("movl %0,%%cr3": :"r" (x))

似乎整个cr3控制寄存器都存储了Page Directory的地址。但是,当我参考 intel ia-32 Developer's_Manual 时,它讲述了一个不同的故事。以下是英特尔手册的内容:

name      0.............11   12.................31
cr3       flags              address of page directory
PDE       flags              address of page table
PTE       flags              address of 4kb page frame

手册说 20 个最高有效位cr3存储页面目录的地址而不是整个cr3寄存器。这也是合理的,因为页面目录正好是 4kb,所以地址的 12 个最低有效位始终为零。

是不是有点奇怪?linux 代码只是将页面目录的地址分配给 .cr3而不是swapper_pg_dir. 寄存器存储的究竟是什么cr3,地址或英特尔手册建议的格式?

以下链接是英特尔手册: http: //www.intel.com/content/www/us/en/processors/architectures-software-developer-manuals.html

4

2 回答 2

4

对于 32 位分页,页目录的地址必须是 4096 的倍数,即其 12 LSB 为零。但是,设置 cr3 的操作码加载 32 位,而不是 20 位。加载 cr3 时,它的高 20 位用于页面目录地址,低 12 位被解释为可能影响较新处理器版本中的分页行为的标志。这些标志的“安全”设置为零,而这正是 Linux 所做的:它使用 32 位值加载 cr3,而该值的 12 LSB 恰好等于 0(因为该 32 位值已被用作内存地址是 4096 的倍数)。

于 2011-10-27T11:49:14.240 回答
2

如果swapper_pg_dir-__PAGE_OFFSET是 4096 的倍数,这没什么奇怪的。

CR3 LSB 中的零是有效的:

  • 保留位必须设置为 0
  • 更新的(从 i80386 开始)功能也可以通过将相关位设置为 0 来禁用,通常这是保持 x86 CPU 向后兼容旧软件的方法。
于 2011-10-27T11:36:28.440 回答