对FAT12文件系统的理解

来源:互联网 发布:网络手游知乎 编辑:程序博客网 时间:2024/05/22 10:31

于渊老师实验用了两个文件系统,一个是前几章用的FAT12文件格式,还有一个是后面他自己设计的一个简单的orange‘s文件系统。

    对于文件系统的作用,我想可以分成两个方面去理解。一个是像我们这次实验用到的文件系统,非常简单直接,是直接属于内核的一部分用来和磁盘驱动打交道;另一个方面就是再抽象一层出来的虚拟文件系统,这个是用来给上层应用提供统一接口的,给具体文件系统的实现规划方圆。我们不需要考虑虚拟文件系统的事情,只是实现一个简单的可以凑合着在磁盘上增删改查的系统就可以了。

    那说到底,文件系统的作用就是解析给出的路径,将文件相对于其所管辖设备(可以简单理解为磁盘上的某个分区)的扇区偏移计算出来,将这个偏移传递给磁盘驱动,磁盘驱动将这个偏移转换成相对于整个磁盘的偏移,然后根据读写指令向磁盘控制器发送信号。磁盘读写完数据后发送中断信号,这个中断信号会让cpu去执行IRQ14硬盘中断处理程序。对于这个程序的具体实现是通过读写端口的方式,将数据读取到内存或写入到磁盘缓冲区,并将结果返回给上层的文件系统。

    作者用了两种加载方式,一个是软盘,一个是硬盘。软盘引导是FAT12格式,硬盘引导的就是作者自己仿照这MINIX精简的格式。
    之所以先写对文件系统的理解,是因为我们一上来就要理解从软盘或者硬盘开始的加载程序,就必然涉及到文件的组织结构,要不然怎么找内核文件呢?而且我觉得操作系统的核心除了调度进程这些纯粹内存操作,就数文件系统最核心了。


    先说说FAT12文件系统
    
之所以叫FAT12,我也是前段时间温习书籍的时候,看到图才有点恍然的,12位来表示簇号而文件系统对于硬盘的管理如作者所说,一般分三个层次:
    
1、分区:通常指整个文件系统(我自己读书粗心,这句话我是在计算了几次主分区的分区表大小才领悟到文件系统就管理一个分区,不管这是个主分区还是一个逻辑分区)

2、簇:一个或者多个扇区

3、扇区:磁盘上最小的数据单元(也就是硬件厂商提供给磁盘驱动的硬件接口,按照一定大小读写数据)

FAT12格式的引导扇区前62个字节都有固定的作用,前36个字节是一个叫做BPB(BIOS Params Block)结构的数据,随后26个字节是引导扇区的一部分。具体的格式读者可以百度,或者可以查阅《一个操作系统的实现》104页,不过记着这个结构体里面的数据都是我们手动填充的,每个成员都有固定的意义,要么真的很懂FAT12的布局,要么还是按照作者给的数据来比较好,比如说下面我们要用到的BPB_RootEntCnt成员,表示根目录文件数最大值,我们写入的值是224,那么根目录区就可以确定占用的大小了。在实际用的时候,前三个字节是填充跳转指令的,紧随其后的是固定的格式,中间不要安插任何数据。随后的448个字节是我们引导程序的空间,最后两个字节为引导扇区结束标志0xAA55。

整个软盘的分割图大概如下

0(起始扇区编号)11019(大小不固定) 引导扇区FAT1FAT2根目录区数据区     每个目录条目占用32个字节,格式如下
名称偏移长度描述

DIR_NAME

0B文件名8字节,扩展名3字节

DIR_ATTR

0xB1文件属性

保留位

0xCA保留位

DIR_WrtTime

0x162最后一次写入时间

DIR_WrtDate

0x182最后一次写入日期

DIR_FstClus

0x1A2次条目对应的开始簇号

DIR_FileSize

0x1C4文件大小













作者为了简便,只有根目录一级目录,不支持除根目录以外的目录形式存在(我也没功力去实现)。可以看到根目录区起始扇区号是19,大小我们可以根据BPB_RootEntCnt和BPB_BytsPerSec来计算。

根目录区大小设为RootEntCnt,我们在BPB数据结构中已经填充了根目录区条目个数BPB_RootEntCnt,每个条目32字节,所以RootEntCnt=((BPB_RootEntCnt*32)+(BPB_BytsPerSec-1))/BPB_BytsPerSec,在这里可以算出来占用14个扇区。那么也顺便可以得到数据区第一个扇区的编号是19+14=33。另外,数据区第一个扇区的簇号是2,不是1和0,也就是说文件在数据区的扇区编号M和FAT表中的簇号N的关系是M=33+N-2。

对于不超过512个字节的文件来说FAT表并没有什么作用,但是对于字节数超过512的文件来说,根目录区存放的文件信息的条目中的DIR_FstClus存放的是文件在数据区的第一个扇区的编号M0对应的簇号N0(也就是M0-33+2),而在FAT表中,簇号N位置存放的是下一个扇区的编号M1对应的簇号N1,如果文件大小超过两个扇区,那么N1位置存放的是下一个扇区的编号M2对应的簇号N2...也就是说簇号的作用有两个,一个是用来寻找下一个簇,一个是用这个值加上一定的偏移作为该簇代表的扇区编号。

FAT表中每个簇号占用12个位,也就是1.5个字节,所以我们要把簇号扩大1.5倍,但是还要考虑到时奇数的时候。如果是偶数,比如说2,乘以1.5就是3,我们直接读取第三个字节然后算术右移4位就好了。如果是奇数,3,那么扩大1.5倍就是4.5,但是我们不可能读取半个字节,所以用ax*3/2的方式读到能包含想要数据的整数个字节,该例是从第4个字节开始读取了,然后右移4位就可以了,我们不要的那0.5个字节就移位移出去了。唉,我数学不好,把这个想明白可算是费了老大的劲。

比如簇号3,所在地址是0x204(这里也验证了我们扩大1.5倍的说法,3*3/2=4),我们看到的是8f 00,但是读到寄存器中的顺序是从高位到低位存放的。也就是00 8f,这样的形式支持我们右移4位能够得到我们想要的结果。

到这里,我想手工去找一个文件应该是可以了。下面说说引导扇区的大致流程。

加载文件到内存,肯定是要读盘的,此时什么代码都没有,那就只能依靠BIOS在开机后所做的工作,也就是BIOS初始化的中断表里有我们需要的读盘函数,int 0x13。

我就抄过来吧。

中断号寄存器作用13hah=00h dl=驱动器号(0表示A盘)

复位软驱

ah=02h    al=要读的扇区数

ch=柱面(磁道)号    cl=起始扇区号

dh=磁头号  dl=驱动器号(0表示A盘)

es:bx->数据缓冲区

从磁盘将数据读入es:bx指向的数据缓冲区

对于1.44MB的软盘来讲,总共有两面,也就是两个磁头(0号和1号磁头),每面80个磁道(0到79),每个磁道18个扇区(1-18号),我们需要将我们平常所说的扇区号(从0号扇区开始编码)转换为这三个分量。

在赵炯老师写的内核源码完全分析的书中对转换有很好的总结。

扇区号与柱面号,当前磁道扇区号和当前磁头号的对应关系:

假定硬盘的每磁道扇区数是track_secs,硬盘磁头总数是dev_heads,指定的硬盘顺序扇区号sector(从0开始),对应当前磁道数为tracks,对应柱面号cyl,当前磁道上的扇区号sec,磁头号head

sector/track_secs=商是tracks,余数是sec

tracks/dev_heads=商是cyl,余数是head

当前磁道扇区从1开始计数,所以sec+1;

反过来计算

sector=(cyl*dev_heads+head)*track_secs+sec-1;

对于我们而言,track_secs=18,dev_heads=2

对于我们想读的扇区,根据扇区号做上述转换,并将结果填到对应的寄存器,int 0x13就可以了。如果该中断失败,CF位会被置位,所以我们根据这个来判断数据是否已经加载进来了。


下面我们来整理出如何在软盘上寻找loader的思路。

作者为了简便起见,没有分多级目录,所有文件的目录数据都是放在“/”目录区。文件的大小都是固定的,0x800个扇区

步骤:

(我组织的不好,最好结合着代码看)

1、读取根目录所在扇区,将数据存放在LOADER_SEG:LOADER_OFF指定的地址处。

2、等数据读取完毕后,让si指向 "LOADER  BIN"字符串的起始地址,让di指向LOADER_OFF,dx赋值为0x10,也就是每个扇区存放的目录条目数,cx赋值为11,也就是字符串的长度。

3、开始比较,cx==0,表示找到文件。

4、如果找到文件,让di回退到当前条目起始地址(di&0xFFE0),然后加上0x1A,指向当前条目的DIR_FstClus域,该值表示文件对应的开始簇号a,加上根目录区大小b(14),加上相对簇号的根目录起始扇区号c(c=17,本来是19的,但是由于簇号的起始号是2,所以我们在此处提前减掉2,方便以后的计算),我们得到文件的扇区号d=a+b+c,我们将文件读到LOADER_SEG:LOADER_OFF指定的位置,此时LOADER_SEG:LOADER_OFF保存的内容已经没用了,可以随意覆盖。如果文件大小超过512个字节,我们还需要继续读取,直到读取到的簇号等于0FFFh。至于读取硬盘数据,读取簇号的方式上面都讲过了。

5、不相等让di回退到当前条目起始地址(di&0xFFE0),然后指向下一个条目(di+0x20),si指回"LOADER  BIN"起始地址,dx-1(表示当前扇区剩下的条目),cx=11,然后重新比较。

6、如果dx==0,还没有找到文件,则读取下一个扇区,跳到第2步。

等到都读取完了,我们就jmp  LOADER_SEG:LOADER_OFF,开始执行我们自己的loader了。

0 0
原创粉丝点击