1.3.5 head.s开始执行(3)

来源:互联网 发布:pathfinder软件价格 编辑:程序博客网 时间:2024/04/27 10:38

1.3.5 head.s开始执行(3)

代码如下:

  1. //代码路径:boot/head.s  
  2. setup_gdt  
  3. ............  
  4. setup_gdt:  
  5. lgdt gdt_descr  
  6. ret  
  7.  
  8. _gdt:   .quad 0x0000000000000000    /* NULL descriptor */  
  9.     .quad 0x00c09a0000000fff        /* 16Mb */  
  10.     .quad 0x00c0920000000fff        /* 16Mb */  
  11.     .quad 0x0000000000000000        /* TEMPORARY-don't use */  
  12.     .fill 252,8,0               /* space for
    LDT's and TSS's etc */ 

点评

为什么要废除原来的GDT而重新设置一套GDT呢?

原来GDT所在的位置是设计代码时在setup.s里面设置的,将来这个setup模块所在的内存位置会在设计缓冲区时被覆盖。如果不改变位置,GDT的内容将来肯定会被缓冲区覆盖掉,从而影响系统的运行。这样一来,将来整个内存中唯一安全的地方就是现在head.s所在的位置了。

那么有没有可能在执行setup程序时直接把GDT的内容拷贝到head.s所在的位置呢?肯定不能,如果先复制GDT的内容,后移动system模块,它就会被后者覆盖掉;如果先移动system模块,后复制GDT的内容,它又会把head.s对应的程序覆盖掉,而这时head.s还没有执行呢。所以,无论如何,都要重新建立GDT。

全局描述符表GDT的位置和内容发生了变化,特别要注意最后的三位是fff,说明段限长不是原来的8MB,而是现在的16MB。如果后面的代码第一次使用这几个段选择符就是访问8MB以后的地址空间,将会产生段限长超限报警,为了防止这类可能发生的情况,这里再次对一些段选择符进行重新设置,包括DS、ES、FS、GS和SS,方法与图1-26类似,主要是段限长增加了一倍,变为了16MB。上述过程如图1-30所示。

调整DS和ES等寄存器的对应代码如下:

  1. //代码路径:boot/head.s  
  2.     movl $0x10,%eax     # reload all the segment registers  
  3.     mov %ax,%ds         # after changing gdt. CS was already  
  4.     mov %ax,%es         # reloaded in 'setup_gdt'  
  5.     mov %ax,%fs  
  6.     mov %ax,%gs 

通过测试我们发现,这是一种舍近求远的方法,其实只要在setup中构建第一个GDT表时把控制段限长的7ff直接设置为fff就可以一步到位了,不需要在这里重新设置段选择符。

现在user_stack数据结构的起始位置就是内核栈的栈底,栈顶指针esp指向user_stack数据结构的外边缘,也就是内核栈的栈顶。这样,当后面的程序需要压栈时,就可以最大限度地使用栈空间。栈顶的增长方向是从高地址向低地址的,如图1-31所示。设置esp的代码如下:

 图1-30 再一次调整DS、ES、FS、GS
  1. //代码路径:boot/head.s  
  2. lss _stack_start,%esp 

 图1-31 设置内核栈因为A20地址线是否打开是保护模式与实模式的根本区别,所以,现在要检验A20地址线是否确实打开了。图1-32在左下部给出了直观的标示。
 图1-32 检验A20是否打开检验A20是否打开的代码如下:

  1. //代码路径:boot/head.s  
  2. xorl %eax, %eax  
  3. 1:  incl %eax  
  4. movl %eax, 0x000000  
  5. cmpl %eax, 0x100000  
  6. je 1b 

点评

A20如果没有打开,则计算机处于实模式下,超过0xFFFFF寻址必然“回滚”。一个特例是0x100000就会回滚到0x000000,也就是说,地址0x100000处存储的值必然和地址0x000000处存储的值完全相同(参见图1-30的描述)。通过在内存0x000000位置写入一个数据,然后比较此处和1MB(即0x100000,注意,已超过实模式寻址范围)处数据是否一致,就可以检验A20地址线是否已打开。

0 0
原创粉丝点击