实战 FAT12 文件系统
1. 引言
经过一系列的文章,我们终于完成了从实地址模式跳转到保护模式,并且实现了分段、分页以及保护模式下的中断与异常机制。
保护模式究竟“保护”了什么
可是我们除了最初的时候,在磁盘第一个扇区写入一段代码来实现最初“hello world”,此后,我们就一直用 DOS 来拉起我们的“操作系统”,那么,你是不是有种不够尽兴的感觉?明明说好要写自己的操作系统,却要用别人的操作系统来引导,我们能不能自己写一个引导区呢?
答案当然是可以的,编写一个引导区看起来是如此的容易,只需要创建一个新的文件,里面指定被载入内存的初始地址,然后在引导扇区的代码中先将这个新的文件内容载入内存,再用一条跳转指令,跳转过去即可。
而这个“新的文件”就被称为操作系统的 loader,他负责在操作系统启动前进行一系列的准备工作,然后从实地址模式跳转到保护模式,再加载内核。
2. 磁盘的基本概念
既然要让引导扇区找到磁盘上的文件,那我们首先要来看看磁盘空间是如何构成的。
通常,磁盘拥有远大于内存的容量,要想合理利用这些容量,就需要将他们进行划分,让数据能够在各自的区域内,从而方便迅速定位数据。
2.1. 磁道、柱面和磁头数
如图所示,我们可以将硬盘看做是多个光盘的组合,而每个“光盘”都被称为一个“盘片”,由于盘片位于硬盘盒内,不在暴露在空气中,因此,盘片得以更加高速的旋转,且数据密度也达到光盘所无法企及的程度,但其原理其实与光盘仍然非常类似。
而正如上面的图上所示,硬盘中并不只有一个盘片,也不只有一个磁头,所有的同心旋转的盘片经由磁头扫过的磁道共同构成了一个圆柱面,这就是“柱面”。
如上图所示,借由盘片的旋转,让磁头能够读取到的一圈圈轨道,就是“磁道”,数据就位于磁道上。
2.2. 扇区、簇与页
每连续的 512 字节数据组成了一个扇区,若干个扇区又组成了一个簇,簇是磁盘空间分配的最小单位,也就是说,你即使创建一个 1 字节的文件,实际上这个文件至少也要占用磁盘 1 簇的空间。
而每次内存与磁盘的交互中,操作的最小单位就是一页,1 页由若干簇构成,通常是 4096B。
3. 经典文件系统 — FAT12
FAT12 是一种“古老的”文件系统,到现在,软盘所使用的文件系统也通常是 FAT12,但其他地方已经基本上没有使用之处了。
不过现在的 FAT32 与 FAT12 从结构上来说是非常类似的,所以我们本文以 FAT12 来做讲解,未来会有专门的文章来介绍各个文件系统之间的区别,敬请期待。
本文,我们以一个 1.44M 的软盘为例进行介绍:
如上图所示,一个 1.44M 的软盘,可以划分为 2879 个扇区,共分为图上所示的五个区域。
3.1. 引导扇区
第一个扇区就是引导扇区,他的具体取值是固定的:
FAT12 引导扇区格式
名称 | 偏移 | 长度 | 内容 | 软盘参考值 |
---|---|---|---|---|
BS_jmpBoot | 3 | jmp LABEL_START | nop | |
BS_OEMName | 3 | 8 | 厂商名 | ‘ForrestY’ |
BPB_BytsPerSec | 11 | 2 | 每扇区字节数 | 0x200(512) |
BPB_SecPerClus | 13 | 1 | 每簇扇区数 | 0x01 |
BPB_RsvdSecCnt | 14 | 2 | Boot记录占用多少扇区 | 0x01 |
BPB_NumFATs | 16 | 1 | 共有多少FAT表 | 0x02 |
BPB_RootEntCnt | 17 | 2 | 根目录文件数最大值 | 0xE0 (224) |
BPB_TotSec16 | 19 | 2 | 扇区总数 | 0xB40(2880) |
BPB_Media | 21 | 1 | 介质描述符 | 0xF0 |
BPB_FATSz16 | 22 | 2 | 每FAT扇区数 | 0x09 |
BPB_SecPerTrk | 24 | 2 | 每磁道扇区数 | 0x12 |
BPB_NumHeads | 26 | 2 | 磁头数 | 0x02 |
BPB_HiddSec | 28 | 4 | 隐藏扇区数 | |
BPB_TotSec32 | 32 | 4 | 如果BPB_TotSec16是0,由这个值记录扇区数 | 0xB40(2880) |
BS_DrvNum | 36 | 1 | 中断13的驱动器号 | |
BS_Reserved1 | 37 | 1 | 未使用 | |
BS_BootSig | 38 | 1 | 扩展引导标记 | 0x29 |
BS_VolD | 39 | 4 | 卷序列号 | |
BS_VolLab | 43 | 11 | 卷标 | ‘OrangeS0.02’ |
BS_FileSysType | 54 | 8 | 文件系统类型 | ‘FAT12’ |
引导代码 | 62 | 448 | 引导代码、数据及其他填充字符等 | |
结束标志 | 510 | 2 | | 0xAA55 |
3.2. 文件分配表 — FAT 表
FAT 表又叫“文件分配表”,从图上可以看到,FAT12 具有两个 9 扇区大小的 FAT 表。
FAT2 通常是 FAT1 的备份,两者可以认为是一样的。
在 FAT 表中,每 12 位被称为一个 FAT 项(FAT Entry),第 0 个和第 1 个 FAT 项始终不使用,从第 2 个 FAT 项开始,每个 FAT 项对应数据区的一个簇,数据区首个簇号为 2,FAT Entry N 正好对应数据区簇号为 N 的簇。
每个 FAT 项中存储的是当前文件的当前簇的下一个簇的簇号,如果值大于等于 0xFF8,那么就表示这已经是文件的最后一个簇,0xFF7 则表示这对应了一个坏簇。
3.3. 根目录区
根目录区存储了若干条目录条目,每个目录条目长 32 字节,最多存储 BPB_RootEntCnt 个条目。
因此可以得到公式:
根目录区扇区数 = (BPB_RootEntCnt * 32)/BPB_BytsPerSec。
BPB_RootEntCnt 和 BPB_BytsPerSec 就是上文中起始扇区中定义的相应字段。
目录条目的存储内容为:
FAT12 根目录区目录条目内容
名称 | 偏移 | 长度 | 描述 |
---|---|---|---|
DIR_Name | 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 | 文件大小 |
3.4. 数据区
毋庸多言,数据区存储的就是文件的实际内容。
如果这个文件实际是一个目录,那么这个簇实际存储的就是这个目录下文件构成的条目列表,具体信息与根目录区中的条目格式相同。
4. FAT12 文件读取过程
经过上述 FAT12 分区的介绍,我们就已经可以清楚的知道如何在一个 FAT12 类型的磁盘上寻找一个文件了:
-
获取文件系统基本信息 — 读取位于第 0 个扇区的起始扇区
-
计算数据区首个扇区 — 根据起始扇区中的 BPB_RootEntCnt 字段和 BPB_BytsPerSec 字段计算根目录区大小,从而计算出数据区对应的扇区号
-
获取根目录中的文件 — 从19号扇区开始读取根目录区条目,找到 DIR_NAME 保存的相同文件名的文件或目录,读取对应的簇号 DIR_FstClus
-
获取文件内容 — 通过 DIR_FstClus 存储的簇号找到对应的 FAT 项,同时读取数据区中对应的簇号的文件内容,并根据 FAT 项获取下一簇号递归进行读取,直到 FAT 项标识文件内容损坏或文件读取完成
5. 实践 — 如何创建软盘
既然我们已经非常清楚了软盘的文件系统结构,你是否想要实践一下看看呢?是否一个软盘的文件系统真的如我们上面所描述的就是这样存储的呢?
5.1. 创建软盘镜像
通过下面的命令可以实现一个虚拟软盘镜像文件的创建:
dd if=boot.bin of=boot.img bs=512 count=1 conv=notrunc
5.2. 建立文件系统
通过下面的命令,可以将刚刚创建的软盘格式化为对应的文件系统格式:
mkfs.vfat floppy.img /建格式化为vfat文件系统/
5.3. 向软盘镜像中添加文件
5.3.1. 创建挂载目标目录
mkdir /mnt/floppy
5.3.2. 挂载软盘镜像
mount -o loop boot.img /mnt/floppy
你也可以增加 -t vfat
参数指定文件系统格式。
5.3.3. 添加文件
对于已经挂载好的 loop 设备,你可以随意去操作:
cp hello.txt /mnt/floppy
cp world.txt /mnt/floppy
rm /mnt/floppy/hello.txt
5.3.4. 解除挂载
umount /mnt/floppy
5.4. 查看虚拟软盘镜像文件内容
虚拟软盘镜像内容是一个二进制文件,我们可以通过 vim 来读取:
vim -b boot.img
可是这样打开后,你仍然会发现看到了一团乱码,别急,通过下面的 vim 命令就可以切换到十六进制模式展示了:
:%!xxd -g 1
6. 微信公众号
欢迎关注微信公众号,以技术为主,涉及历史、人文等多领域的学习与感悟,每周三到七篇推文,只有全部原创,只有干货没有鸡汤。
7. 附录 1 — 系列历史文章
7.1. 准备工作
计算机是如何启动的?如何制作自己的操作系统
如何调试操作系统
7.2. 保护模式
操作系统的内存管理 — 分段与分页、虚拟地址、逻辑地址、线性地址、物理地址
保护模式究竟“保护”了什么
7.2.1. 分段
详解 32 位保护模式与内存分段机制
进军保护模式
保护模式进阶 — 再回实模式
实战局部描述符表 LDT
利用调用门实现特权级间跳转(上) — 原理篇
利用调用门实现特权级间跳转(下) — 实战篇
7.2.2. 分页
详解操作系统分页机制与实战
实战分页机制实现 — 通过实际内存大小动态调整页表个数
7.2.3. 中断与异常
保护模式下的中断和异常(上) — 硬件原理篇
保护模式下的中断和异常(下) — 软件实战篇
《实战 FAT12 文件系统》来自互联网,仅为收藏学习,如侵权请联系删除。本文URL:http://www.bookhoes.com/4020.html