`
thecloud
  • 浏览: 881591 次
文章分类
社区版块
存档分类
最新评论

Linux0.11内核--启动引导过程

 
阅读更多

<!-- @page { margin: 0.79in } P { margin-bottom: 0.08in } -->

 启动搬迁过程:
  1BIOS将磁盘引导块程序bootsect读入到内存0x7c00,开始执行指令;
  2bootsect将自己搬迁到内存0x90000,跳到该段中的自己的下一条指令执行;
  3bootsect将设备检测安装程序setup读入到0x90200
  4bootsect将内核映像system读入到0x10000,跳到setup头部0x90200执行指令;
  5setup获取系统参数,依次保存在0x90000
  6setupsystem0x10000搬迁到0x0000
  7setup设置硬件寄存器和CPU状态字寄存器,进入32位保护模式,跳到system头部0x0000执行指令。
  8、开始执行内核映像中的指令。
  9、内核映像首部的指令(head.s)设置各个寄存器,加载中断描述符表、全局描述符表,检测芯片,
   对16M内存进行分页。
  10、执行main程序。
  
  
  阅读三个汇编程序和注释,很快就能了解到启动引导程序在进入main函数前作了这些事情。
  为什么要这样搬迁和执行呢?
  
  简单地讲,内核启动搬迁过程是:bios装载运行bootsectbootsect装载setupsystem,运行setup
  搬迁systembios的行为是已经固定写好烧在主板上bios芯片里的了。不是linus所控制的,也不是
  操作系统的范畴了。bios应该是和硬件架构紧密相关的。所以为什么biosbootsect读到0x7c00这么
  个怪地址,也没有其它的好讲了————对架构我不懂。 :(
  在加载bootsect之前,bios0地址开始加载了中断向量表————这个是我们的汇编代码中可以使用bios
  断功能的基础。是在实模式中我们的原始武器和工具。按照一个中断向量占四个字节,7c00前面如果都是
  中断向量表的话,这里应该有7c00/4 = 7936个中断向量了。应该没有这么多吧? 可能是有空余空间供
  扩展? 不得而知。
  
  bootsect自己搬迁自己的行为,我没有找到充分的理由。
  setup被装载到0x90200system被装载到0x10000,这些都没有覆盖到0x7c00512的空间,也就不会造成
  自己装载的咚咚覆盖了自己的指令代码的危险。而这个bootsect512字节大小,至今也没有变化,也不
  应该是为后续扩展所保留的。从Linussetup直接load0x90200可以看出,这个512字节也应该是不会
  变大的————由于bootsect是由bios装载的,变大了说明bios的代码和行为都变化了,这个是不现实的。
  所以我能解释的理由就是:linus觉得bios加载的地方不爽,所以特意把它挪到0x90000setup放在一起。
  如果你知道这个bootsect搬迁的理由,请不吝告诉我~
  
  
  关于setup
  setupbootsect装载到了0x90200bootsect执行完之后就执行了setup代码。setup被装载到0x90200
  而不是其它的地方,应该是由于system占用了0x100000x90000,而bootsect占用了0x900000x90200
  由于0x7c00512地址以前的地方被bios占用了。因此setup可能的装载的地方有:0x7c00512后面,
  或者0x90200后面。而在setup代码的执行过程中有一个动作,将system0x10000搬迁到0地址。这样,
  由于预留的512K大小的system必然把00x80000的内存都覆盖了。也就是说如果把setup装载在0x7e00
  之后,则会发生自己的搬迁行为修改了自己的指令地址————这是不可以的。
  而且将setup装载在0x7e00,则setup的大小受到限制,不能超过0x7e000x10000这块地址。
  setup获取的设备信息覆盖了0x90000bootsect的代码。然后将system0地址平移。这个动作覆盖了
  系统中断和0x7c00bootsect
  这个时候为什么可以覆盖中断向量表呢? 我想是基于这么几个原因:
  setup通过bios提供的这些工具能获取的系统参数都已经获取并保存了,工具已经没用了。在后面进入
  保护模式后,也已经不能通过中断向量的方式来使用bios中断了。前一个原因可以通过查看后面的汇编
  代码得到证实:后面的代码都没有再调用bios中断。第二个原因可以通过后续代码的动作和注释得到
  证实:setup32位保护模式加载了全局描述符表,中断描述符表。 后续发生中断时,将通过中断描述
  符表中的项映射到中断处理代码上去。这里面原来中断向量的每一项应该是四个字节(我没有记错的话),
  而中断描述符表中的项有八个字节————32位保护模式下,包含的中断信息更多了。
  
  关于system
  system就是Linux的内核了。内核首部的head.s的指令其实应该还是算作引导程序。放在内核中,而不是
  像setup一样单独编出来,估计是为了后续版本更方便的修改吧————毕竟内存分页、GDTIDT之类的东西
  修改的可能性是很大的。
  为什么将system0x10000搬迁到0地址,书上也说了,好处是对于其中的代码,线形地址和物理地址是一样
  的,这样子写程序更方便一些————linus这样说。实际上,我感觉不搬迁也没有什么不行。代码和数据的操作
  也应该没有什么不方便,毕竟就是汇编里面也是使用的标号。或许还是我没有理解到?
  system加载了全局描述符表,中断描述符表。中断描述符表已经说过了,用来映射中断服务程序和中断号的。
  全局描述符表,则是用来描述全局符号的。呵呵,这个解释。全局描述符表是一个记录各个任务的相应段信息
  的全局表。表中两个字作为一个任务的描述项:局部描述符表LDT,任务状态段TSS。局部描述符表指向某个
  具体任务的各个段信息(代码段,数据&堆栈段)的结构。任务状态段TSS应该是用来记录任务状态进行任务调度
  用的吧? 从这里看来,多进程的实现应该就是保存各个任务的上下文,进行切换和上下文处理吧。而上下文,
  也就是寄存器状态、指令位置、数据状态了。
  head.s还对16M内存进行了分页。每4096字节的内存分为一页,用四个字节描述一页(应该是四个字节的32位地址
  指向这一页的首部吧)。然后1024个页地址组成一个页表,一个页表占据一页(1024×44096)。一个页表也就
  管理了1024×40964M内存。Linus16M内存即占用了四个页表来描述。然后四个页表的地址又写到0地址开始的
  地方,占用了16字节,形成了页目录了。 页目录从0地址开始,页表从0x1000开始。也即第0页都是页目录了。
  按照Linus的这个处理,4096/4 × 4M 4G,也就是这个页目录的大小可以管理4G内存了。不过如果真的初始化
  了4G的内存页,会出问题。 4G内存需要1024个页表,一个页目录,供占用1025个页面,这样页表就写过了
  0x90000,要写到1025×1024 0x101000,比0x90200超过很远了————后果就是现在写到0x902000x400×2
  0x90a00后面的全局描述符表和中断描述符表了。中断描述符表无所谓,反正是哑中断。但是描述符表被破坏了,
  后面的就没得玩了。
  好了,全局描述符表(多任务的容器)建好了,内存分页也做好了。 就等main来打展身手了。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics