在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)macros:
#define load_cr3(pgdir) write_cr3(__pa(pgdir)) #define write_cr3(x) \ __asm__ __volatile__("movl %0,%%cr3": :"r" (x))
整个cr3控制寄存器似乎存储了页面目录的地址。 但是,当我参考intel ia-32开发者手册时,它讲述了一个不同的故事。 以下是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注册是商店,地址或英特尔手册build议的格式?
以下链接是英特尔手册: 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所做的:它加载了一个32位值的cr3,恰好有12个LSB等于零(因为这个32位值被当作一个内存地址是4096的倍数)。
没有什么奇怪的,如果swapper_pg_dir-__PAGE_OFFSET
是4096的倍数。
CR3 LSB中的零有效: