分类:
2010-06-28 13:49:31
【操作系统第一步】
一、FAT12文件格式:
第一章谈到了引导程序的编写。它是在0面0磁道0扇区的一个文件。它的大小是512BYTE,那么我们现在就来具体了解一下它的结构。
文件格式通常分为:
1、扇区:磁盘上的最小数据单元。
2、簇:一个或多个扇区。
3、分区:通常指整个文件系统,也就是一个分区。
现在就来看看一个分区整体结构(扇区磁盘的最小单元):
___________________________________________________________________________
|长度(未知)_____________【数据区】_____________需要根据根目录表的元素计算.______|
|长度(未知)_____________【根目录区】_____________需要根据BPB_RootEntCnt计算. __|
|长度(18)、Sector_____________【FAT2】_______________________________________|
|长度(9)、Sector_____________【FAT1】________________________________________||0、Sector____________【引导扇区】___________________________________________|
可以看到一个分区系统就是由5个部分:
1、引导扇区:
也就是装入7C00内存地址的那段512字节的程序。不过这512和先前的那个只要代码的512程序可就大有不同了。因为这是WINDOWS规定的FAT16引导扇区:
其中引导扇区存放着两个重要的数据结构体;
不过在该扇区开始是:BS_JmpBoot(3个字节)、它是程序开始执行出会跳转到代码区。BS_OEMName(8个字节).它是原始设备制造公司名字符串数据。
①、BPB(BIOS Parameter Block)属于基本输入输出块:
紧接着从11字节开始到------35字节结尾就全是BPB的信息了。记录着文件系统的重要信息。
②、BS(Boot Sector)属于引导扇区:
从36字节到-------61字节结尾就全是BS的信息了,记录着程序需要的信息。包括卷标序列号等...前面的BS_JmpBoot跳转与BS_OEMName也是属于BS引导信息。
2、FAT1:
FAT1的起始扇区是1位于引导扇区后的块. 它是以12位为一个FAT表项。代表一个簇也就是扇区。第0个和第1个FAT表始终不用。这对应于数据块的起始簇也是2.。 那么第二个FAT项就对应数据块的第一个簇(偏移为2),由于是12位表示一个数据块对应的簇。而字节有是最小单位。所以在处理FAT表项的时候。。
以字节来拆分。加入有 [8-0](1) ,[8-0](2),[8-0](3) 这3个字节。那么第一个FAT项因该是:
[4-0](2)__[8-0](1) .按高高低低的拆分(高地址的低位成为低地址的高位搭配凑足12位)。
第二个FAT是:[8-0](3)_[7-4](2)。
通常FAT的值代表下一个簇号,但是如果值大于或等于0XFF8则表示当前簇已经是本文件的最后一个簇。如果值是0XFF7表示它是一个坏簇。
FAT表可以看作是一个用来表示 文件在数据块所占用的扇区数量的标志,如果文件数据超过512Byte 那么FAT的值就不是是FF8H 应该是指向该文件下一段数据所在的FAT表位置,。也就是数据块中的簇位置。FAT与数据块的簇一一对应。如果FAT不等于FF8H表示文件还有连续的数据块。
3、FAT2:
FAT2跟FAT1的 内容一个摸样。是FAT1的备份。
4、根目录区:
根目录的每一个条目格式长度是32个字节.记录着一个文件信息。
那么紧跟着FAT2后的第一个19扇区(19*512=0x2600byte)处,就是第一个条目(文件)的信息。它的长度是32个字节。记录着包括文件的名字、属性、写入时间、写入日期、条目对应的开始簇号(指文件数据偏移块,簇偏移从2开始。)、以及文件大小这些信息。
根目录的偏移位置在FAT16当中不用计算了 因为就两个FAT表。如果需要计算那么可以:
BPB_FATSz16* BBPB_NumFATs +1 =BootSectorBase (根目录区的起始扇区数).
5、数据区:
数据区位于根目录区后面。所以首先得获得根目录区占用的空间后。这样才能得到数据区的起始扇区数。
BPB_RootEntCnt * 32 /BPB_BytesPerSec =NumBootSector(根目录所占用的扇区数)。
但是如果 BPB_RootEntCnt * 32/BPB_BytesPerSec 有余数的话那么得到根目录区占用的扇区数总长将是被截掉了。这样是不对的。所以要再填充一个扇区。磁盘的最小单元是扇区要明白。
那么公式需要改变一下:
( BPB_RootEntCnt * 32+BPB_BytesPerSec-1) /BPB_BytesPerSec =NumBootSector;
这样就填补了根目录所占用的扇区数NumBootSector了;
现在DataSetorBase(数据起始扇区)=BootSectorBase + NumSectorBase;
得到数据起始扇区后。就可以按根目录的条目信息指定的簇号进行正确的访问了。簇偏移是从2开始的。
所以DataSetorBase 的簇偏移是2。
×了解了如上内容后就可以编写一个FAT16文件系统的引导程序,并且还可以进行磁盘文件的管理与读取。
二、读写磁盘
读写磁盘要用到中断。那么这里就用BIOS的int 13中断来处理。
al = 2h 表示读扇区。不过这里需要3个分量参数
1、磁头号(也就是面)
2、柱面( 也就是磁道相对与当前磁头的扇区偏移量)
3、起始扇区号( 相对于当前磁道的扇区偏移量)
1.44MB的软驱 有两面也就是磁头0磁头1,有80个柱面(磁道)。每个柱面有18个扇区。
所以2×80×18×512=1.44MB空间。
那么逆运算可以求出当前扇区偏移所在的具体位置。
用扇区号 / 18( 商是当前在总盘的磁道偏移位置,):
① 、商除以2得到相对于当前磁头的柱面号偏移扇区量。
②、商是奇数的话那么就代表是1磁头。
③、余数+1 是起始扇区号
×那么就可以编写程序来实现对FAT16文件系统的磁盘读写操作。
把读扇区写成一个扇区 传两个参数 一个cl =要读取扇区的个数、二个ax代表从那个数据扇区号开始读。
;---------读扇区-----------
ReadSector: ;参数就是ax 代码要读取的数据的起始扇区号 cl是要读取扇区的数量
push bp
mov bp,sp ;保存原来的堆栈
sub sp,2 ;开辟2个字节 存放要读取的扇区数 访问时 可以用byte[bp-2]放问数据
mov BYTE [bp-2],cl ;(cl是传来的是读去的扇区个数)
push bx ;保存bx
mov bl,[BPB_SecPerTrk];每个磁道(柱面)的扇区数量
div bl ;ax总长的扇区号
inc ah ;余数+1扇区号是从1开始的
mov cl,ah ;(起始扇区号)
mov dh,al ;dh保存着相对于0磁头的的柱面偏移位置,如果超过0磁头那么累加
shr al,1
mov ch,al ; (柱面号)
and dh,1 ;柱面为号偶数的扇区属于磁头号0.柱面号为奇数是属于磁头号1的数据。
pop bx
mov dl,[BS_DrvNum] ;当前驱动器号 0表示A:
.GoOn_Reading:
mov ah,2
mov al,BYTE [bp-2] ;这个是要读取扇区的个数
int 13h
jc .GoOn_Reading ;没有读完就会cf=1 那么就让它一直读完
add esp,2 ;因为开辟了2个字节现在销毁
pop bp
retn
有了读扇区的函数后,我们就可以在方便的根据根目录文件条目对应数据进行读取了。
可以用几个循环来遍历检查:
第一层循环来遍历根目录的所有扇区.
for(int i=0;i < 根目录扇区总;i++)
{
第二层循环来遍历根目录的扇区里面的文件项目.
mov ax,根目录扇区号
mov cl,1
call ReadSector
for(int j=0;j<16h;j++) ;一个扇区可用有16个文件项目因为一个项目32BYTE。
{
遍历文件项目的时候就可以判断文件名是否正确对应了.
这里进行一些字符串的判断。
如果找到 Loader.bin内核加载程序那么跳出去 }
}
这是整体思想 具体编码可自己用自己的方法。就可以找到正确的文件条目。那么在找到Loader,bin条目后,。我们必需还要做点事情就是将Loader.bin里的数据也从文件系统里拿出来。这样才真正达到加载磁盘文件。
×从根目录文件项里找到数据区对应的簇、
那么可以写一个GetFATEntry 函数来获取 FAT1里的项目值。因为文件项对应在数据区的簇。在FAT1表里是一一对应的。。并且如果文件大于1个扇区也可以用FAT1找到其他的数据。
那么我们的GetFATEntry函数的输入参数就设置为 ax(根目录中文件条目里指定的簇偏移。它对应FAT1里的表项值如果FAT1表项值不是0xFF8那么就代表它还有数据)
那么拥有这个函数后。。
×判断文件条目里数据的簇偏移。因为它对应FAT1的表项。
得到FATEntry后。就好办了。。再判断它的值是否是0xff8 如果是的化就证明该文件数据块就一个扇区。簇偏移也就是FATEntry的偏移。如果不0xFF8而是0x10h 那么就表示 需要去偏移为10H的FAT1项查找。如果此项目为0xFF8那么就表示 这个文件占两个扇区。。簇偏移位置就是第一个FATEntry偏移位置 和第二个FATEntry位置。。他们与数据区的簇一一对应!!!
【总结】
写一个FAT12文件系统的引导程序,并且到软驱读入一个文件装入到内存。
1、编写ReadSector 扇区的函数。因为需要找根目录寻找文件。
2、用二层循环。一、根目录区外循环 ,二、读取的根目录区一个扇区的信息到内存。进行根目录项的循环。然后就可以判断文件名字符串了,这样就找到了文件在根目录项的位置。
3、将文件装入到内存:
需要根据文件对应数据区的簇号来判断。FAT项目对应的项,。如果FAT项的值不等 0XFF8或者0XFF7那么表示该文件还有数据在另外一个扇区,那么此时的FAT项的值就是另外一个FAT项。此项偏移对应数据区的簇偏移。
得到具体扇区位置后,将程序装入内存直接跳转过去。。这样引导程序的工作就完成了。
先主控权就到了Loader.bin 手里了。