Skip to content

Latest commit

 

History

History
214 lines (156 loc) · 13.8 KB

240813a_fat.md

File metadata and controls

214 lines (156 loc) · 13.8 KB

磁盘分区表和文件系统

目录

  • 1 MBR分区表格式
    • 1.1 Table定义
    • 1.2 扩展分区表EBR
  • 2 GPT分区表格式
    • 1.1 Table定义
    • 1.2 分区项定义
  • 3 FAT文件系统
    • 3.1 一些基本概念
    • 3.2 Boot Sector
    • 3.3 数据格式
      • 3.3.1 文件系统类型判定

1 MBR分区表格式

MBR包含了MBR启动程序(Legacy BIOS会读取,将其加载到0x7c00并执行)与分区表,放在磁盘开头,大小512字节(一个Sector,放在Sector 0)

MBR最多可以支持4个分区(其中最多1个扩展分区)。其中最多可以将1个分区设定为active。在旧版Windows中,要求系统分区必须标记为active

1.1 Table定义

起始地址(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,可设定0x800x00
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, 1023254, 63, 1023

1.2 扩展分区表EBR

扩展分区的System ID0x050x0F,它可以包含多个逻辑分区,使用链表形式的EBR记录。每个逻辑分区都有一张对应的表,这些表的格式和MBR类似,区别是其中只有2项分区项是有用的,第1项用于描述该分区本身,第2项用于指向下一个分区表的LBA。扩展分区表使用链表的形式存储。理论上逻辑分区数量没有限制,实际上需要看软件限制,太多的逻辑分区会导致较长的EBR扫描时间

每个EBR也占用一个Sector。它除了0x1BE0x1CE两个分区表项以外所有位域都是0。这两个分区表项除了CHS、LBA地址以外所有位域也都是0

2 GPT分区表格式

UEFI官方文档

GPT分区表最多支持记录128个分区,会占用多个LBA。其中LBA0保留防止旧程序意外修改,而LBA1为GPT分区表头,LBA233为GPT分区表项。在磁盘的末尾LBA-33-2为分区表项副本,而-1为分区表头副本。GPT分区表项不再使用CHS,只使用LBA

1.1 Table定义

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 PART45h 46h 49h 20h 50h 41h 52h 54h
0x08 4 GPT版本(0x00010000
0x0C 4 Header大小(固定0x0000005C
0x10 4 Header CRC(从0x000x5C之前的部分)
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 每个分区项大小,通常为1280x00000080
0x58 4 分区表区域的CRC
0x5C 保留,全0

1.2 分区项定义

分区项从LBA2开始放置。每个分区项大小128字节

GPT分区项格式如下

起始(Byte) 大小(Byte) 定义
0x00 16 分区类型GUID,不同的文件系统类型例如MS Basic DataLinux Data等会有对应的固定的值
0x10 16 分区UUID,Linux下为PARTUUID
0x20 8 分区起始LBA
0x28 8 分区结束LBA
0x30 8 分区Attributes。Bit0置1表示该分区是Firmware会访问的,不可删除,例如ESP通常会将该Bit置位。其余Bit基本不会用到
0x38 72 分区名称字符串(使用0x00空格)

3 FAT文件系统

Microsoft的FAT Spec

本地pdf

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,包含文件与目录数据

3.1 一些基本概念

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,就可以获取到下一级文件/目录对应的全部数据

3.2 Boot Sector

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 0x900xE9 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字节

3.3 数据格式

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偏移即可

3.3.1 文件系统类型判定

FAT文件系统直接通过Cluster数量来判定是FAT12,FAT16或FAT32