计算机 在开机启动的时候,是经历了以下的步骤:
1.运行内置在BIOS芯片中的加电自检程序
2.按照CMOS中对硬件的配置初始化硬件
3.按CMOS中存储的启动项顺序搜索启动盘
4.若该启动盘的第一个扇区最后是以0xaa55结尾,则为引导扇区,CPU将其512个字节加载到
内存地址0000:7c00处,然后跳转到0x7c00处开始执行引导扇区的代码
问题就在于此,我们的操作系统不可能只有512个字节,所以如何突破这512个字节的限制呢?我们可以再建立一个文件,通过引导扇区将其加载入内存,然后将控制权交给他,这样就不受512个字节的限制了。并可以由他来加载我们的操作系统。
( 为什么不从引导扇区的512个字节直接加载操作系统内核呢,如今的操作系统都是保护模式下运行的,在内核执行之前,必须要经历引导,加载内核,跳入保护模式等步骤,512个字节很有可能不够用,所以。。。)
这个文件可以称之为loader,存储在启动盘上,选择软盘作启动盘,为了以后操作方便,建立fat12格式的文件系统。几乎所有的文件系统都会把磁盘化分为若干层次以方便组织和管理,这些层次包括:扇区,簇,分区。(扇区是磁盘上的最小数据单元)
fat12文件系统划分的软盘格式如下:
根目录区的大小未定。
引导扇区中有一个数据结构叫做BPB,初始化代码如下:
处理器从该数据结构中可以了解软盘格式信息。
而根目录区则由若干目录条目组成,每个条目占32个字节,条目定义了文件的名称,属性,大小,日期以及在磁盘中的位置,其中文件名相对条目首地址偏移为0,长度为0xB,条目对应的开始簇号偏移为0x1A,长度为2,由于在BPB中定义一个簇包含一个扇区,则条目对应的开始簇号就是开始扇区号,不过该扇区号是相对数据区的偏移扇区号。数据区就是存储文件的具体数据了。
根目录区条目在磁盘中的存储格式如下:
[root@localhost bochs-2.4.5]# xxd -u -a -g 1 -c 16 -s 0x2600 -l 512 x.img
0002600: 52 49 56 45 52 20 20 20 54 58 54 20 00 00 00 00 RIVER TXT ....
0002610: 00 00 00 00 00 00 A0 59 3D 3E 02 00 0F 00 00 00 .......Y=>......
(蓝色标出的是文件名,红色标出的是文件在数据区中的簇号)
若该文件只存放在一个扇区,好像只要通过根目录区的条目就可以确定文件位置了,不过若文件太大,存储超过一个扇区,而且存储的几个扇区不一定连续时,我们怎么确定文件的位置呢?
不是还有2个FAT表么,如上图的fat1和fat2通常是一样的,fat2可以看作是fat1的备份。
fat1的结构类似于一个位图,每12位为一个项,代表一个簇。第0个和第一个项始终不使用,从第二个项开始表示数据区的每一个簇。所以根目录区的条目中文件位置是从02开始排列的,也就是说数据区的第一个簇的簇号是2。
一般FAT项代表的是文件的下一个簇号,如果值大于或等于0xFF8就表示当前簇已经是本文件的最后一个簇。如果值为0xFF7,就表示它是一个坏簇。
fat在磁盘中的格式如下:
0000200: F0 FF FF FF FF FF FF FF FF FF FF FF 00 00 00 00 ................
0000210: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
我们要实现将软盘上的loader加载到内存某地址处。步骤如下:
一.搜索软盘上的文件
由于磁盘的最小数据单元是扇区,所以一切操作都是以扇区为单位进行
1.复位软驱
2.在根目录寻找loader.bin(其中复位软驱及读取扇区使用中断13)
遍历根目录区的所有扇区,将每一个扇区加载入内存,然后从中寻找文件名为 loader.bin的条目,直到找到为止。
二.加载到内存
1.由扇区号求得FAT项的值
2.根据簇号加载loader.bin到指定内存
三.将控制权交给loader.bin
具体程序如下:
以上程序来自《Orange`s 一个操作系统的实现》