在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)和write_cr3(x)宏:
#define load_cr3(pgdir) write_cr3(__pa(pgdir))

#define write_cr3(x) \
__asm__ __volatile__("movl %0,%%cr3": :"r" (x))
似乎整个cr3控制寄存器都存储页面目录的地址。但是,当我引用intel ia-32Developer's_Manual时,它讲述了一个不同的故事。以下是intel手册的内容:
name      0.............11   12.................31
cr3       flags              address of page directory
PDE       flags              address of page table
PTE       flags              address of 4kb page frame
手册说cr3的20 MSB存储页面目录的地址,而不是整个cr3寄存器。由于页面目录正好是4kb,因此地址的12 LSB始终为零,这也是合理的。
是不是有点奇怪,因为linux代码只是将页面目录的地址分配给cr3而不是swapper_pg_dir的20 MSB。
我的问题是cr3寄存器究竟是什么存储,地址或intel手册建议的格式?
以下链接是intel手册:http://www.intel.com/content/www/us/en/processors/architectures-software-developer-manuals.html

最佳答案

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

10-05 23:46