进入保护模式后,程序一样的需要用到段寄存器,当然这里装入段寄存器的不再是段地址,而是段的选择子。
因为要访问整个0~4GB数据段,所以要把DS中装入0~4GB数据段的段描述符,从图13-005中,我们可以知道这个段描述符索引号为“1”,TI位为“0”(位于GDT中),RPL为“00”。这里插入复习一下段选择子的构成,如下图图13-009:
因此1#描述符的段选择子为0000_0000_0000_1_0_00B,即0x0008。将该段选择子传送给寄存器DS。如图13-010第59行、第60行。
同理,要使用栈段,也必须将栈段的选择子给寄存器SS,由寄存器来加载相应的段描述符到描述符高速缓存器。栈段的描述符在GDT中的索引号为“3”,TI位为“0”,RPL为“00”,因此该描述父母的选择子为0000_0000_00011_0_00B,即0x0018,将该选择子给寄存器SS,并初始化栈指针ESP为0。如图13-010第62行~第64行。
执行完程序第64行后,内存状态示意图如图13-011。
准备工作完成后,主引导程序就开始加载内核程序。加载内核程序用了一个过程“read_hard_disk_0”,但这个过程是32位保护模式下运行的过程,虽然名字与本书第8章的那个过程一样,但是内容还是有区别的。下图图13-012是第8章加载硬盘内容的过程。
下图图13-013是本章读取硬盘程序:
为方便理解,将本章加载硬盘内容过程称为32read,将第8章加载硬盘内容的过程称为16read,因为它们之间的之所以有区别,是因为16位模式和32位保护模式的不同而导致的。这两个过程的区别分析如下:
1、参数设置
32read:(1)起始逻辑扇区号,用EAX。
(2)目标缓冲区地址,用DS:EBX。
16read:(1)起始逻辑扇区号,用DS:SI;
(2)目标缓冲区地址,DS:BX。
分析:32位EAX寄存器可以直接保存28位的逻辑扇区号,因此不再需要内存来保存。EBX寄存器在32位模式下,可以访问全部0~4GB内存空间,因此不会再出现16位实模式中需要防止载入内容超过64KB,需要每次加载后重新设定新的目标位置段地址的情况。
2、返回值
32read:返回EBX,该值=EBX_传入值+512;
16read:无返回值。
因为在32位保护模式下,EBX可以直接访问0~4GB内存空间,因此当本次加载完成后,EBX的值已经比开始前传入的数值多了512,刚好就是下次加载的目标地址处。因此就不需要像16位保护模式下的情况那样,再进行相关转换设置。
回到程序:主引导程序并不知道内核有多长,但是它可以通过读取内核第一个扇区内的信息,获得内核的长度,因而进行正确加载。