我最近研究了IA32e分页,虽然我知道它是如何工作的,但是当我遇到一个真实的例子时,我无法理解每个条目中的值表示什么。
我已经阅读了手册,它告诉我有几个标志位需要设置,我试图将以下示例中的PML4E, PDPTE和PDE的值分解为手册上写的格式,但结果似乎是错误的。
//======= init page
.align 8
.org 0x1000
__PML4E:
.quad 0x102007
.fill 255,8,0
.quad 0x102007
.fill 255,8,0
.org 0x2000
__PDPTE:
.quad 0x103003
.fill 511,8,0
.org 0x3000
__PDE:
.quad 0x000083
.quad 0x200083
.quad 0x400083
.quad 0x600083
.quad 0x800083
.quad 0xe0000083 /*0x a00000*/
.quad 0xe0200083
.quad 0xe0400083
.quad 0xe0600083 /*0x1000000*/
.quad 0xe0800083
.quad 0xe0a00083
.quad 0xe0c00083
.quad 0xe0e00083
.fill 499,8,0
代码来自书<<64位操作系统的设计与实现。代码在这个GitHub存储库
中可用。内核在内存0x100000处加载;__PML4E、__PDPTE和__PDE相对于内核加载位置存储在偏移量0x1000、0x2000、0x3000处
但我不能理解的是,为什么有0x102007而不是0x102000, 0x103003而不是0x103000,以及__PDE中复杂的值。
值为0x102007
的PML4E是0x102000 + FLAG_PRESENT + FLAG_WRITE + FLAG_USER
,它将该表项控制的512gb区域设置为可写且可访问的CPL >代码;0(并标记条目存在)。
值为0x103003
的PDPTE是0x102000 + FLAG_PRESENT + FLAG_WRITE
,它将该表项控制的1GiB区域设置为可写,但不能被带有CPL >的代码访问;0(并标记条目存在)。
值为0x000083
的PDE是0x000000 + FLAG_PRESENT + FLAG_WRITE + FLAG_PAGESIZE
,这使得PDE直接映射一个可写的2MiB页面,该页面不能被CPL >代码访问;0(并标记条目存在)。
假设设置了分页,这些分页结构将创建以下内存映射:
0 - 10MiB Identity mapped as writable for the kernel
10MiB - 26MiB Mapped to 0xe0000000 as writable for the kernel
26MiB - 1GiB Not mapped
1GiB - 512GiB Not mapped
512GiB - 64TiB Not mapped
64TiB - 64TiB + 512GiB Alias to range 0 - 512GiB
64TiB + 512GiB - 256TiB Not mapped