【学习】【保护模式编程、七】

【操作系统第一步】

一、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 手里了。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值