在操作系统启动的过程中,第一步启动的是Booter,由于我们需要找到Loader.bin这个引导文件,我们需要在软盘上实现一个FAT12文件系统,从而方便我们的文件管理。
话不多说,先上最终结果图:
已经实现了文件搜索功能,只是因为我还没往软盘中写入loader.bin,因此提示找不到文件。
之前我已经了解过FAT文件系统的基本原理,在这里不多赘述。本质上,FAT将一个文件的数据簇以链表的形式进行了管理。
FAT文件系统的存储布局
引导记录 | FAT1 | FAT2 | 根文件夹 | 数据区(其他文件夹和文件) |
FAT的存储布局如上面的表展示的这样。两份FAT(文件分配表)的内容完全一致。FAT表之后就是根文件夹,接着就是数据区。数据区保存其他文件夹和文件数据。在FAT文件系统中,以簇(连续的几个扇区)为单位来作为逻辑存储单元。数据区的簇号和FAT表项是一一对应的关系。因此,哪怕文件只有1个byte,FAT也会为他分配一个簇。
FAT表项
FAT表项中存储的是文件中下一个簇的簇号,规定0xFFF就是文件的最后一个簇。
对于FAT表项的位宽,则与FAT的类型有关,FAT12就是指FAT表项位宽为12bit。
根目录区和数据区
根目录区保存的是目录项的信息,数据区可以保存目录项和文件内数据的信息。这里讲到的目录项是一个32bytes的结构体,里面记录了名字、长度、数据起始簇号等一系列的信息。
目录项的结构如下:
需要特别注意的是DIR_FstClus这个字段,由于FAT[0]和FAT[1]是保留项,因此,起始簇号是2.
读取软盘扇区
通过阅读BIOS的中断表可知,要读取软盘扇区,可以借助BIOS中断服务程序INT0x13的主功能号AH=0x02来实现。只需要按照要求,将要读取的扇区数、磁道号、扇区号、磁头号、驱动器号、数据缓冲区地址offset传入相应的寄存器,再发起中断,就能实现读取软盘扇区。
这里需要注意的是,我们文件系统里的扇区号是LBA格式的,也就是逻辑块地址,而BIOS上的中断服务程序只接受CHS格式的磁盘扇区号。CHS就是(Cylinder/Head/Sector)。因此我们需要进行转换。
转换公式如下:
LBA扇区号÷每磁道扇区数
得到商Q、余数R
柱面号=Q>>1, 磁头号=Q&1,起始扇区号=R+1
接着我们就把数据写入寄存器,发起中断就可以了。
实现文件搜索功能
当我们实现了读取软盘扇区的功能之后,就能在这个基础之上实现文件搜索功能。
方法起始就是从根目录中的第一个目录项开始,一个个的遍历目录项,不断使用LODSB指令,逐位比较目录项中的文件名与目标文件名是否一致。
这里的主要难点其实就是汇编实现,思想不是很难,只不过真的,在用汇编来实现这些的过程中,是真的痛苦。可能是因为我太菜了。
把文件装载到内存中
当搜索到loader.bin这个引导程序后,我们就在根据目录项中的起始簇号,不断地加载FAT表项,然后去数据区对应的位置读取数据,加载到内存中。
这个过程会涉及到FAT表项的解析工作,这是一个难点。由于FAT12每个FAT表项占用12bit,也就是每3个字节存储2个FAT表项,因此FAT表项的存储是具有奇偶性的。大概就是体现在有些FAT表项是在一个byte的第0位开始存储,有些则是在byte的第6位开始存储。因此我们解析FAT表项的时候,需要对奇数项和偶数项区别对待。并且,还可能存在FAT表项横跨两个扇区的问题,因此我们需要一次读取两个扇区进来,这样便于解决FAT项横跨两个扇区的问题。
至于如何解析FAT表项,我们需要把FAT表项号乘3然后除以2,也就是扩大1.5倍。这样能够获取余数的奇偶性,把它保存在[Odd]变量中。并且将计算结果除以每扇区的字节数,得到FAT的偏移扇区号和扇区内偏移量。最后,根据奇偶标志变量[Odd],进一步处理奇偶错位的问题。具体的方法就是:把奇数项向右移动4位
经过上面一波操作之后,就能获取到FAT表项的值了。
然后加载文件就很简单,不断根据FAT表项的值,读取数据区对应的扇区,直到FAT的值为0xFFF,就说明文件加载完毕了。
看看代码
然后,具体的代码长这个样子:
https://github.com/fslongjin/DragonOS/commit/79b591f3e6730b68cb267d7d20d05
转载请注明来源:https://longjin666.cn/?p=1310
欢迎关注我的公众号“灯珑”,让我们一起了解更多的事物~