1.2.2 加载第二部分代码—setup(1)

来源:互联网 发布:和合期货软件下载 编辑:程序博客网 时间:2024/05/03 08:27

1.2.2 加载第二部分代码—setup(1)

1. bootsect对内存的规划

现在,BIOS已经把bootsect(也就是引导程序)载入内存了,它的作用就是把第二批和第三批程序陆续加载到内存中。为了把第二批和第三批程序加载到内存中的适当位置,bootsect首先做的工作就是规划内存。

通常,我们是用高级语言编写应用程序,这些程序是在操作系统的平台上运行的。我们只管写高级语言的代码和数据,至于这些代码和数据在运行的时候放在内存的什么地方,是否会相互覆盖,我们都不用操心,因为操作系统和高级语言的编译器替我们做了大量的看护工作,以确保不会出错。现在我们讨论的是操作系统本身,启动代码使用的是汇编语言,没有高级语言编译器替其提供保障,只有靠操作系统的设计者把内存的安排想清楚,确保无论操作系统如何运行,都不会出现代码与代码、数据与数据、代码与数据之间相互覆盖的情况。为了更准确地理解操作系统的运行机制,我们必须清楚操作系统的设计者是如何规划内存的。

在实模式状态下,寻址的最大范围是1MB,为了规划内存,bootsect首先设计了如下的代码:

  1. //代码路径:boot/bootsect.s  
  2.  
  3. SETUPLEN = 4                ! nr of setup-sectors  
  4. BOOTSEG  = 0x07c0               ! original address of boot-sector  
  5. INITSEG  = 0x9000               ! we move boot here-out of the way  
  6. SETUPSEG = 0x9020               ! setup starts here  
  7. SYSSEG   = 0x1000               ! system loaded at 0x10000 (65536)  
  8. ENDSEG   = SYSSEG + SYSSIZE     ! where to stop loading 

这些源代码的作用就是对后续操作所涉及的内存位置进行设置,包括将要加载的setup程序的扇区数(SETUPLEN)和被加载到的位置(SETUPSEG)、启动扇区被BIOS加载的位置(BOOTSEG)和将要移动到的新位置(INITSEG)、内核(kernel)被加载的位置(SYSSEG)、内核的末尾位置(SYSEND)和根文件系统设备号(ROOT_DEV),这些位置在图1-5中都明确地标注了出来。设置这些位置就是为了确保将要载入内存的代码和已经载入内存的代码及数据各在其位,互不覆盖,并且它们各自有够用的内存空间。大家在后续的章节会逐渐看到内存规划的意义和作用。

从现在起,我们的头脑中要时刻牢记这样一个概念:操作系统的设计者要全面、整体地考虑内存的规划。我们会在后续的章节中不断地了解到,精心安排内存是操作系统设计者时时刻刻都要关心的事。我们带着这样的观念继续讲解bootsect程序的执行。

 图1-5 实模式下的内存使用规划

2.复制bootsect

接下来,bootsect启动程序将它自身(全部的512B内容)从内存0x07C00(BOOTSEG)处复制至内存0x90000(INITSEG)处,这个动作和目标位置如图1-6所示。

 图1-6 bootsect复制自身

执行这个操作的代码如下:

  1. //代码路径:boot/bootsect.s  
  2.  
  3. mov ax, #BOOTSEG  
  4. mov ds, ax  
  5. mov ax, #INITSEG  
  6. mov es, ax  
  7. mov cx, #256  
  8. sub si, si  
  9. sub di, di  
  10. rep  
  11. movw 

在这次复制过程中,ds(0x07C0)和si(0x0000)联合使用,构成了源地址0x07C00;es(0x9000)和di(0x0000)联合使用,构成了目的地址0x90000(参看图1-6左边),而mov cx, #256这一行循环控制量,提供了需要复制的“字”数(一个字为两个字节),256个字正好是512字节,即第一扇区的字节数。

通过代码我们还可以看出,图1-5提到的BOOTSEG和INITSEG现在开始发挥作用了。注意,此时CPU的段寄存器(CS)指向0x07C0 (BOOTSEG),即原来bootsect程序所在的位置。

点评

由于“两头约定”和“定位识别”的作用,所以bootsect在开始时“被迫”加载到0x07C00位置。现在将其自身移至0x90000处,说明操作系统开始根据自己的需要安排内存了。

bootsect复制到新位置后,bootsect会执行下面这行加粗的代码:

  1. //代码路径:boot/bootsect.s  
  2.  
  3.     rep  
  4.     movw  
  5.     jmpi go, INITSEG  
  6. go: mov ax,cs  
  7.     mov ds,ax 

从图1-6中我们已经了解到当时CS的值为0x07C0,执行完这个跳转后,CS值变为0x9000 (INITSEG),IP的值为从0x9000(INITSEG)到go: mov ax, cs 这一行对应指令的偏移。换句话说,此时CS:IP指向go: mov ax, cs这一行,程序从这一行开始往下执行。图1-7形象地表示了跳转到go: mov ax, cs这一行执行时CS和IP的状态,如图右下方所示。

 图1-7 跳转到go处继续执行
0 0