head.s
的代码片段如下所示:
movl $swapper_pg_dir-0xc0000000,%eax movl %eax,%cr3 /* set the page table pointer.. */ movl %cr0,%eax orl $0x80000000,%eax movl %eax,%cr0 /* ..and set paging (PG) bit */
在内核启用分页机制之前(当然PE标志现在已经被启用),它将临时页目录表的地址加载到%cr3
。
问题是:
我认为内核应该直接把$swapper_pg_dir
值放入%eax
而不是$swapper_pg_dir-0xc0000000
。 我知道我错了,但为什么?
内核将内存视为基于0xC0000000。 任何内存分配,指针或全局,位于0xC0000000到0xFFFFFFFF之间。 但是,对于硬件控制器(如MMU或任何协处理器),内存窗口基于0x00000000。
所以,在将一个指向表或描述符的指针加载到HW引擎时,它必须基于0x00000000
OP询问为什么Linux从swapper_pg_dir
减去0xc0000000
。 这个数学的原因是%cr3
需要物理地址,而$swapper_pg_dir
是一个虚拟地址。 在内核页面初始化的初始阶段,有8MB RAM的映射( 0 to 0x007fffff
)。 第一次映射是one to one
的虚拟地址0x00000000-0x007fffff
而其他是0xc0000000-0xcoo7fffff
。 为了得到swapper_pg_dir
物理地址,我们必须从swapper_pg_dir
地址中减去0xc0000000
。