【问题标题】:x86 cr3 and linux swqpper_pg_dirx86 cr3 和 linux swqpper_pg_dir
【发布时间】:2011-12-16 10:36:40
【问题描述】:

在 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-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

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

是不是有点奇怪? linux代码只是将页面目录的地址分配给cr3,而不是swapper_pg_dir的20个最高有效位。 cr3 寄存器存储的究竟是什么,intel 手册建议的地址或格式?

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

【问题讨论】:

  • 那么,您的问题是什么?你知道,一个带有问号之类的句子......
  • 抱歉,我会修改它。

标签: assembly linux-kernel x86 osdev page-tables


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    如果swapper_pg_dir-__PAGE_OFFSET 是 4096 的倍数,这并不奇怪。

    CR3 LSB 中的零有效:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-02
      • 1970-01-01
      • 2019-07-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多