在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控制寄存器存储了Page Directory的地址。但是,当我参考intel ia-32Developer'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
手册说cr3的20 MSB存储页面目录的地址而不是整个cr3寄存器。这也是合理的,因为页面目录正好是4kb,因此地址的12 LSB始终为零。
是不是有点奇怪,因为linux代码只是将页面目录的地址分配给cr3而不是swapper_pg_dir的20 MSB。
我的问题是cr3寄存器到底是什么商店,地址或者英特尔手册建议的格式?
以下链接是英特尔手册:http://www.intel.com/content/www/us/en/processors/architectures-software-developer-manuals.html
答案 0 :(得分:2)
对于32位寻呼,页面目录的地址必须是4096的倍数,即其12 LSB为零。但是,用于设置cr3的操作码加载32位,而不是20位。当加载cr3时,其20个高位用于页面目录地址,低12位被解释为标志,这可能影响较新处理器版本中的分页行为。这些标志的“安全”设置为零,这正是Linux所做的:它加载cr3的32位值,恰好其12 LSB等于零(因为该32位值已被视为内存地址是4096的倍数。
答案 1 :(得分:1)
如果swapper_pg_dir-__PAGE_OFFSET
是4096的倍数,那就没什么奇怪了。
CR3 LSB中的零有效: