MBR包含了MBR启动程序(Legacy BIOS会读取,将其加载到0x7c00
并执行)与分区表,放在磁盘开头,大小512字节(一个Sector,放在Sector 0)
MBR最多可以支持4个分区(其中最多1个扩展分区)。其中最多可以将1个分区设定为active。在旧版Windows中,要求系统分区必须标记为active
起始地址(Byte) | 大小(Byte) | 定义 |
---|---|---|
0x000 |
440 |
二进制可执行代码。可以将后面的6 字节也当作代码区,共计446 字节 |
0x1B8 |
4 |
可选的Disk ID或签名 |
0x1BC |
2 |
保留域 |
0x1BE |
16 |
第1个分区项 |
0x1CE |
16 |
第2个分区项 |
0x1DE |
16 |
第3个分区项 |
0x1EE |
16 |
第4个分区项 |
0x1FE |
2 |
0x55, 0xAA ,MBR结束 |
其中每个16
字节长度的分区项格式如下
起始(Byte) | 大小(Byte) | 定义 |
---|---|---|
0x00 |
1 |
分区属性,bit7置位表示active,可设定0x80 或0x00 |
0x01 |
3 |
分区起始地址(寻址方式CHS,依次为Head[7:0] Sector[5:0] Cylinder[9:0] 。实际上由于小端存储,第2字节的高2bit才是第1字节的高位) |
0x04 |
1 |
分区类型System ID ,表示文件系统类型 |
0x05 |
3 |
分区结束地址(最后一个扇区地址,CHS) |
0x08 |
4 |
分区起始LBA |
0x0C |
4 |
分区扇区数量 |
在Legacy BIOS + DOS的启动流程中,MBR中的启动代码会将其自身从
0x7c00
重映射到0x0600
,之后检查MBR分区表项找出active的那个分区,并将其Sector 0中的数据加载到0x7c00
。这个分区的Sector 0被称为DOS bootsector,MBR中的代码会设定SI
并再次跳转到0x7c00
执行DOS启动程序(标准流程。几乎所有的Legacy启动都是最终跳转到0x7c00
)。实现双启动是可能的只能从主分区启动。不能从扩展分区启动
由于MBR中分区起始LBA和分区扇区数量只有32bit,所以MBR不支持2TB以上的磁盘或分区。CHS地址域是没有用的,但是不能设为0。规定分区在不大于8GB时,LBA的设定和CHS设定需要一致;而分区在大于8GB以后,需要设定CHS为255, 63, 1023
或254, 63, 1023
扩展分区的System ID
为0x05
或0x0F
,它可以包含多个逻辑分区,使用链表形式的EBR记录。每个逻辑分区都有一张对应的表,这些表的格式和MBR类似,区别是其中只有2项分区项是有用的,第1项用于描述该分区本身,第2项用于指向下一个分区表的LBA。扩展分区表使用链表的形式存储。理论上逻辑分区数量没有限制,实际上需要看软件限制,太多的逻辑分区会导致较长的EBR扫描时间
每个EBR也占用一个Sector。它除了0x1BE
和0x1CE
两个分区表项以外所有位域都是0。这两个分区表项除了CHS、LBA地址以外所有位域也都是0
GPT分区表最多支持记录128个分区,会占用多个LBA。其中LBA0
保留防止旧程序意外修改,而LBA1
为GPT分区表头,LBA2
到33
为GPT分区表项。在磁盘的末尾LBA-33
到-2
为分区表项副本,而-1
为分区表头副本。GPT分区表项不再使用CHS,只使用LBA
LBA0
定义和MBR相同,区别是只有Disk ID和第1个分区项中有数据
起始地址(Byte) | 大小(Byte) | 定义 |
---|---|---|
0x1B8 |
4 |
Disk ID |
0x1BE |
16 |
第1个分区项 |
0x1FE |
2 |
0x55, 0xAA |
该分区项格式如下
起始(Byte) | 大小(Byte) | 定义 |
---|---|---|
0x00 |
1 |
固定0x00 |
0x01 |
3 |
起始CHS,固定0x000200 |
0x04 |
1 |
固定0xEE ,GPT Protective |
0x05 |
3 |
结束CHS,如果超出无法表示那么固定为0xFFFFFF |
0x08 |
4 |
起始LBA,固定0x00000001 |
0x0C |
4 |
结束LBA,即最大可访问LBA。如果超出无法表示那么固定为0xFFFFFFFF |
LBA1
定义如下
起始地址(Byte) | 大小(Byte) | 定义 |
---|---|---|
0x00 |
8 |
字符串EFI PART (45h 46h 49h 20h 50h 41h 52h 54h ) |
0x08 |
4 |
GPT版本(0x00010000 ) |
0x0C |
4 |
Header大小(固定0x0000005C ) |
0x10 |
4 |
Header CRC(从0x00 到0x5C 之前的部分) |
0x14 |
4 |
保留,全0 |
0x18 |
8 |
本Header所在LBA,为1 |
0x20 |
8 |
备份Header副本所在LBA,在磁盘最后一个LBA |
0x28 |
8 |
第1个可用于GPT分区项的LBA(不是代表空闲空间,添加新分区不会修改该域) |
0x30 |
8 |
最后1个可用于GPT分区项的LBA |
0x38 |
16 |
磁盘GUID(格式符合UUID) |
0x48 |
8 |
后续的分区项记录起始LBA,为0x00000002 |
0x50 |
4 |
分区项数量(分区项入口数) |
0x54 |
4 |
每个分区项大小,通常为128 (0x00000080 ) |
0x58 |
4 |
分区表区域的CRC |
0x5C |
保留,全0 |
分区项从LBA2
开始放置。每个分区项大小128
字节
GPT分区项格式如下
起始(Byte) | 大小(Byte) | 定义 |
---|---|---|
0x00 |
16 |
分区类型GUID,不同的文件系统类型例如MS Basic Data ,Linux Data 等会有对应的固定的值 |
0x10 |
16 |
分区UUID,Linux 下为PARTUUID |
0x20 |
8 |
分区起始LBA |
0x28 |
8 |
分区结束LBA |
0x30 |
8 |
分区Attributes。Bit0 置1表示该分区是Firmware会访问的,不可删除,例如ESP通常会将该Bit置位。其余Bit基本不会用到 |
0x38 |
72 |
分区名称字符串(使用0x00 空格) |
Microsoft的FAT Spec
FAT文件系统采用小端存储。FAT总共有FAT12,FAT16,FAT32,exFAT,VFAT这5种,其中FAT12最多支持16MB;FAT16最多支持2GB,共64K个Cluster(磁盘越大Cluster越大,空间利用率较低);FAT32中每个FAT入口为32bit(28bit有效),可以无需使用太大的Cluster;exFAT中每个FAT入口为32bit,可以支持4GB以上的文件;VFAT可以支持长文件名(255字节)
FAT32文件系统分为4个基本部分,分别为
-
Reserved Region
-
FAT Region,表区
-
Root Directory Region (FAT32中不存在)
-
Data Region,包含文件与目录数据
FAT32中的数据以Cluster为单位进行管理。一个文件或目录对象实体至少会占用一个Cluster。依据FAT32文件系统总大小,一个Cluster可以是1 2 4 8 16 32 64 128
个Sector(512Byte)大小
FAT32文件系统中的FAT表只是用于记录哪些Cluster的数据是属于同一个文件或目录实体的,它并不包含其他信息例如文件/目录的内容或属性。表中的每一项都和后面实际的Cluster一一映射
FAT32中目录和文件一样也会在数据区分配有Cluster,不同的是目录节点记录的是其包含的子文件和子目录信息(包括Cluster号)而不是Raw Data,其中每个入口大小为32Byte(如果不考虑长文件名)。一个目录实体是可以占用多个Cluster的。如果想要访问指定名称的文件,必须从根目录实体开始遍历。从根目录实体找到下一级文件/目录名对应的入口,从这个32Byte的入口获取到对应的Cluster号码,再到FAT表找到所有该文件/目录实体对应的Cluster,就可以获取到下一级文件/目录对应的全部数据
FAT32文件系统开头的保留区域(Sector 0)又称为Boot Sector,其中包含了BPB(BIOS Parameter Block)。FAT32的BPB格式依次向后兼容FAT16和FAT12。BPB+eBPB大小为90Byte
Boot Sector除Boot Code(420Byte+2Byte0x55AA
)以外其他位域定义如下(共90Byte)
名称 | 起始地址(Byte) | 大小(Byte) | 定义 |
---|---|---|---|
BS_jmpBoot |
0x00 |
3 |
一条跳转指令。可以是0xEB 0xXX 0x90 或0xE9 0xXX 0xXX |
BS_OEMName |
0x03 |
8 |
设定为字符串MSWIN4.1 。实际上经常设定为MSDOS5.0 |
BPB_BytsPerSec |
0x0B |
2 |
Sector大小,通常为512 ,可取1024 2048 4096 |
BPB_SecPerClus |
0x0D |
1 |
FAT中数据以簇Cluster为单位进行分配与管理,一个文件至少会占用一个Cluster。表示每个簇中包含的Sector数量,依据分区大小可取1 2 4 8 16 32 64 128 ,也就是说分区越大,存小文件时利用率越低 |
BPB_RsvdSecCnt |
0x0E |
2 |
从该分区开头LBA开始的保留区域,单位Sector。FAT12和FAT16为1 ,FAT32为32 。保留区域随后的是FAT表,也就是说FAT表的位置通过该值查找 |
BPB_NumFATs |
0x10 |
1 |
FAT表数量,永远为2 。两张FAT表存放的内容是相同的,只是做冗余备份。FAT表数量有可能为1 ,例如在某些自带纠错的存储介质 |
BPB_RootEntCnt |
0x11 |
2 |
在FAT12,FAT16中表示根目录节点中包含的子文件和子目录数量,FAT16中为512 ,FAT32中设为0 不使用 |
BPB_TotSec16 |
0x13 |
2 |
表示该分区的Sector数量,FAT32中设为0 表示不使用,使用BPB_TotSec32 |
BPB_Media |
0x15 |
1 |
不可移动介质为0xF8 ,可移动介质通常为0xF0 。可取0xF0 0xF8 0xF9 0xFA 0xFB 0xFC 0xFD 0xFE 0xFF 。FAT0入口的最低1Byte也会存放该值 |
BPB_FATSz16 |
0x16 |
2 |
表示单个FAT表占用的Sector数量,FAT32中设为0 ,使用BPB_FATSz32 |
BPB_SecPerTrk |
0x18 |
2 |
在支持CHS寻址方式的设备中,表示INT 13h中断获取到的Sectors Per Track 值 |
BPB_NumHeads |
0x1A |
2 |
在支持CHS寻址方式的设备中,表示INT 13h中断获取到的Count Of Heads 值 |
BPB_HiddSec |
0x1C |
4 |
只和INT 13h可见的设备有关,表示该FAT分区在磁盘中的偏移,也就是分区前面的Sector数量。对于该值不同的操作系统可能有不同的设定方式 |
BPB_TotSec32 |
0x20 |
4 |
该FAT32文件系统所在分区的大小,单位Sector,不可以比实际的分区更大。FAT12/FAT16只有在大于0x10000 个Sector时才会使用该域 |
FAT12和FAT16之后的内容
名称 | 起始地址(Byte) | 大小(Byte) | 定义 |
---|---|---|---|
BS_DrvNum |
0x24 |
1 |
通过INT 13h可获取到的Drive Number,软驱为0x00 ,HDD为0x80 |
BS_Reserved1 |
0x25 |
1 |
为0 |
BS_BootSig |
0x26 |
1 |
表示下面3个域有效 |
BS_VolID |
0x27 |
4 |
唯一的序列号,相当于FAT32的UUID(格式XXXX-XXXX ) |
BS_VolLab |
0x2B |
11 |
卷标,和根目录节点中记录的卷标内容相同。不设定卷标默认为NO NAME |
BS_FilSysType |
0x36 |
8 |
可能是字符串FAT FAT16 FAT12 。不可用作判定文件系统类型的依据。但是格式化时需要正确设置 |
FAT32之后的内容
名称 | 起始地址(Byte) | 大小(Byte) | 定义 |
---|---|---|---|
BPB_FATSz32 |
0x24 |
4 |
表示单个FAT表占用的Sector数量 |
BPB_ExtFlags |
0x28 |
2 |
[7] 为0 表示启用镜像FAT表,为1 表示只用1个FAT表;[3:0] 表示使用1个FAT表时使用的是哪个FAT表 |
BPB_FSVer |
0x2A |
2 |
FAT版本,高字节为主版本。可能全设为0 |
BPB_RootClus |
0x2C |
4 |
根目录对应的Cluster号码(从分区开头开始算起),通常为2 |
BPB_FSInfo |
0x30 |
2 |
FSInfo在Reserved中的Sector偏移,通常为1 (相对于分区起始位置。FSInfo可能有备份版本,但是不一定是最新的) |
BPB_BkBootSec |
0x32 |
2 |
Boot Sector备份的位置(单位Sector,相对于分区起始Sector而言),固定为6 |
BPB_Reserved |
0x34 |
12 |
全0 |
BS_DrvNum |
0x40 |
1 |
同上 |
BS_Reserved1 |
0x41 |
1 |
为0 |
BS_BootSig |
0x42 |
1 |
同上 |
BS_VolID |
0x43 |
4 |
同上 |
BS_VolLab |
0x47 |
11 |
同上 |
BS_FilSysType |
0x52 |
8 |
FAT32 |
此外,Boot Sector末尾也有0x55 0xAA
,代表DBR的结束
Boot Sector后面还有一个FSInfo Sector。这个FSInfo Sector也会有一个备份
FAT32从
0x5A
开始即Boot Sector的Reserved区域,上述重要信息占用90字节
FAT表的大小是固定的。在分区起始LBA加上BPB_RsvdSecCnt
就得到第一张FAT表的位置,再加上BPB_FATSz32
就得到第二张FAT表的位置,第二张FAT之后就是数据区了。FAT表中每4字节对应一个Cluster,这4个字节可能是全0,也可能是存放了下一个Cluster序号下标,也可能是表示目录/文件节点的终结,等等。Cluster序号从2开始,第一个数据区Cluster(Cluster 2)紧接着第二张FAT表之后
根据Cluster大小的不同(Sector的2^n倍),想要一个Cluster对应的LBA起始地址直接将Cluster序号左移再加LBA偏移即可
FAT文件系统直接通过Cluster数量来判定是FAT12,FAT16或FAT32