关于底层单片机的U盘固件程序在此就不谈了,这里只涉及上层文件系统部分。如果后面有时间,我再发贴上来。
本例在LPC1768内存中开辟8K字节作为整个U盘文件系统缓冲区。通过USB接口向主机发送USB设备描述符,接口描述符,端点描述符,配置描述符。。。。。Bulk Only(批量传输)模式响应主机发送的CBW(Command Block Wrapper,即命令块包),将设备枚举为USB 海量存储设备(USB Mass Storage Class)。关于具体细节不属于本文的范畴,大家可以参考具体的USB协议,USB Mass Storage Class协议或是其他朋友写的文章。。。。。。
成功枚举后,在电脑上将会看到如图1所示的硬盘图标,在我的电脑上是P盘。
图 1
(在写这里的时候,本人着实郁闷了半天,U盘插到我笔记本上WIN7时,是完整的空盘,而插到台式机上时就显示已使用空间1KB。起初怀疑是单片机程序中硬盘镜像的FAT表有问题,弄了半天,最后用WinHex查看从台式机取下的U盘数据,发现里面被塞了两个文件,这下明白了,台式机有病毒,插上去就生成了两个文件。刚好占用两个扇区。所以在调试任何程序时,有些细节是蛮折腾人的。)
容量为6.00KB, 可用空间6.00KB。按道理我的硬盘应该有8KB才对,因为我在单片机内存中开辟了8KB。但为何会少了2KB呢?这个问题在看完后面之后你就会明白。
此时U盘里无任何文件数据,是一张空盘。
接下来用WinHex打开此盘,大家将会看到以下一些数据图片。
首先是前512字节,也就是“扇区0”
图 2
注意左边的一些信息,此U盘的大小为8K字节,(分为16个扇区 × 512字节)。也就是共有16个扇区。和我内存中开辟的缓冲区大小一致。但空闲的仅为6K字节,也就是说有2KB(即4个扇区)的容量被占用了。它们分别是:
图 3
DBR区 占用0 扇区。
FAT1表 占用 1 2 两个扇区
FAT2表 无
根目录 占用 3 扇区
数据区 占用 4------15 扇区
DBR区(DOS BOOT RECORD)即操作系统引导记录区的意思,通常占用分区的 第 0 扇区共 512 个字节(特殊情况也要占用其它保留扇区,我们先说第 0 扇)。在这 512 个字节中,其实又是由跳转指令,厂商标志和操作系统版本号,BPB(BIOS Parameter Block),扩展BPB,os引导程序,结束标志几部分组成。
图 4
表 1
跳转指令JUMP
图 2列出的偏移0x00-0x02的跳转指令“EB 3C 90“,清楚地指明了引导代码的偏移位置。“jump 3CH“加上跳转指令所需的位移量2,即开始于0x3E。此段指令在不同的操作系统上和不同的引导方式上,其内容也是不同的。
OEM厂商标志
跳转指令之后是8 字节长的OEM ID,它是一个字符串,OEM ID标识了格式化该分区的操作系统的名称和版本号。为了保留与MS-DOS的兼容性,通常Windows格式化该盘是在FAT16磁盘上的该字段中记录了“MSDOS5.0”,如图2所示。
BPB和扩展BPB
BPB(BIOS Parameter Block)参数块记录着本分区的起始扇区、结束扇区、文件存储格式、硬盘介质描述符、根目录大小、FAT个数、分配单元(也称之为簇)的大小等重要参数。如表2所示
表2 FAT16分区的BPB字段
表2 FAT16分区的BPB字段 | |||
字节位移 | 字段长度(字节) | 例 值 | 名称、定义和描述 |
0x0B | 2 | 00 02 | 扇区字节数(Bytes Per Sector) 硬件扇区的大小。本字段合法的十进制值有512、1024、2048和4096。对大多数磁盘来说,本字段的 值为512 |
0x0D | 1 | 01 | 每簇扇区数(Sectors Per Cluster) 一个簇中的扇区数。由于FAT16文件系统只能跟踪有限个簇(最多为65536个)。因此,通过增加每簇的扇区数可以支持最大分区数。分区的缺省的簇的大小取决于该分区的大小。本字段合法的十进制值有 1、2、4、8、16、32、64和128。导致簇大于32KB(每扇区字节数*每簇扇区数)的值会引起磁盘错误和软件错误 |
0x0E | 2 | 01 00 | 保留扇区数(Reserved Sector) 第一个FAT开始之前的扇区数,包括引导扇区。 |
0x10 | 1 | 01 | FAT数(Number of FAT)该分区上FAT的副本数。本字段的值一般为2 |
0x11 | 2 | 10 00 | 根目录项数(Root Entries) 能够保存在该分区的根目录文件夹中的32个字节长的文件和文件夹名称项的总数。在一个典型的硬盘上,本字段的值为512。其中一个项常常被用作卷标号(Volume Label),长名称的文件和文件夹每个文件使用多个项。文件和文件夹项的最大数一般为511,但是如果使用的长文件名,往往都达不到这个数。 |
0x13 | 2 | 10 00 | 小扇区数(Small Sector) 该分区上的扇区数,表示为16位(<65536)。对大于65536个扇区的分区来说,本字段的值为0,而使用大扇区数来取代它。 |
0x15 | 1 | F8 | 媒体描述符( Media Descriptor)提供有关媒体被使用的信息。值0xF8表示硬盘,0xF0表示高密度的3.5寸软盘。媒体描述符要用于MS-DOS FAT16磁盘,在Windows 2000中未被使用 |
0x16 | 2 | 02 00 | 每FAT扇区数(Sectors Per FAT) 该分区上每个FAT所占用的扇区数。计算机利用这个数和FAT数以及隐藏扇区数来决定根目录在哪里开始。计算机还可以根据根目录中的项数(512)决定该分区的用户数据区从哪里开始 |
0x18 | 2 | 01 00 | 每道扇区数(Sectors Per Trark) |
0x1A | 2 | 01 00 | 磁头数(Number of head) |
0x1C | 4 | 00 00 00 00 | 隐藏扇区数(Hidden Sector) 该分区上引导扇区之前的扇区数。在引导序列计算到根目录和数据区的绝对位移的过程中使用了该值 |
0x20 | 4 | 00 00 00 00 | 大扇区数(Large Sector) 如果小扇区数字段的值为0,本字段就包含该FAT16分区中的总扇区数。如果小扇区数字段的值不为0,那么本字段的值为0 |
结合图2和表2的数据可以得出以下信息:
1. 本U盘的扇区大小为512字节
2. 每簇扇区数为1,也就是说U盘共有15簇。
3. 保留扇区数为1,也就是说U盘在FAT开始之前仅有一个引导扇区。
4. 只有1个FAT表,占用2个扇区。
5. 本U盘共有 16个扇区,总容量为8KB。
6. 每道扇区1个,磁头1个,无隐藏扇区。
在图2中,偏移0x3E开始的数据为操作系统引导代码。这是由偏移0x00开始的跳转指令所指向的,此段指令在不同的操作系统上和不同的引导方式上,其内容也是不同的,这里就不对引导代码进行探讨了,因为它涉及的很多东西,且本设计并没有使用到它。
扇区的最后两个字节存储值为0xAA55的DBR有效标志,对于其他的取值,系统将不会执行DBR相关指令。
操作系统之所以设置保留扇区,是为了对DBR作备份或留待以后升级时用。当DBR扇区被破坏导致分区无法访问时。可以用保留扇区的备份替换第0扇区来找回数据。在图2中,DBR偏移量0x0E位置的2个字节是0x0001,指明了保留的扇区数为1,即第一个FAT开始之前的扇区数,它包括引导扇区。
FAT表和数据的存储原则
FAT(File Allocation Table 即文件分配表)是Microsoft在FAT文件系统中用于磁盘数据(文件)索引和定位引进的一种链式结构。它有两个,为的是备份。假如把磁盘比作一本书,FAT表可以认为是相当于书中的目录,而文件就是各个章节的内容,但FAT表的表示方法与目录有些不同。
在FAT文件系统中,文件的存储依照FAT表制定的簇链式数据结构来进行。同时,FAT 文件系统将组织数据时使用的目录也抽象为文件,以简化对数据的管理。
图5所示给出了此U盘上FAT表的数据。
图5 FAT表
FAT 文件系统之所以有12,16,32 不同的版本之分,其根本在于FAT 表用来记录任意一簇链接的二进制位数。以FAT16为例,每一簇在FAT表中占据2个字节(二进制16位)。所以,FAT16最大可以表示的簇号为0xFFFF,以32K为簇的大小的话,FAT16可以管理的最大磁盘空间为:32KB×65535=2048MB,这就是为什么FAT16不支持超过2GB分区的原因。
FAT表实际上是一个数据表,以2个字节为单位,我们暂将这个单位称为FAT记录项,从图5中,可以知道,前一个记录项(即前两个字节)是0xFFF8,它是FAT表的标志,通常情况,第1、2个记录项用作介质描述。从第三个记录项开始记录除根目录外的其他文件及文件夹的簇链情况。根据簇的表现情况FAT用相应的取值来描述,见表1-4。
因为此为空盘,所以FAT表记录中仅有一个FAT表标志 F8 FF。
FAT表的另一扇区图,见图6。
图6
FAT文件系统的目录结构其实是一颗有向的从根到叶的树,这里提到的有向是指对于FAT 分区内的任一文件(包括文件夹),均需从根目录寻址来找到。可以这样认为:目录存储结构的入口就是根目录。
FAT 文件系统根据根目录来寻址其他文件(包括文件夹),故而根目录的位置必须在磁盘存取数据之前得以确定。FAT文件系统就是根据分区的相关DBR参数与DBR中存放的已经计算好的FAT表(2 份)的大小来确定的。格式化以后,根目录的大小和位置其实都已经确定下来了——位置紧随FAT2之后。但此U盘无FAT2,所以就紧随FAT1之后,占据第3扇区。
FAT文件系统的一个重要思想是把目录(文件夹)当作一个特殊的文件来处理,在FAT16中,虽然根目录地位并不等同于普通的文件或者说是目录,但其组织形式和普通的目录(文件夹)并没有不同。FAT 分区中所有的文件夹(目录)文件,实际上可以看作是一个存放其他文件(文件夹)入口参数的数据表。其具体存储原理是:不管目录文件所占空间为多少簇,一簇为多少字节。系统都会以32个字节为单位进行目录文件所占簇的分配。这32个字节以确定的偏移来定义本目录下的一个文件(或文件夹)的属性,实际上是一个简单的二维表。这32个字节的各字节偏移定义如表1-5所示。
因为此盘目前为空盘,所以根目录除了磁盘名称数据外,还无任何文件记录。在后面会具体举例说明。
根目录扇区数据请看图7.
图7
红色圈出来的32字节,作用是在盘符中显示名称“YangYong”。文件名“YangYong”;无扩展名;属性为归档卷标;其它项目全为0。
从第4扇区到第15扇区全为数据区,见图8。
图 8
下面我们通过在U盘中新建一个文件名为ReadMe.txt的文件来对比上面空盘,看存储内容发生了那些变化,帮助大家更好的了解FAT构架。
此时U盘容量变为5.5KB可用,见图9
图9
打开U盘可以看到我们新建的文件,见图10
图10
虽然文件只有79个字节,但却占据了512个字节,也就是一个扇区的容量。留意一下文件属性,后面我们会做对比。
打开文件,可以看到里面的内容,见图11。
图 11
用WinHex打开此U盘。扇区0的数据没有任何变化,而扇区1也就是FAT1区的数据发生了变化,如图12,请此图与前面的图5对比看
图 12
FAT1区多了两个字节,即“FF FF”表示此文件仅占一个扇区就结束了。
扇区2的数据也没有任何变化,
而扇区3作为根目录区,已经发生了变化,如图13,请与前面的图7对比看。
图13
红色圈起来的部分,为新增加的内容,下面具体分析一下其含义。
图14
1. “52 45 41 44 4D 45 20 20” 为文件名的ASCII码,字符串为“ReadMe”。
2. “54 58 54” 为扩展名“txt”。
3. “20” 表示此文件属性为归档。
4. “00” 系统保留
5. “2C” 创建时间的10毫秒位
6. “B2 9A” 文件创建时间
时间 =小时*2048+分钟*32+秒/2 =19×512 + 21×32 +36/2 =0x9AB2
7. “33 3D” 文件创建日期
日期 =(年份-1980)*512+月份*32+日 =(2010 -1980)×512 +9×32 +19 =0x3D33
8. “33 3D” 文件最近访问日期
日期 =(年份-1980)*512+月份*32+日 =(2010 -1980)×512 +9×32 +19 =0x3D33
9. “00 00” 文件起始簇号高16位
10. “A4 9A” 文件最近修改时间
时间 =小时*2048+分钟*32+秒/2 =19×512 + 21×32 +8/2 =0x9AA4
11. “33 3D” 文件最近修改日期
日期 =(年份-1980)*512+月份*32+日 =(2010 -1980)×512 +9×32 +19 =0x3D33
12. “02 00” 文件起始簇号为 0002 即 第二簇
13. “4F 00 00 00” 文件长度为0x4F 即79个字节。
文章部分内容参考了http://blog.csdn.net/menghnhhuan/archive/2009/06/15/4270168.aspx,在此表示感谢!
第一次论坛发贴,着实耗时,初浅之极,不妥之处在所难免。。。。。。。
下面顺便上传一个查看工具和此文中用到的U盘数据文件
下一节,将以一个32MB的TF卡的实例更深入的探讨FAT文件构造的数据组织形式。请访问http://blog.ednchina.com/singlechip/
用户377235 2015-1-15 10:39
用户377235 2014-3-8 10:06
真得了不起,看了受益匪浅
用户377235 2013-2-13 10:53
用户967597 2012-8-10 11:18
用户377235 2012-8-8 23:01
用户419652 2011-5-31 14:38
用户425516 2010-9-26 20:00
朱玉龙 2010-9-26 17:06
用户425516 2010-9-26 12:18
用户1584993 2010-9-26 11:22