当我读到head.s(Linux内核文件之一)时,我遇到了一个问题。

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