构建64位操作系统-Intel架构:实模式,保护模式,实模式长寻址,IA-32e

1.Intel处理器架构-实模式

        BIOS加载引导程序开始执行时,程序位于实模式。

        实模式下特点有:

 1.1.实模式下的物理寻址       

jmp 0x1000:0x0010

          实模式下上述0x1000:0x0010对应的目标位置物理地址为0x1000 << 4 + 0x0010 = 0x10010。

1.1.1.实模式下物理地址位宽限制

        其中形如0x1000:0x0010这样的寻址形式。

        前一部分称为段地址,后一部分称为段内偏移。两个地址数值上必须限定在16位宽度。两部分合起来计算出的物理地址位宽限定在20位宽度。

        这样实模式下

        0xFFFF:0xFFFF = 0xFFFF << 4 + 0xFFFF = 0x10FFEF,这样的一个物理地址至少需要21个比特位来表达,就超过了20个比特位的限制。所以,0xFFFF:0xFFFF实际的物理地址为0xFFEF。超出20个比特位部分被舍弃掉了。

        这样实模式下,可表达的最大物理地址为0xFFFFF。这样的一个物理地址可用0xF000:0xFFFF来得到。

  1.2.寄存器和标号位数限制

es
cs
ds
...

        上述实模式下寄存器位数是16位。

Label1:
    xxxx
Label2 dd 0x00

        上述标号代表标号所在位置距离所在段首部的偏移。在实模式下上述标号数值是16位宽度的。

1.3.实模式下中断处理

        实模式下在物理地址[0, 1KB)范围内存储中断向量表。每个表项占据4B,共256项。

        每一项前2字节存储offset,后2字节存储segment。

2.Intel处理器架构-保护模式

        保护模式显著特点是重新设计了分段机制。

        物理内存的一块区域可被定义为一个段,段通过段描述符来描述该段的属性信息。

        特别的段描述符还可以用来描述调用门,陷阱门,中断门任务门以便实现特定的功能。

        段描述符需要存放在表结构中。

        存放段描述符的表结构有三种类型:

        一种称为GDT,全局描述符表。

        一种称为LDT,局部描述符表。

        一种称为LDT,中断描述符表。

        三种类型的表定位不同,分别用于存储符合其定位的段描述符。

2.1.GDT

        对保护模式来说,必须提供一个GDT以便处理器正常开展工作。

        GDT中存储的段,可以是用于描述一段代码区域的段,描述一段数据区域的段(包含描述栈区域的段)。特殊点的每个LDT表占据区域也构成一个段,这样的也须用段描述符来描述,且对应的描述符只能存储到GDT的表中。每个任务允许定义个称为TSS的区域,这个区域也构成一个段,这样的也须用段描述符来描述,且对应的描述符只能存储到GDT的表中。

2.1.1.8字节段描述符

        GDT中存储的段描述符占据8个字节。即64个比特位。我们对这64个比特位按从低到高进行编号,从0开始编号。

        编号[0,15]区域存储                           段长度的[0,15]

        编号[16, 31]区域存储                        段基地址的[0,15]

        编号[32, 39]区域存储                        段基地址的[16,23]

        编号[40,43]区域存储                         Type类型字段

        编号44区域存储                                S标志(系统段标志。1:非系统段,0:系统段)

        编号[45,46]区域存储                         DPL标志(段的特权级)

        编号47区域存储                                P标志(段在内存标志。1:在,0:不在)

        编号[48,51]区域存储                         段长度的[16,19]

        编号52区域存储                                AVL标志(一般为0)

        编号53区域存储                                L标志(保留,0)

        编号54区域存储                                D/B标志

        编号55区域存储                                G标志(尺寸粒度,1:4KB,0:字节)

        编号[56,63]区域存储                         段基地址的[24,31]

        

        D/B标志:

        对可执行代码段。为1时,默认下,段内地址是32位的。操作数是32位或8位的。

        对栈段。为1时,使用ESP作为栈指针。为0时,使用SP作为栈指针。

        对数据段。为1时,上边界为0xFFFF FFFF。为0时,上边界为0xFFFF。

2.1.2.2字节段选择子

        保护模式下,段寄存器内存储的2字节内容称为段选择子。16个比特位。我们对这16个比特位按从低到高进行编号,从0开始编号。

        编号[0,1]区域存储                           RPL(请求特权级)

       编号2区域存储                                 TI(0,GDT;1,LDT)

       编号[3, 15]区域存储                         段选择子索引

2.1.3.代码段

        S标志位为1,且编号43区域为1。此时段描述的类型称为代码段。

        进一步,此时,

        编号42区域称为C(一致性)标志位。为1时,称为一致性代码段。为0时,称为非一致性代码段。

        对一致性代码段有以下机制:

        当前程序(代码段)可执行或跳转到一个一致性代码段,即使该一致性代码段的特权级高于当前。且跳转后CPL不变。

        对非一致性代码段,上述跳转到一个更高特权级代码段是不可行的。

        

        编号41区域称为R(可读)标志位。表示这个段内容是否可被读取。代码段必然是可执行的,不可写的。但是否可读允许通过此位来配置。

        编号40区域称为A(访问)标志位。当代码段被访问时,处理器设置对应段描述符的A标志位为1。

2.1.4.数据段

         S标志位为1,且编号43区域为0。此时段描述的类型称为数据段。

          进一步,此时,

        编号42区域称为E(扩展方向)标志位。为1时,段向下扩展。为0时,段向上扩展。向上与向下扩展可以理解为从段基地址向段存储新数据时,新数据是存储到基地址之上,还是存储到基地址之下。对正常数据区域,是向上的。对栈,一般是向下的。               

        编号41区域称为W(可写)标志位。表示这个段内容是否可写。数据段必然是可可读的。但是否可写允许通过此位来配置。

        编号40区域称为A(访问)标志位。当代码段被访问时,处理器设置对应段描述符的A标志位为1。

2.1.5.系统段

        S标志位为0。此时段描述的类型称为系统段。

        对于系统段,需要结合编号[40,43]区域4个比特位来进一步确定段的类型。

43 42 41 40 系统段类型
0 0 0 0 保留
0 0 0 1 16位TSS段(有效的)
0 0 1 0 LDT段
0 0 1 1 16位TSS段(使用中)
0 1 0 0 16位调用门
0 1 0 1 任务门
0 1 1 0 16位中断门
0 1 1 1 16位陷进门
1 0 0 0 保留
1 0 0 1 32位TSS段(有效的)
1 0 1 0 保留
1 0 1 1 32位TSS(使用中)
1 1 0 0 32位调用门
1 1 0 1 保留
1 1 1 0 32位中断门
1 1 1 1 32位陷阱门

        对于LDT段描述符,用于描述LDT区域。LDT区域作为一个表,D/B标志位对其无意义,一般设置为0。

        对于TSS段描述符,用于描述TSS区域。        

2.1.6.TSS区域

        一个TSS区域的结构可以用如下表格来描述

偏移 尺寸 描述
0x00 2 上个任务的TSS选择子
0x02 2 保留
0x04 4 ESP0
0x08 2 SS0
0x0A 2 保留
0x0C 4 ESP1
0x10 2 SS1
0x12 2 保留
0x14 4 ESP2
0x18 2 SS2
0x1A 2 保留
0x1C 4 CR3
0x20 4 EIP
0x24 4 EFLAGS
0x28 4 EAX
0x2C 4 ECX
0x30 4 EDX
0x34 4 EBX
0x38 4 ESP
0x3C 4 EBP
0x40 4 ESI
0x44 4 EDI
0x48 2 ES
0x4A 2 保留
0x4C 2 CS
0x4E 2 保留
0x50 2 SS
0x52 2 保留
0x54 2 DS
0x56 2 保留
0x58 2 FS
0x5A 2 保留
0x5C 2 GS
0x5E 2 保留
0x60 2 LDT段选择子
0x62 2 保留
0x64 2 最低比特位是T标志,其余保留
0x66 2 I/O位图基地址

        上面表格中红色区域我们称为动态区域,绿色区域我们称为静态区域。

        TSS结构需要在如下场景中发挥作用:

        1.程序通过JMP/CALL提供的段选择子,定位到GDT中的TSS段描述符时。发生任务切换。

        此时TR所关联的TSS区域中的动态区域用于存储当前程序执行现场。所谓执行现场就是由动态区域中各个对应字段构成的。

        动态区域中"上个任务的TSS选择子"特殊处理,使用目标TSS区域中的"上个任务的TSS选择子"来记录上个程序的TSS选择子。

        同时会使用目标TSS区域中的静态区域来设置新任务的CR3,LDT,根据新任务的特权级相应设置SS,ESP为目标TSS区域中静态区域内对应值。

        2.程序通过JMP/CALL提供的段选择子,定位到GDT/LDT中的任务门描述符时。发生任务切换。

        具体当前程序的TSS区域的动态区域,目标程序的TSS区域的静态区域如何起作用参考1。

        3.触发中段或异常,且对应的处理表项是任务门描述符。发生任务切换。

        具体当前程序的TSS区域的动态区域,目标程序的TSS区域的静态区域如何起作用参考1。

        4.EFLAGS.NT设置为1时,执行IRET。发生任务切换。

        具体当前程序的TSS区域的动态区域,目标程序的TSS区域的静态区域如何起作用参考1。

        综上所述,TSS机制为任务切换提供的一种支持机制。借助TSS机制实现的任务切换可以让处理器帮应用自动处理执行现场保留,新任务必要执行环境设置等工作。

2.1.7.如何告知处理器GDT的位置信息

        处理器存在GDTR寄存器,用于存储GDT尺寸,GDT起始位置。

        可使用 "LGDT [SrcAddr]"告知。

        实模式下,默认操作数大小是16位。保护模式下,操作数大小需结合数据段的D/B标志位确定。IA-32e模式下默认64位。

2.2.LDT

        LDT表也用于存储保护模式下的8字节段描述符。不过无法存储描述LDT区域的描述符,描述TSS区域的描述符。

2.2.1.如何告知处理器LDT的位置信息        

        处理器存在LDTR寄存器。用于存储描述LDT区域的段选择子。

        使用 "LLDT LDT段的选择子" 告知。

2.3.如何从实模式切换到保护模式

        1.系统进入保护模式前,需创建一个拥有代码段描述符,数据段描述符的GDT(首个表项需为NULL描述符)。然后通过LGDT告知处理器GDT表尺寸,位置。

        2.LDT表的使用是可选的,如使用,则需准备LDT表。然后通过LIDT告知处理器LDT的段选择子。

        3.保护模式需开启分页机制下,开启分页机制前,需要准备好页目录表,页表。并将页目录表的物理地址加载到CR3控制寄存器。进入保护模式后,再置位CR0.PG可开启分页机制。

        4.进入保护模式前,需创建一个IDT。IDT可用于存储中断门描述符,陷阱门描述符,任务门描述符。然后通过LIDT告知处理器IDT表尺寸,位置。

        5.进入保护模式后,如果需要使用基于TSS区域的任务切换机制,则需在执行任务切换前,创建对应的TSS区域,TSS段描述符。使用LTR汇编指令将TSS段选择子加载到TR寄存器。以便处理器知道当前任务的TSS区域。

        如何进入保护模式?

        通过MOV指令置位CR0.PE后即进入保护模式。进入保护模式后,将从特权级0开始执行。

        一般推荐的实践方式为:

        1.CLI禁止可屏蔽硬件中断

        2.MOV 设置CR0.PE为1

        3.远跳转

        进入保护模式后,数据段寄存器仍保留着实模式的段数据,需重新加载数据段选择子或用JMP/CALL执行新任务来更新。

        使用STI使能可屏蔽硬件中断前,需用LIDT告知处理器IDT表的基地址和长度。

2.4.寻址能力

        实模式下,我们通过段寄存器,段内偏移,支持的寻址范围可用20个比特位来表示。

        保护模式下,我们的段基础地址,段偏移都是32位的,相应的寻址范围也变为32位比特位。

        但要让处理器允许我们寻址到超过20个比特位的地址空间,需要开启A20地址线才可以。

        以下是一种开启A20地址线的方法:

in	al,	92h
or	al,	00000010b
out	92h,	al

        即从io端口0x92先读取1字节,将读取1字节的比特位1(从0开始编号)设置为1后,再写入0x92端口即可。

2.5.实模式下进行4GB寻址的方法

        默认实模式下,通过16位段寄存器,16位段内偏移,支持的寻址范围是20个比特位。

        通过以下方法,可在实模式下进行4GB寻址:

        1.cli禁止中断

        2.准备GDT,通过LGDT告知处理器GDT尺寸,位置

        3.通过MOV置位CR0.PE进入保护模式

        4.通过MOV为希望具备4GB寻址的段寄存器p设置为保护模式GDT中支持4GB寻址数据段描述符的段选择子。

        5.通过MOV复位CR0.PE回到实模式

        这样操作后,实模式下使用p作为段寄存器,计算p:off的线性地址时,不再采用

        线性地址=p>>4+off的方式。而是采用

        线性地址=p对应数据段的32位Base+off

        值得注意的是,实模式下,搭配不具备p特征的段寄存器时,段内偏移只能使用16个比特位。搭配具备p特征的段寄存器时,段内偏移可以使用32个比特位。

mov	byte	[fs:edi],	al

2.6.IA-32e模式及其下的兼容模式,64位模式。

        IA-32e模式是Intel为64位处理器设计的新模式,也称长模式。包含兼容模式,64位模式两种子运行模式。

2.6.1.检测处理器是否支持IA-32e模式

        CPUID.80000001h:EDX[29].LM

2.6.2.IA-32e下地址空间

        线性地址位宽64位。有效地址是低48位用于线性地址寻址,高16位作为符号位扩展的地址。也称为Canonical地址。

        相应的Canonical型地址区间0x0000 0000, 0000 0000~0x0000 7FFF, FFFF FFFF和0xFFFF 8000, 0000 0000~0xFFFF FFFF, FFFF FFFF是程序可用区域。

2.6.3.IA-32e下段机制

        IA-32e下段机制继承自保护模式,又有较大改进。

        存放段描述符的表结构有三种类型:

        一种称为GDT,全局描述符表。

        一种称为LDT,局部描述符表。

        一种称为LDT,中断描述符表。

        三种类型的表定位不同,分别用于存储符合其定位的段描述符。

2.6.4.8字节代码段,数据段描述符

        IA-32e模式下,代码段,数据段的段基地址强制为0x00,段尺寸强制为无限制。

        我们对这64个比特位按从低到高进行编号,从0开始编号。

        编号[0,15]区域存储                           段长度的[0,15]

        编号[16, 31]区域存储                        段基地址的[0,15]

        编号[32, 39]区域存储                        段基地址的[16,23]

        编号[40,43]区域存储                         Type类型字段

        编号44区域存储                                S标志(系统段标志。1:非系统段,0:系统段)

        编号[45,46]区域存储                         DPL标志(段的特权级)

        编号47区域存储                                P标志(段在内存标志。1:在,0:不在)

        编号[48,51]区域存储                         段长度的[16,19]

        编号52区域存储                                AVL标志(一般为0)

        编号53区域存储                                L标志

        编号54区域存储                                D/B标志

        编号55区域存储                                G标志(尺寸粒度,1:4KB,0:字节)

        编号[56,63]区域存储                         段基地址的[24,31]

        

        上述是保护模式下8字节段描述符解析。

        IA-32e模式下(IA32_EFER.LMA=1),依然对代码段,数据段依然采用8字节段描述符。依然可按上述去解析。但不同之处在于。

        1.对代码段,L标志位为0时,处理器将运行在IA-32e的兼容子模式。此时完全按照和保护模式一致的方式去解释段描述符。

        2.对代码段,L标志位为1时,处理器将运行在IA-32e的64位子模式。此时D/B标志位必须是0。此时代码段的默认操作数位宽是32位。地址位宽是64位。 

        3.对数据段,

2.6.5.16字节系统段描述符

        IA-32e模式下,对系统段采用16字节段描述符。低8字节依然沿用保护模式下8字节段描述符格式。具体细节为:

        1.IA-32e模式下,系统段描述符类型

43 42 41 40 功能
0 0 0 0 16B描述符的高8B
0 0 0 1 保留
0 0 1 0 LDT段描述符
0 0 1 1 保留
0 1 0 0 保留
0 1 0 1 保留
0 1 1 0 保留
0 1 1 1 保留
1 0 0 0 保留
1 0 0 1 64位TSS段描述符(有效的)
1 0 1 0 保留
1 0 1 1 64位TSS段描述符(使用中)
1 1 0 0 64位调用门描述符
1 1 0 1 保留
1 1 1 0 64位中断门描述符
1 1 1 1 64位陷阱门描述符

        2.对LDT段描述符,TSS段描述符

        多出来的高8字节,最高4字节保留,低4字节存储段基地址63:32。

        低8字节按保护模式下8字节解释。Type字段以1中为准。

        对于TSS段所描述的TSS区域,使用场景发生了较大改变。由于IA-32e模式不支持任务门机制。相应的,IA-32e模式下,TSS区域无需用来提供对任务切换时现场保存与恢复的支持。只需负责为不同特权级间的栈切换提供支持即可。

        相应的TSS区域结构变为如下

偏移 尺寸 描述
0x0 4 保留
0x4 4 RSP0的低32位
0x8 4 RSP0的高32位
0xC 4 RSP1的低32位
0x10 4 RSP1的高32位
0x14 4 RSP2的低32位
0x18 4 RSP2的高32位
0x1C 4 保留
0x20 4 保留
0x24 4 IST1低32位
0x28 4 IST1高32位
0x2C 4 IST2低32位
0x30 4 IST2高32位
0x34 4 IST3低32位
0x38 4 IST3高32位
0x3C 4 IST4低32位
0x40 4 IST4高32位
0x44 4 IST5低32位
0x48 4 IST5高32位
0x4C 4 IST6低32位
0x50 4 IST6高32位
0x54 4 IST7低32位
0x58 4 IST7高32位
0x5C 4 保留
0x60 4 保留
0x64 2 保留
0x66 2 I/O位图基地址

        IA-32e下,针对特权级0,1,2的SS段寄存器,支持加载NULL段选择子(GDT的0项)。

        IA-32e下,发生特权级切换时,新的SS段寄存器强制加载一个NULL段选择子。RSP将根据特权级被赋值为RSPn(n=0~2)。旧的SS,RSP将被保存到新栈中。

2.6.6.IA-32e模式下的调用门描述符

        IA-32e下调用门描述符从原来的8B扩充到16B.

        我们对这128个比特位按从低到高进行编号,从0开始编号。

        编号[0,15]区域存储                           段内偏移的[0,15]

        编号[16, 31]区域存储                        段选择子

        编号[32, 39]区域存储                        0

        编号[40,43]区域存储                         Type类型字段(1100)

        编号44区域存储                                S标志(系统段标志。1:非系统段,0:系统段)

        编号[45,46]区域存储                         DPL标志(段的特权级)

        编号47区域存储                                P标志(段在内存标志。1:在,0:不在)

        编号[48,63]区域存储                         段内偏移[16, 31]

        编号[64, 95]区域存储                        段内偏移[32, 63]

        编号[96, 127]区域存储                      保留       

        处理器在执行IA-32e模式的调用门时,将以8B的数据位宽向栈中压入数据。

        RETF指令的默认操作数是32位,若要返回到64位程序,需在RETF前额外加上前缀0x48。

2.6.7.IA-32e模式下的中断和异常处理

        IA-32e模式的中断/异常处理机制与保护模式的异常处理机制相似。

        不过中断发生时,栈空间的保存(SS, RSP)由选择性保存(特权级CPL变化时),改为无条件保存。

        IA-32e模式还引入了一种全新的中断栈切换机制。

        IA-32e模式的系统段描述符不再支持任务门描述符,只剩下陷阱门描述符,中断门描述符。

        

        我们对这128个比特位按从低到高进行编号,从0开始编号。

        编号[0,15]区域存储                           段内偏移的[0,15]

        编号[16, 31]区域存储                        段选择子[0,15]

        编号[32, 34]区域存储                        IST

        编号[35]区域存储                              0

        编号36区域存储                                S标志(系统段标志。1:非系统段,0:系统段)

        编号[37,39]区域存储                         0

        编号[40, 43]区域存储                        Type

        编号[44]区域存储                              0

        编号[45, 46]区域存储                        DPL

        编号47区域存储                                P

        编号[48, 63]区域存储                        段内偏移的[16, 31]

        编号[64, 95]区域存储                        段内偏移的[32, 63]

        编号[96,127]区域存储                       保留

        在IDT的任意一个门描述符都可使用IST机制或原有栈切换机制。当IST=0时,使用原有栈切换机制。否则,使用IST机制,此时处理器无条件进行栈切换。

        使用IST机制下,

        处理器强制将SS赋值为NULL段选择子,并将中断栈地址加载到RSP寄存器中。

        最后,将原SS,RSP,RFLAGS,CS和RIP寄存器值压入新栈中。

2.7.IA32e下分页机制

        IA-32e模式需伴随页管理机制的开启(置位CR0.PG,CR4.PAE,IA32_EFER.LME)。

        IA-32e模式的页管理机制可将Canonical型的线性地址映射到52位物理地址空间(由处理器最高物理可寻址位宽值MAXPHYADDR决定)。

        处理器通过CR3保存的物理地址,可将线性地址转换成一个多层级页表结构,IA-32e模式的页管理机制共支持4KB,2MB,1GB(CPUID.80000001h:EDX[26].1G-Page位可检测是否支持1GB物理页)三种规格的物理页容量。

        IA-32e模式的页管理机制使用多层级页表来结构化线性地址空间,CR3负责定位顶层页表PML4的物理基地址。

        PCIDs功能支持检测:

        CPUID.01h:ECX[17].PCID

        支持下,置位CR4.PCIDE标志位时开启PCID功能。

        开启PCID功能前提下,使用MOV指令操作CR3的第63位,将会影响TLB的有效性(全局页除外)。

       1.CR3寄存器解析

        处理器使能PCIDs功能时:

        编号[0,11]区域存储                           PCID

        编号[12, M-1]区域存储                     PML4页表的物理基地址

        编号[M, 63]区域存储                        保留       

        处理器使能PCIDs功能时:

        编号[0,2]区域存储                           保留

        编号[3]区域存储                              PWT标志位

        编号[4]区域存储                              PCD标志位

        编号[5, 11]区域存储                        保留

        编号[12, M-1]区域存储                    PML4页表的物理基地址

        编号[M, 63]区域存储                       保留

        

        2.对于PML4页表(容量4KB)的页表项的解析

        若页表项是无效的

        编号[0]区域                                         0

        编号[1, 63]区域                                   保留

       

        若页表项是有效的

        编号[0]区域                                        1

        编号[1]区域                                        R/W

        编号[2]区域                                        U/S

        编号[3]区域                                        PWT

        编号[4]区域                                        PCD

        编号[5]区域                                        A

        编号[6, 11]区域                                  保留

        编号[12, M-1]区域                              PDPT页表的物理基地址

        编号[M, 62]区域                                 保留

        编号[63]区域                                      XD标志位

        

        3.对于PDPT页表(容量4KB)的页表项的解析

        若页表项是无效的

        编号[0]区域                                        0

        编号[1, 63]区域                                  保存

        若物理页是1GB的

        编号[0]区域                                        1

        编号[1]区域                                        R/W

        编号[2]区域                                        U/S

        编号[3]区域                                        PWT

        编号[4]区域                                        PCD

        编号[5]区域                                        A

        编号[6]区域                                        D

        编号[7]区域                                        1(可作为1GB物理页的依据)

        编号[8]区域                                        G

        编号[9, 11]区域                                  保留

        编号[12]区域                                      PAT

        编号[13, 29]区域                                保留

        编号[30, M-1]区域                             1GB物理页的基地址

        编号[M, 62]区域                                保留

        编号[63]区域                                     XD标志位

       

        若物理页不是1G的

        编号[0]区域                                        1

        编号[1]区域                                        R/W

        编号[2]区域                                        U/S

        编号[3]区域                                        PWT

        编号[4]区域                                        PCD

        编号[5]区域                                        A

        编号[6]区域                                        保留

        编号[7]区域                                        0(可作为非1GB物理页的依据)

        编号[8, 11]区域                                  保留

        编号[12, M-1]区域                              页目录表的物理基地址

        编号[M, 62]区域                                保留

        编号[63]区域                                     XD标志位

      

        4.对PDT表(容量4KB)的页表项的解析

        若页表项是无效的

        编号[0]区域                                        0

        编号[1, 63]区域                                  保存

        若物理页是2MB的

        编号[0]区域                                        1

        编号[1]区域                                        R/W

        编号[2]区域                                        U/S

        编号[3]区域                                        PWT

        编号[4]区域                                        PCD

        编号[5]区域                                        A

        编号[6]区域                                        D

        编号[7]区域                                        1(可作为2MB物理页的依据)

        编号[8]区域                                        G

        编号[9, 11]区域                                  保留

        编号[12]区域                                      PAT

        编号[13, 20]区域                                保留

        编号[31, M-1]区域                             2MB物理页的基地址

        编号[M, 62]区域                                保留

        编号[63]区域                                     XD标志位

       

        若物理页不是2MB的

        编号[0]区域                                        1

        编号[1]区域                                        R/W

        编号[2]区域                                        U/S

        编号[3]区域                                        PWT

        编号[4]区域                                        PCD

        编号[5]区域                                        A

        编号[6]区域                                        保留

        编号[7]区域                                        0(可作为非2MB物理页的依据,那只能是4KB物理页了)

        编号[8, 11]区域                                  保留

        编号[12, M-1]区域                              页目录表的物理基地址

        编号[M, 62]区域                                保留

        编号[63]区域                                     XD标志位

        5.对PT表(容量4KB)的页表项的解析

        若页表项是无效的

        编号[0]区域                                        0

        编号[1, 63]区域                                  保存

        此时物理页只能是4KB的

        编号[0]区域                                        1

        编号[1]区域                                        R/W

        编号[2]区域                                        U/S

        编号[3]区域                                        PWT

        编号[4]区域                                        PCD

        编号[5]区域                                        A

        编号[6]区域                                        D

        编号[7]区域                                        PAT

        编号[8]区域                                        G

        编号[9, 11]区域                                  保留

        编号[12, M-1]区域                              4KB物理页的物理基地址

        编号[M, 62]区域                                保留

        编号[63]区域                                     XD标志位

        6.对1~5中涉及的相关标志位的解释

        P                        物理页存在标志位

        W                       物理页写权限标志位(读权限始终有)

        U/S                     访问模式标志位。0时,特权级3程序不可访问。1时,无限制。

        PWT                   0,回写。1,写穿。

        PCD                   0,页可以缓存。1,页不能缓存。

        A                         访问标志位。0,未访问。1,已访问。

        D                        脏页标志位。0,干净。1,脏页。

        PAT                    页面属性标志位。

        G                        全局页标志位。0,局部页。1,全局页。

        PS                      物理页容量标志位。

        

        CR0.CD为1时,PWT和PCD被忽略。

        7.如何翻译64位线性地址

       对4KB物理页:

        64位线性地址构成=16位符号扩展位+9位PML4表索引+9位PDPT表索引+9位PDT表索引+9位PT表索引+12位段内偏移。

        对2MB物理页:

        64位线性地址构成=16位符号扩展位+9位PML4表索引+9位PDPT表索引+9位PDT表索引+21位段内偏移。

        对1GB物理页:

        64位线性地址构成=16位符号扩展位+9位PML4表索引+9位PDPT表索引+30位段内偏移。

        

2.8.如何从保护模式切换到IA-32e模式     

2.8.1.检测处理器是否支持IA-32e模式

call	support_long_mode
test	eax,	eax
jz	no_support

;=======	test support long mode or not
support_long_mode:
mov	eax,	0x80000000
cpuid
cmp	eax,	0x80000001
setnb	al	
jb	support_long_mode_done
	
mov	eax,	0x80000001
cpuid
bt	edx,	29
setc	al

support_long_mode_done:
	movzx	eax,	al
	ret

;=======	no support
no_support:
	jmp	$

        对上述代码的解释:

        1.通过0x80000000执行cpuid,来查询cpuid支持的最大功能号

        2.向cpuid查询是否支持长模式(IA-32e)依赖0x80000001。所以,

        2.1.cpuid执行结果(存储在eax)大于等于0x80000001,则设置al为1。

        2.1.cpuid执行结果小于0x80000001,用al设置eax并返回。eax将被设置为0。

        3.接下来,必然cpuid大于等于0x80000001

        3.1.通过0x80000001执行cpuid。结果存储在edx。edx第29比特位为1,则支持长模式。为0,则不支持。

        3.2.测试edx第29比特位来设置al,并用al设置eax,返回。

        4.测试eax即可知道是否支持长模式。eax为0时,不支持。不为0时,支持。

 2.8.2.从保护模式切换到IA-32e模式

         处理器只能在开启分页机制的保护模式下才能切换到IA-32e模式。

        1.IA-32e模式激活后,GDTR,LDTR,IDTR,TR依然沿用保护模式的描述符表。IA-32e中,上述描述符表寄存器应重新加载为IA-32e模式的64位描述符表。

        2.IA-32e模式激活后,在将IDTR更新为IA-32e模式下描述符表前,需用CLI禁止可屏蔽硬件中断。对NMI不可屏蔽中断,需借助外部硬件电路来禁止。

        

        激活IA-32e:

        IA32_EFER.LME。

        

        激活步骤:

        1.保护模式下,用MOV CR0复位CR0.PG标志位来关闭分页机制。

        2.置位CR4.PAE,开启物理地址扩展。

        3.将页目录(顶层页表PML4)的物理基地址加载到CR3

        4.置位IA32_EFER.LME开启IA-32e模式

        5.置位CR0.PG开启分页机制。此时处理器会自动置位IA32_EFER.LMA。

        注意,开启分页机制,关闭分页机制前后对附近代码的线性地址的解释是不一样的。但应控制前后线性地址在开启,关闭前后,解释到相同的物理地址。

           

        

猜你喜欢

转载自blog.csdn.net/x13262608581/article/details/128996633