x86 cr3和linux swqpper_pg_dir

时间:2011-10-27 11:23:54

标签: linux assembly

在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

2 个答案:

答案 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中的零有效:

  • 保留位必须设置为0
  • 更新(因为i80386)功能可以通过将相关位设置为0来禁用,通常这是使x86 CPU向后兼容旧软件的方法。