《ORANGE’S:一个操作系统的实现》读书笔记(四)突破512字节(一)

        进入保护模式不是一件很困难的事情,按照指定的步骤进行操作就可以了。但是我们要做的事情是很多的,如果我们总是局限在512字节的引导扇区上,那么很多事情就都做不了了。这显然不是我们想要的,我们需要一个方法帮助我们突破这512字节的引导扇区的限制,让我们可以做更多的事情。

        虽然引导扇区小,但是我们现在使用的软盘容量却大的多。所以,可以再建立一个文件,将其通过引导扇区加载入内存,然后将控制权交给它。这样,512字节的限制就没有了。

        那么,被引导扇区加载进内存的是不是就应该是操作系统内核了呢?一个操作系统从开机到开始运行,大致经历“引导 -> 加载内核入内存 -> 跳入保护模式 -> 开始执行内核”这样一个过程。也就是说,在内核开始执行之前不但要加载内核,而且还有准备保护模式等一些列工作,如果全都交给引导扇区来做,512字节有可能是不够用的,所以,我们把这个过程交给另外的模块来完成,我们把这个模块叫做 Loader。引导扇区负责把 Loader 加载入内存并且将控制权交给它,其它工作都交给 Loader 来做,因为它没有512字节的限制,可以做更多的事情。

        在这里,书上记录的方式是将软盘做成 FAT12 格式,这样对 Loader 以及今后的 Kernel(内核)的操作将会简单易行。

FAT12

        FAT12 是DOS时代就开始使用的文件系统(File System),直到现在仍然在软盘上使用(可能现在已经有很多人没有见过软盘了,而且软盘也不再被电脑使用,但是本书就是使用这样的方式。我个人理解的是,如果将这种方式理解了,那么换成其它的,应该也是一样的操作方式,比如FAT32)。几乎所有的文件系统都会把磁盘划分为若干层次以方便组织和管理,这些层次包括:

  • 扇区(Sector):磁盘上的最小数据单元。
  • 簇(Clust):一个或多个扇区。
  • 分区(Partition):通常指整个文件系统。

        引导扇区是整个软盘的第 0 个扇区,在这个扇区中有一个很重要的数据结构叫做 BPB(BIOS Parameter Block),引导扇区的格式如下表所示,其中名称以BPB_开头的域属于BPB,以BS_ 开头的域不属于BPB,只是引导扇区的一部分。

名称

偏移

长度

内容

Orange's 的值

BS_jmpBoot

0

3

一个短跳转指令

jmp LABEL_START

nop

BS_OEMName

3

8

厂商名

'ForrsetY'

BPB_BytePerSec

11

2

每扇区字节数

0x200

BPB_SecPerClus

13

1

每簇扇区数

0x1

BPB_RsvdSecCnt

14

2

Boot记录占用多少扇区

0x1

BPB_NumFATs

16

1

共有多少个FAT表

0x2

BPB_RootEntCnt

17

2

根目录文件数最大值

0xE0

BPB_TotSec16

19

2

扇区总数

0xB40

BPB_Media

21

1

介质描述符

0xF0

BPB_FATSz16

22

2

每个FAT扇区数

0x9

BPB_SecPerTrk

24

2

每磁道扇区数

0x12

BPB_NumHeads

26

2

磁头数(面数)

0x2

BPB_HiddSec

28

4

隐藏扇区数

0

BPB_TotSec32

32

4

如果BPB_TotSec16是0,由这个值记录扇区数

0

BS_DrvNum

36

1

中断13的驱动器号

0

BS_Reservedl

37

1

未使用

0

BS_BootSig

38

1

扩展引导标记(29h)

0x29

BS_VolID

39

4

卷序列号

0

BS_VolLab

43

11

卷标

'OrangeS0.02'

BS_FileSysType

54

8

文件系统类型

'FAT12'

引导代码及其它

62

448

引导代码、数据及其它填充字符等

引导代码(剩余空间被0填充)

结束标志

510

2

0xAA55

0xAA55

        紧接着引导扇区的是两个完全相同的FAT表,每个占用9个扇区。第二个FAT之后是根目录区的第一个扇区。根目录区的后面是数据区,如下图所示。 

        接下来要做的事情就是把 Loader 复制到软盘上并让引导扇区找到并加载它,那么就来看一下引导扇区通过怎样的步骤才能找到文件,以及如何把文件内容全部都读出来并放进内存里。为简单起见,我们规定 Loader 只能放在根目录中,而根目录信息放在FAT2后面的根目录区中。那么,先来看一下根目录区。

        根目录区位于第二个FAT表之后,开始的扇区编号为19,它由若干个目录条目(Directory Entry)组成,条目最多有 BPB_RootEntCnt 个。由于根目录区的大小是依赖于BPB_RootEntCnt的,所以长度不固定。根目录区的每一个条目占用 32 字节,它的格式如下表所示。

名称

偏移

长度

描述

DIR_Name

0

0xB

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

DIR_Attr

0xB

1

文件属性

保留位

0xC

10

保留位

DIR_WrtTime

0x16

2

最后一次写入时间

DIR_WrtDate

0x18

2

最后一次写入日期

DIR_FstClus

0x1A

2

此条目对应的开始簇号

DIR_FileSize

0x1C

4

文件大小

        条目格式结构并不复杂,但是我们要是能直观看到一个真实的目录条目就好了。这并不难做到,我们可以使用上一篇文章创建的虚拟软盘 fd.img,然后把它作为 FreeDos 的A盘,格式化后就可以方便地往其中添加文件和目录了。这样,当我们想查看它的格式时,只需要用二进制查看器打开 fd.img 就可以了。

        接下来,按照书上所示,通过FreeDos在这张虚拟软盘中添加以下2个文本文件进行查看:

  • RIVER.TXT,内容为 riverriverriver。
  • FLOWER.TXT,内容输入大量字符(重复单词:flower),使该文件大小超过512字节,用来测试文件跨越扇区的情况。

        完成后,我们使用二进制查看器打开 fd.img 文件进行查看。我这里选用的二进制文件查看器是:Bz1621.lzh,你可以选择自己习惯的二进制查看器软件进行使用。

        由于根目录区是从第19扇区开始,每个扇区512字节,所以根目录区第一个字节位于偏移 19×512=9728(十进制)=0x2600(十六进制)处。现在使用Bz二进制查看器软件打开 fd.img 文件,转到偏移 0x2600处查看一下内容,如下图所示:

        看到这里,可以清楚的看到创建的两个文件的单词 RIVER、FLOWER,那么以 RIVER.TXT 为例,按照条目格式结构进行分析理解(DOS是小端存储)。 

名称

偏移

长度

描述

DIR_Name

0

0xB

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

RIVER TXT

DIR_Attr

0xB

1

文件属性

0x20

DIR_WrtTime

0x16

2

最后一次写入时间

0x553A

DIR_WrtDate

0x18

2

最后一次写入日期

0x5787

DIR_FstClus

0x1A

2

此条目对应的开始簇号

0x0002

DIR_FileSize

0x1C

4

文件大小

0x00000011

        文件名和大小很容易理解,时间日期信息对我们没用。当我们寻找Loader时,只要发现文件名正确就认为它是我们要找的那个文件。最后剩下最重要的信息DIR_FstClus,即文件开始簇号,它告诉我们文件存放在磁盘的什么位置,从而让我们找到它。由于一个簇只包含一个扇区,所以为了简化计算过程,下文中将“簇”替换成“扇区”进行记录。

        需要注意的是,数据区的第一个簇的簇号是2,而不是0或者1。RIVER.TXT的开始簇号是2,也就是说,此文件的数据开始于数据区第一个簇。数据区的第一个簇即第一个扇区位置在哪里呢?这需要通过计算根目录区所占的扇区数才能知道。我们既然已经知道了根目录区条目最多有BPB_RootEntCnt个,扇区数也就可以计算出来了,假设根目录区共占用 RootDirSectors 个扇区,则有公式:

 

         将数字带入公式,结果取整,得到 RootDirSectors=14。所以:数据区开始扇区号=根目录区开始区号+14=19+14=33。第33扇区偏移量为512×33=16896,转换为16进制为:0x4200,让我们到这个位置看一下里面的内容。从下图中可以看出,和我们写入的文件内容是一样的。

        这时可能会有一个问题,那就是我们已经通过根目录区找到了文件并看到了内容,那我们还要FAT表做什么呢?实际上,对于小于512字节的文件来说,FAT表用处不大,但是如果文件大于512字节,我们就需要用FAT表来找到所有的簇(扇区),毕竟文件大于512字节还是很常见的。

        FAT表有两个,FAT2可看做是FAT1的备份,它们通常是一样的。那么FAT表的结构是什么样的呢?我们还是先来一点直观的认识,FAT1的扇区编号是1,偏移512字节,转换为16进制是0x200,我们到这个位置看一下里面的内容。如下图:

        根本看不懂里面的内容是什么。书上讲的是,这里的内容有点像一个位图,其中,每12位称为一个FAT项(FATEntry),代表一个簇。第0个和第1个FAT项始终不使用,从第2个FAT项开始表示数据区的每一个簇,依此类推。

        需要注意的是,由于每个FAT项占12位,包含一个字节和另一个字节的一半,所以显得有点别扭。具体是这样的,假设连续3个字节分别如下图所示,那么灰色框表示的是前一个FAT项(FATEntry1),BYTE1是FATEntry1的低8位,BYTE2的低4位是FATEntry1的高4位;白色框表示的是后一个FAT项(FATEntry2),BYTE2的高4位是FATEntry2的低4位,BYTE3是FATEntry2的高8位。

        通常,FAT项的值代表的是文件下一个簇号,但如果值大于或等于0xFF8,则表示当前簇已经是本文件的最后一个簇。如果值为0xFF7,表示它是一个坏簇。文件中的簇号和FAT项相对应,例如文件RIVER.TXT的开始簇号是2,对应FAT表中第2个FAT项,该项的值为0xFFF,该值大于0xFF7,表示这个簇已经是最后一个簇了。

        接下来我们来看一下FLOWER.TXT文件,这个文件比较大,超过512字节,看一下它对应的FAT项是什么样的。FLOWER.TXT文件的簇号为3,对应第3个FAT项,该项的值为0x004,也就是说,这个簇不是文件的最后一个簇,下一个簇号为4。我们再看第4个FAT项,该项值为0x005;不是最后一个簇,接着看第5个FAT项,该项值为0x006;往下看第6个FAT项,该项值为0xFFF,大于0xFF8,为最后一个簇。所以,FLOWER.TXT占用了第3、4、5、6,共计4个簇。第3个簇对应的是第34个扇区,第34扇区偏移量为512×34=17408,转换为16进制为:0x4400。让我们到这里看一下里面的内容(如下图),可以看到好多单词“flower”,和写入文件的内容是一样的。

        这里需要注意一点,一个FAT项可能会跨越两个扇区,这种情况在编码实现的过程中要考虑在内。

        好了,到这里为止,如何在一个软盘中找到自己想要的文件应该已经清楚了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值