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
。