您尚未登录。

楼主 # 2023-08-29 16:45:44

leilong
会员
注册时间: 2019-12-06
已发帖子: 36
积分: 36

FATFS文件系统详解:关于如SD卡、SD nand、spi nor flash等众多存储设备

文章目录#申请原创#
FATFS文件系统详解
1. 简介
2. 基础概念
3. FAT文件系统组成介绍
4. FAT文件系统分析
4.1 采用FAT格式格式化SD nand/sd卡
4.2 引导扇区分析
4.3 分区偏移及大小计算
4.4 FAT子类型确认
4.4 访问FAT条目
4.5 文件与簇之间的关系
4.6 FSInfo扇区结构及备份引导扇区
4.7 FAT目录
4.7.1 SFN 短文件名目录
4.7.2 LFN长文件名
4.7.3 LFN系统对于SFN的兼容
5. 分区分析
5.1 保留分区分析
5.2 FAT区分析
5.3 根目录区分析
5.4 数据区分析
5.5 新增文件测试
6. 总结
1. 简介
在早期计算机刚发展的时候,那时候硬盘大小、flash设备容量都比较小,随着技术的不断迭代更新,硬盘容量越来越大。在早期,面对小容量的硬盘/flash,往往采用对应地址存放对应数据的方案,由于数据量不大,操作起来尚还可以。但是发展到今天,随着硬盘/flash容量不断增大,存储的数据也越来越多,早期单一的对应地址存放对应数据的方案已经无法满足我们的需求,操作硬盘/flash会变得异常的困难复杂。
因此针对上述问题,一群大佬们便开始设计文件系统这样一个东西,用来管理硬盘/flash上的数据信息,像我们电脑上打开文件夹,访问里面的文件,这其实就是基于文件系统访问电脑硬盘上数据的一个操作。
发展至今,文件系统已有众多版本,本文主要分享 关于FAT文件系统的详细设计, FAT文件系统适用于嵌入式设备,如SD卡、SD nand、spi nor flash等众多存储设备,同时基于此文件系统的文件亦能被电脑正常读取。
2. 基础概念
在研究文件系统之前,我们需要首先弄清楚关于内存这块的几个基本概念:
2.1.区分 扇区、块、簇的概念
扇区(sector):flash可操作的最小单元,通常指我们擦除的最小单元大小,以sd nand举例,通常最小为512Byte
块(block) 以及 簇(cluster):其实这是两个相同的概念,只是由于历史原因,在不同系统上的不同称呼,在windows中称簇,而在linux中称块。一个簇/块由多个扇区组成,由于一个扇区的空间较小,因此文件系统通过会将多个扇区组合在一起形成一个簇,并以簇为单位进行读写操作! 一个簇通常可以由 2、4、8、… 、2的n次方个扇区组成。
2.2.FAT文件系统总共由FAT12、FAT16以及FAT32三个版本,这是由于随着存储技术不断发展,FAT文件系统迭代导致,数字越大,版本越新,新版本对老版本完全兼容!
3. FAT文件系统组成介绍
Fat文件系统官方文档:http://elm-chan.org/docs/fat_e.html
FAT文件系统在flash上的布局如下图所示,总共由四个区域组成:
保留区
FAT区
根目录区 (FAT32类型不包含此区域)
数据区
SD NAND,贴片式TF卡,贴片式SD卡,北京君正,nor flash,存储,芯片,主控,小容量emmc,大容量SLC Nand
接下来,我们对一张格式化为FAT格式的SD卡进行分析,理解FAT文件系统的实现细节:
4. FAT文件系统分析
4.1 采用FAT格式格式化SD nand/sd卡
1.使用win10格式化一张118.5M的SD nand / sd卡,我这里用的是手上的一颗 创世CS 家的sd nand加一块转接板,和SD卡完全没有区别,且SD nand在稳定性上比SD卡具有优势。
此处由于SD nand(SD卡)大小原因,默认采用FAT16进行了格式化!因此在下文中我们先以FAT16进行分析,之后再重新格式化为FAT32进行分析,就很容易懂了!
4.2 引导扇区分析
1.使用 winhex 工具打开对应磁盘,注意需使用管理员权限运行
2.打开后我们可以以二进制的格式查看SD卡上所有数据,首先看到第一个扇区,也就是对应的引导扇区 boot sector,注意引导扇区位于保留区!
3.接下来我们根据官方文档 对引导扇区进行分析
注意,FAT文件系统数据均采用小端格式!
a) 首先是FAT12/16/32公共部分,(偏移值 0 - 35):
EB 3C 90:BS_JmpBoot,跳转指令
4D 53 44 4F 53 35 2E 30:BS_OEMName,MSDOS 5.0,一个名字,指示创建此卷的操作系统,无其他作用
00 02:BPB_BytsPerSec,扇区大小 512 字节
04:BPB_SecPerClus,每次操作的最小扇区数,簇 Cluster,4 (与格式化时选择的大小匹配 2048 = 512 * 4)
06 00:BPB_RsvdSecCnt,保留区的扇区数,6 (通过此可计算,FAT区起始地址为 6 * 512 = 0xC00)
02:BPB_NumFATs,FATs的个数,2(一般此值为2,多一个用来做冗余备份,解决系统异常导致第一个损坏时,增大恢复的可能性,表示FAT区有两个FATs备份)
00 02:BPB_RootEntCnt,512,在FAT12/16系统中,此字段表示根目录中32字节目录条目数量,设置此值时需注意对齐,为了最大的兼容性,FAT16系统上此值应设置为512,FAT32系统上此值应设置为0
00 00:BPB_TotSec16,16位大小区域描述FAT卷扇区总数,0。当FAT12/16系统扇区数 ≥0x10000(65536)时,此字段应设置为0,真实值存放在 BPB_TotSec32 字段;对于FAT32系统,此值必须为0。(此处由于我们的总扇区数=118.510241024/512 = 242688 > 65536,所以此字段为0)
F8:BPB_Media 媒体类型
ED 00:BPB_FATSz16,237,一个FAT占用的扇区数,此字段仅在FAT12/16系统使用;FAT32系统,此字段必须为0,使用BPB_FATSz32字段替代。FAT区总大小等于 BPB_FATSz?? * BPB_NumFATs 扇区(2372512=242688=0x3B400,由此可推算根目录区起始地址:0x3B400+0xC00=0x3C000)。
3F 00:BPB_SecPerTrk,每个磁道的扇区数,此字段仅与具有几何形状且仅用于 IBM PC 的磁盘 BIOS 的介质相关,不用管。
FF 00:BPB_NumHeads,头数量,此字段仅与具有几何形状且仅用于 IBM PC 的磁盘 BIOS 的介质相关,不用管。
00 00 00 00:BPB_HiddSec,0,FAT 卷之前的隐藏物理扇区数(当磁盘被分区之后,当前分区并不一定是从扇区头开始的)
00 B4 03 00:BPB_TotSec32,242688,32位大小区域描述FAT卷扇区总数(整个卷空间大小)。 FAT12/16系统,扇区总数小于0x10000时,此字段必须为0,真实值存放在BPB_FATSz16;FAT32系统,此字段一直有效。(118.5M = 512 * 242688)
b) 接下来是FAT12/16特有字段(偏移值36)
80:BS_DrvNum,IBM PC 的磁盘 BIOS 使用的驱动器号,00h代表软盘,80h代表固定磁盘
00:BS_Reserved,保留字段,0
29:BS_BootSig,扩展引导签名,表示以下存在三个字段
83 3E 07 E4:BS_VolID,与 BS_VolLab 一起构成卷序列号,一般在格式化的时候结合时间生成
4E 4F 20 4E 41 4D 45 20 20 20 20:(解析为:"NO NAME “),BS_VolLab,11byte卷标,当卷标不存在时,此值应设置为"NO NAME”
46 41 54 31 36 20 20 20:(解析为:"FAT16 "),BS_FilSysType文件系统类型,支持字段有:"FAT12 ", "FAT16 " or "FAT ",注意很多人认为是通过此字段区分FAT12/16/32系统类型,实际是错误的,文件系统类型实际上是根据磁盘大小确定的,官方文档 “Determination of FAT sub-type” 章节或本博文后文有描述,不过为了最大的兼容性考虑,此字段应设置为对应文件系统的名字。
33 C9 ~ CB D8:BS_BootCode,引导启动程序,与平台有关,不使用时填充为0
55 AA:BS_BootSign,0xAA55,引导签名,指示这是一个有效的引导扇区
当扇区大小大于512字节时,剩余的字段应全部使用0x0填充。
c) 如果是FAT32,则采用FAT32特有字段解析(偏移值和FAT12/16特有字段一致为36)
虽然此处我们的是FAT16格式,不过此处也将FAT的字段进行描述,方便理解。
BPB_FATSz32:一个FAT占用的扇区数,此字段仅在FAT32系统有效。FAT区总大小等于 BPB_FATSz?? * BPB_NumFATs 扇区。
BPB_ExtFlags:扩展标识字段,bit7=0,表示所有FAT都是镜像的和活跃的;bit7=1,表示只有bit3-0表示的FAT是有效的。
BPB_FSVer:FAT32版本,高字节是主版本号,低字节是次版本号。
BPB_RootClus:根目录的第一个簇号,此值通常为2,因为前两个簇一般用于保留。
BPB_FSInfo:FSInfo结构扇区与FAT32卷顶部的偏移扇区值。此值通常为1,因为其通常位于引导扇区旁边。
BPB_BkBootSec:备份引导扇区与FAT32卷顶部的偏移扇区值。此值通常为6,考虑最大的兼容性,此值不建议为其他值。
BPB_Reserved:保留
BS_DrvNum:含义与FAT12/16字段一样
BS_Reserved:含义与FAT12/16字段一样
BS_BootSig:含义与FAT12/16字段一样
BS_VolID:含义与FAT12/16字段一样
BS_VolLab:含义与FAT12/16字段一样
BS_FilSysType:始终为"FAT32 ",对FAT类型的确定没有任何影响。
BS_BootCode32:引导启动程序,与平台有关,不使用时填充为0
BS_BootSign:0xAA55,引导签名,指示这是一个有效的引导扇区
当扇区大小大于512字节时,剩余的字段应全部使用0x0填充。
以上就是引导扇区内容的详细分析了,通过引导扇区的内容,我们即可知道FAT文件系统依赖的硬件存储空间大小、簇大小、扇区大小以及以及FAT系统版本等重要信息。
同时通过引导扇区的内容,我们便可计算出对应的FAT的四个区域的大小及起始偏移位置等重要信息,接下来计算FAT四个分区的起始位置及大小。
4.3 分区偏移及大小计算
FAT卷总共分为以下四个区域:
保留区
1.第一个扇区为引导扇区,存放BPB(BIOS Parameter Block)数据,存放的是FAT卷的配置参数。
2.上述参数中以 BPB_ 命名的字段都是 BPB 的一部分,而以 BS_ 标题命名的字段都不是 BPB 的一部分,而只是引导扇区的一部分
FAT区(分区表装载区)
根目录区
数据区
各分区偏移地址及大小如下:
此外,关于FAT区,通常存在一个以上的FAT,如此处所格式化的sd卡便存在两个FAT,对应的偏移地址和大小如下:
4.4 FAT子类型确认
关于FAT的类型是FAT12/16/32确认:FAT类型由数据区内簇的数量决定,除此之外无其他办法!
当一个卷,簇的数量 ≤4085 时,为FAT12
当一个卷,簇的数量 ≥4086 且 ≤65525 时,为FAT16
当一个卷,簇的数量 ≥65526 时,为FAT32
簇的数量计算公式:CountofClusters = DataSectors / BPB_SecPerClus;
如我们这里:CountofClusters = 242176 / 4 = 60544,所以为 FAT16!
当簇的大小从 512 ~ 32768字节的各种条件下,不同类型FAT对应卷的大小范围如下:
4.4 访问FAT条目
FAT区由一条条FAT条目构成,关于 FAT[N] 对应的条目具体位置计算如下:
FAT16:
FAT32:
格外需要注意的是,不同格式,对应的FAT条目的长度和格式不一样:
此外对于FAT32格式,高4位是保留位,只有低28位有效!
具体如下图所示:
4.5 文件与簇之间的关系
那么文件和簇之间的相互关系又是怎样的呢?我们又是如何准确的找到存放在flash上的文件的呢?接下来让我们看下文件与簇之间的关系映射。
在FAT卷上文件通过目录管理,目录是一个32字节数组组成的目录条目结构,此目录结构包含:文件名、文件大小、时间戳以及文件所在的第一个簇号。
簇号为0和1的簇被保留,由参数BPB_RootClus可知,有效簇从第2号簇开始。FAT[2](2号簇)对应数据区的第一个簇。
因此第N个簇的位置计算公式如下:
FirstSectorofCluster = DataStartSector + (N - 2) * BPB_SecPerClus
每个条目所在的位置,对应一个簇。当文件长度大于一个簇长度时,条目内的值为下一个条目的索引,直到文件所在的最后一个簇,由此构成簇链!文件所在的最有一个簇所对应的FAT条目内的值由一个特殊的值(EOC)组成,它永远不会匹配任何有效的簇号,如下:
FAT12: 0xFF8 - 0xFFF (typically 0xFFF)
FAT16: 0xFFF8 - 0xFFFF (typically 0xFFFF)
FAT32: 0x0FFFFFF8 - 0x0FFFFFFF (typically 0x0FFFFFFF)
存在一些特殊的值被用来做损坏簇的标记,如下:
FAT12: 0xFF7
FAT16:0xFFF7
FAT32:0xFFFFFFF7
不过此处需要注意,在FAT12/16系统上,上述特殊值绝不会和任何有效簇匹配,但是在FAT32上有可能,因此为了防止混淆,你在创建FAT32系统的时候应该避免这种情况发生!因此FAT32系统上簇的上限为268435445(大于256M个簇)
FAT条目初始化的时候,FAT[2] 及以后的数据应被初始化为0,指示未被使用处于空闲状态,如果值不为0,则意味着簇被损坏或被使用状态。在FAT12/16系统上,空闲簇的数量未被记录,而在FAT32系统上,FAT32支持FSInfo结构体,里面记录了空闲簇的数量。
关于FAT[0]和FAT[1]:
此两个保留的条目,没有与任何簇有联系;不过具有其他意义,如下:
FAT12: FAT[0] = 0xF??; FAT[1] = 0xFFF;
FAT16: FAT[0] = 0xFF??; FAT[1] = 0xFFFF;
FAT32: FAT[0] = 0xFFFFFF??; FAT[1] = 0xFFFFFFFF;
FAT[0]中的?? 与 BPB_Media 相同;
FAT[1] 记录了错误历史记录:卷脏标志(FAT16:bit15、FAT32:bit31),系统在启动的时候清除此位,正常关闭的时候恢复。
如果此位已经清除,表明上次未被正常关闭,可能存在逻辑卷错误;硬件错误标志(FAT16:bit14、FAT32:bit30)当出现无法恢复的读写错误时清除,表明需要进行全面检查。
关于FAT区域,有两个重点注意事项:
第一个是FAT的最后一个扇区可能没有被完全使用。在大多数情况下,FAT在扇区的中间结束。FAT驱动程序不应该对未使用的区域做出任何假设。在格式化卷时,应该用零填充它,并且在此之后不应更改它。
另一个是BPB_FATSz16/32可以指示比卷需要的值大的值。换句话说,未使用的扇区可以跟随每个FAT。这可能是数据区域对齐或其他原因导致的。同时,在格式化时这些扇区也会被用零填充。
下表展示了不同FAT类型中FAT值所对应的含义解释:

离线

页脚

工信部备案:粤ICP备20025096号 Powered by FluxBB

感谢为中文互联网持续输出优质内容的各位老铁们。 QQ: 516333132, 微信(wechat): whycan_cn (哇酷网/挖坑网/填坑网) service@whycan.cn