1.从主引导扇区到BootLoader

本笔记主要目的是记录整个过程和思路,并记下一些关键点和需要注意的不容易理解的点,很多细节就略过了,需要的读者可以自行google或者参考原书《Orange’S一个操作系统的实现》.整个实现过程代码参见github

为什么要有BootLoader?

前面我们知道了,BIOS会加载MBR然后执行它,MBR需要做的事情主要有加载内核、做好进入保护模式的准备工作(设置GDT等),然后跳入保护模式,最后再转移到内核部分开始执行。可以看到,这些工作是相对比较复杂的,全给引导扇区去做512字节可能不够,因此要在中间加一个东西,它没有512字节的限制,把那些工作交给它来做,MBR则负责加载它并将控制权交给它。所以,BootLoader应运而生了。

从软盘读取BootLoader

不同的存储器比如软盘、硬盘有着不同的工作方式,要从中读取数据,或者写入数据都要遵循各自的规则与格式。而存储器用来组织管理其中数据的规范和标准就叫做文件系统(File System)

甚至同一块磁盘,它的不同分区也可以用不同的文件系统来进行组织和管理。比如我们在同一块硬盘装Windows和Linux双系统,就会对硬盘进行分区,Windows的分区用的是NTFS文件系统,而Linux的分区通常用的是ext文件系统。

因此,在读取软盘中存的BootLoader之前,我们必须知道软盘的文件系统是怎么样的,也就是数据在软盘中是怎样组织和存储的,。软盘的年代比较久远了,用的还是DOS时代就使用的FAT12格式的文件系统,但是有个好处就是它不复杂,比较易于掌握。接下来就简单地了解一下这种文件系统,这样之后无论什么文件系统学习起来都会轻松很多,因为设计思想都差不多。当然,此时的目的就是知道怎么读bootloader即可

FAT12文件系统(微软提出)

几乎所有文件系统都会把磁盘划分为若干层次以方便组织和管理数据,层次包括:

  • 扇区(Sector):磁盘上的最小数据单元
  • 簇(Cluster):一个或者多个扇区
  • 分区(Partition):通常一个分区就是用一种文件系统,所以可以表示整个文件系统

下图是一个软盘的文件系统结构图(1.44M,FAT12)

扇区号系统结构
~2879数据区
19~根目录区
10~18FAT2
1~9FAT1
0引导扇区

其中根目录区长度不固定,需要计算,从而数据区跟着变动。

下面具体讲讲各个区的作用和内容:

  • 引导扇区:是0号扇区,有一个重要数据结构BPB(BIOS Parameter Block),里面主要存一些这个存储器目前文件系统的参数,比如每扇区字节数、每簇扇区数等,供BIOS读取;BS(Boot Sector)则是其余部分,主要是关于这个软盘的厂商、卷标、文件系统类型等软盘的参数
  • 根目录区:由BPB_RootEntCnt个目录条目(Directory Entry)组成,所以它的长度是由引导扇区里的内容定的。每个条目32字节:主要包含文件名、属性、大小、日期以及在磁盘中位置。(这也是我们在OS的文件资源管理器里看到的文件列表,每个文件都有属性等信息的来源)这里可以用DOS里的xxd命令显示一个扇区的内容,看看真实的目录条目。
    • 文件在磁盘中的位置是用簇号表示的,而这里一个只包含一个扇区,所以两者同义。
    • 簇号从2开始(why?maybe为了表示数据区前面还有扇区),通过根目录区的大小可以计算得到文件内容所在的位置(偏移,以字节为单位)
  • FAT区:FAT2可以看做是FAT1的备份,通常是一样的。FAT里每12位是一个FAT项(FAT Entry),代表一个簇,所以也从2号FAT项开始用,前俩为空。**通常FAT项的值代表文件下一个簇号(开始簇号在目录条目里),如果它大于等于0xFF8,则表示已经是最后一个簇了;如果它等于0xFF7,则表示它是一个坏簇。**这么设计说明一个文件在存储器中存不一定是连续的,而是用类似链表的结构串起来的。

注意:一个FAT项可能跨越两个扇区,编码的时候要考虑。还有就是子目录怎么组织,这个有空再研究…

做好DOS可以识别的引导扇区

这个也简单,按照前面说过的格式,设置好引导扇区的BPB和BS等头信息即可。这部分其实前面没用DOS的时候没有也没问题,因为这是给DOS也就是操作系统看的。

注意编译成.com的话就不是简单的BIOS读取了,而是DOS来读取了,所以执行.com文件的引导扇区文件也无需加格式。

一个简单的Boot Loader

只是用来检验引导扇区可以正确读取软盘里的文件,因此这个程序文件里功能就是简单的显示一个字符然后死循环。

BIOS中断读软盘中的Loader

  • 加载一个文件入内存,使用BIOS 13h号中断。值得注意的是,参数的安装硬盘磁头号、柱面(磁道)号和起始扇区号的格式。这里要转换一下。转换得到参数并读取扇区的部分用一个函数ReadSector来实现.

  • 准备好了读取的函数,还得从软盘里找到要读取的loader.bin文件(获取扇区号),才能提供函数的参数

  • 查找loader位置的过程主要是:遍历根目录区的所有扇区,将每个扇区依次载入内存,然后在每个扇区里依次遍历每个条目,寻找文件名为loader.bin的条目,直到找到为止。

  • 找到loader.bin所在的起始扇区后,由于文件在软盘中通常不是存在连续扇区里的,所以要通过FAT里的扇区“链表”来找到并依次读取其余扇区。这个过程也用一个函数来处理,输入是扇区号,输出就是其对应的FAT项的值(文件的下一个簇号也就是扇区号)

  • 获取FAT项的代码中,有两个点需要注意:

    • 一个FAT项为12字节,所以双数扇区对应的FAT表项是前一个字节的后4位加上后一个字节组成的,单数则是前一字节加上后一字节的前4位,所以要区别对待单双数的扇区号。
    • 另外,一个FAT项可能跨越两个扇区,所以代码中一次读两个扇区。

向BootLoader交出控制权

即jmp到BootLoader,开始执行BootLoader的代码。

可以设置一个专门显示提示字符串的函数,每完成一步,显示一个相应的提示字符串,比如完成控制权转交后,在BootLoader代码里显示一个"Ready"

这里没有再使用DOS执行,而是直接执行,至于前面为什么要把程序编译成.com文件并用DOS执行,这里又为什么不用了,之前没有细想这个问题,这里做一个总结和补充。详情点这里

BootLoader主要作用

BootLoader的主要作用有两点:

  • 加载内核进入内存
  • 跳入保护模式:因为进入内核执行时应当已经进入保护模式,否则内核特权级都没法体现。

作者说:

只要一个.com文件中不包含DOS系统调用,我们就可以把它当做Loader来用。

对于这句话的理解,首先,通过查阅资料,我知道了DOS是一个工作在实模式下的操作系统,所以,DOS的系统调用也是实模式的。DOS在执行Loader.com文件后,控制权就交给了loader自己,这时候其实就已经和DOS无关了,loader可以做它自己的事情,加载内核,跳入保护模式,可是一旦跳入保护模式,就不能再调用DOS系统调用,因为那样会将控制权交回给DOS(很可能根本就不允许),而DOS系统调用是实模式下的,此时处理器已经是保护模式下的了,必然出错。

对于引导程序加载Loader,只需要直接放入内存的指定位置即可,而Loader加载内核就没那么简单了,因为内核是在Linux系统下编译得到的ELF格式的可执行文件,比.com或者.bin这种纯二进制文件复杂一些。下一章就要先研究这种格式…

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值