我试图尽可能地了解这个OSDEV tutorial的内容。我按照建议阅读了AMD64程序员manaul(第2卷)第4章和第5章,但我不明白当他经历这个循环时会发生什么:
mov ebx, 0x00000003 ; Set the B-register to 0x00000003.
mov ecx, 512 ; Set the C-register to 512.
.SetEntry:
mov DWORD [edi], ebx ; Set the uint32_t at the destination index to the B-register.
add ebx, 0x1000 ; Add 0x1000 to the B-register.
add edi, 8 ; Add eight to the destination index.
loop .SetEntry ; Set the next entry.
我明白为什么他把ebx设置为3,但除此之外,我看不出他在ID地图2 MB上做了什么。
答案 0 :(得分:0)
mov ebx, 0x00000003 ; Set the B-register to 0x00000003.
代码使用ebx保留要写入下一页表条目的值。它将其初始化为3
,以设置 present 和可写位(位0和1)。从这里开始,它将在每次循环迭代时向其添加0x1000
,这不会影响这两位。物理地址字段为零,因此这使第一个条目映射到物理地址为零。
mov ecx, 512 ; Set the C-register to 512.
循环运行512次迭代,每页表项一次迭代。每个条目为64位(8字节)。长模式下的一页表可以容纳512个条目。 512是4096/8。
.SetEntry:
mov DWORD [edi], ebx ; Set the uint32_t at the destination index to the B-register.
写一页表条目。
add ebx, 0x1000 ; Add 0x1000 to the B-register.
将要写入下一页表条目的物理地址增加4KB。每个页表条目映射4KB。
add edi, 8 ; Add eight to the destination index.
将下一个页表项写入页表的下一项。每个页表项均为8个字节。
loop .SetEntry ; Set the next entry.
循环指令的意思是ecx = ecx - 1
jnz .SetEntry
。如果将ecx
减1之后,如果ecx
不为零,它将运行循环的另一次迭代。由于ecx
在循环前已初始化为512,因此上述指令将重复512次。 / p>
由于第一个条目使用的物理地址为零,并且每个后续条目的物理地址都高4KB,每个条目映射的是4KB,并且其中有512个,因此此代码填充了虚拟地址0(包括端值)的页表条目到2MB(不包括)的条目,这些条目的身份映射到物理内存的前2MB。 “身份”映射是指对其进行映射,以便物理地址等于线性地址。长模式下的每个页表都映射2MB的地址空间。由于此代码填充了一个页面表,因此它映射了2MB。
请注意,仅此代码不足以设置分页。此代码仅填充页表条目。该代码适用于32位PAE分页或长模式分页。
在PAE分页中,您还需要设置另外两个页面。对于长模式,您需要设置其他三个页面。 PAE分页使用3级转换,其中顶层映射1GB区域,中间映射2MB区域,而页表映射4KB区域。
长模式分页使用4级(或在最新的处理器上,它可以是5级)分页。在长模式下,顶层映射512GB区域,第二层映射1GB区域,第三层映射2MB区域,最外层映射4KB区域。
除了您问题代码中显示的设置之外,用于设置身份映射的代码还需要设置上述页面。