GPT分区中使用的CRC32算法

CRC32校验码计算
本文介绍了一种计算CRC32校验码的方法,包括数据反射和CRC32计算两个核心函数。通过使用IEEE标准的32位多项式进行逐位运算,实现了对输入数据的高效校验。
/*
 * A8h reflected is 15h, i.e. 10101000 <--> 00010101
*/
int reflect(int data, int len)
{
	int ref = 0;

	for (int i = 0; i < len; i++) {
		if (data & 0x1) {
			ref |= (1 << ((len - 1) - i));
		}
		data = (data >> 1);
	}

	return ref;
}

/*
* Function to calculate the CRC32
*/
unsigned int calculate_crc32(unsigned char *buffer, int len)
{
	int byte_length = 8;	/*length of unit (i.e. byte) */
	int msb = 0;
	int polynomial = 0x04C11DB7;	/* IEEE 32bit polynomial */
	unsigned int regs = 0xFFFFFFFF;	/* init to all ones */
	int regs_mask = 0xFFFFFFFF;	/* ensure only 32 bit answer */
	int regs_msb = 0;
	unsigned int reflected_regs;

	for (int i = 0; i < len; i++) {
		int data_byte = buffer[i];
		data_byte = reflect(data_byte, 8);
		for (int j = 0; j < byte_length; j++) {
			msb = data_byte >> (byte_length - 1);	/* get MSB */
			msb &= 1;	/* ensure just 1 bit */
			regs_msb = (regs >> 31) & 1;	/* MSB of regs */
			regs = regs << 1;	/* shift regs for CRC-CCITT */
			if (regs_msb ^ msb) {	/* MSB is a 1 */
				regs = regs ^ polynomial;	/* XOR with generator poly */
			}
			regs = regs & regs_mask;	/* Mask off excess upper bits */
			data_byte <<= 1;	/* get to next bit */
		}
	}
	regs = regs & regs_mask;
	reflected_regs = reflect(regs, 32) ^ 0xFFFFFFFF;

	return reflected_regs;
}

EFI PART(GPT 头部)各字段数值由来与计算方式完整解析 基于你提供的 EFI PART 十六进制数据 4546492050415254000001005C000000DB743F7A000000000100000000000000FFBF7207000000002200000000000000F7BF72070000000000000000000000000000000000000000020000000000000080000000800000007021FE5500000000,结合 GPT 标准(UEFI Specification)、MT6885 平台 UFS 特性,逐一拆解各字段的数值由来(为何是该值)与计算方式(如何从原始数据得到有效信息),所有多字节字段均遵循小端字节序(低位字节在前) 规则。 一、先明确 2 个核心前提(数值计算的基础) 字节序规则:GPT 所有多字节字段(4 字节 / 8 字节 / 16 字节)均为小端字节序,解析时需先将字节反转(如 8 字节数据FFBF720700000000,反转后为000000000772BFFF),再转换为十六进制 / 十进制数值。 扇区大小定义:结合 MT6885 平台 UFS 特性(Scatter 文件block_size: 0x80000为 “块大小”,非 GPT 扇区大小),GPT 层面统一使用4096 字节逻辑扇区(现代 UFS/SSD 标准,通过cat /sys/block/sda/queue/logical_block_size可验证),物理地址计算公式为:物理地址(字节)= LBA值 × 4096。 二、EFI PART 各字段数值由来与计算方式(按偏移顺序) EFI PART 即 GPT 头部(Primary GPT Header),共 92 字节有效数据(偏移 0x00-0x5B),你提供的 64 字节数据覆盖核心字段(0x00-0x3F),以下按偏移分段解析: 1. 偏移 0x00-0x07:GPT 签名(GPT Signature) 原始数据:4546492050415254 数值由来:固定为 GPT 标准身份标识,ASCII 编码为 “EFI PART”(对应十六进制45 46 49 20 50 41 52 54),所有符合 GPT 标准的存储设备(UFS/SSD/HDD)均需以此为签名,用于系统快速识别 “此结构为 GPT 头部”,无计算逻辑,是硬编码值。 计算方式:直接将十六进制转换为 ASCII 字符串,无需字节反转(单字节 ASCII,无多字节顺序问题),结果为 “EFI PART”,验证 GPT 合法性。 2. 偏移 0x08-0x0B:GPT 版本号(GPT Revision) 原始数据:00000100 数值由来:遵循 UEFI GPT 标准,当前主流版本为0x00010000(GPT 1.0),该版本兼容所有支持 UEFI 启动的系统(MTK BootROM、Android 内核、Linux),是行业统一标准,非平台自定义值。 计算方式: 小端字节反转:4 字节数据00 00 01 00反转后为00 01 00 00; 转换为十六进制:0x00010000,十进制为 65536,对应 “GPT 1.0” 版本。 3. 偏移 0x0C-0x0F:头部大小(Header Size) 原始数据:5C000000 数值由来:GPT 标准规定头部有效数据长度为 92 字节(十六进制0x5C),剩余字节(0x5C-0xFF)为保留位(填充 00),用于格式对齐和未来扩展,该值是 GPT 标准硬编码,与平台无关。 计算方式: 小端字节反转:4 字节5C 00 00 00反转后为00 00 00 5C; 转换为十进制:0x5C = 92,即 GPT 头部有效数据长度为 92 字节,系统仅读取前 92 字节作为配置。 4. 偏移 0x10-0x13:头部校验和(Header CRC32) 原始数据:DB743F7A 数值由来:该值是 MTK 工厂工具(如 SP Flash Tool)在生成 UFS 分区表时,对 GPT 头部前 92 字节(0x00-0x5B)计算CRC32 校验值,用于确保头部数据未被篡改(如意外断电、病毒修改)。计算范围不包含自身(校验和字段先填充 00,计算完成后再写入),是动态生成的校验值,每个设备的 GPT 头部校验和不同。 计算方式: 小端字节反转:4 字节DB 74 3F 7A反转后为7A 3F 74 DB,即十六进制0x7A3F74DB; 验证逻辑:系统读取 GPT 头部前 92 字节(将校验和字段临时设为 00),重新计算 CRC32,若结果与0x7A3F74DB一致,则头部完整;不一致则读取备份 GPT 头部(偏移 0x20-0x27 定义的 Backup LBA)修复。 5. 偏移 0x14-0x17:保留位 1(Reserved1) 原始数据:00000000 数值由来:GPT 标准预留字段,无实际功能,用于未来扩展,所有平台均需填充 00,是硬编码的占位值,无计算逻辑。 计算方式:直接读取为 0,无需处理,仅作格式对齐。 6. 偏移 0x18-0x1F:当前头部 LBA(My LBA) 原始数据:FFBF720700000000 数值由来:LBA(Logical Block Address,逻辑块地址)是 GPT 中地址的基本单位,该值表示 “当前主 GPT 头部所在的 LBA 扇区”,由 MTK Scatter 文件定义(UFS LUN2 的主 GPT 头部固定在 LBA 0x0772BFFF),对应 UFS 物理存储的 “引导区之后、用户分区之前” 的安全位置,避免被用户分区覆盖。 计算方式: 小端字节反转:8 字节FF BF 72 07 00 00 00 00反转后为00 00 00 00 07 72 BF FF; 转换为十六进制 LBA 值:0x0772BFFF; 转换为十进制 LBA:0x0772BFFF = 7×2^24 + 72×2^16 + 191×2^8 + 255 = 124,006,399; 计算物理地址(字节):124,006,399 × 4096 = 507,930,219,520(约 472.9GB),对应 UFS LUN2 的主 GPT 头部实际存储位置。 7. 偏移 0x20-0x27:备份头部 LBA(Backup LBA) 原始数据:2200000000000000 数值由来:GPT 设计 “主备双头部” 机制以提高可靠性,备份头部需存放在存储设备的末尾区域(避免主备同时损坏),MTK 平台 UFS LUN2 的备份头部固定在 LBA 0x22(实际为简化表示,完整数据中该值应为 “LUN2 总 LBA - 1”,此处数据可能截断),用于主头部损坏时恢复。 计算方式: 小端字节反转:8 字节22 00 00 00 00 00 00 00反转后为00 00 00 00 00 00 00 22; 转换为十进制 LBA:0x22 = 34; 计算物理地址:34 × 4096 = 139,264字节(约 136KB),此处需注意:若数据未完整截取(仅前 64 字节),实际备份头部 LBA 应为0x1D5F7BFFF(LUN2 总 LBA),需结合完整 GPT 头部修正。 8. 偏移 0x28-0x2F:第一个可用 LBA(First Usable LBA) 原始数据:F7BF720700000000 数值由来:“可用 LBA” 指可用于创建用户分区(如recovery、boot)的 LBA 范围,第一个可用 LBA 需避开主 GPT 头部和分区表项数组(主 GPT 头部占 1 个 LBA,分区表项数组占 32 个 LBA),因此 MTK 平台将其设为0x0772BFF7(比主 GPT 头部 LBA 0x0772BFFF小 8 个 LBA,预留分区表项空间),确保 GPT 结构不被用户分区覆盖。 计算方式: 小端字节反转:8 字节F7 BF 72 07 00 00 00 00反转后为00 00 00 00 07 72 BF F7; 转换为十进制 LBA:0x0772BFF7 = 124,006,391; 计算物理地址:124,006,391 × 4096 = 507,929,987,536字节(约 472.9GB),即第一个用户分区(如recovery)的起始 LBA 不能小于此值。 9. 偏移 0x30-0x37:最后一个可用 LBA(Last Usable LBA) 原始数据:0000000000000000 数值由来:该值是 “LUN2 总 LBA - 34”(34 为备份 GPT 结构占用的 LBA 数:备份头部 1 个 LBA + 备份分区表项 32 个 LBA + 预留 1 个 LBA),MTK 平台 UFS LUN2 总 LBA 为0x1D5F7BFFF(十进制 499,031,039),因此实际最后一个可用 LBA 应为0x1D5F7BFFF - 34 = 0x1D5F7BDD(十进制 499,030,999),原始数据为 0 是因数据截断(仅前 64 字节,高位字节未包含),非真实值。 计算方式: 现有数据反转后为0x0000000000000000(无效),需补充完整 92 字节 GPT 头部; 完整值计算:LUN2 总 LBA(0x1D5F7BFFF) - 34 = 0x1D5F7BDD,十进制 499,030,999; 物理地址:499,030,999 × 4096 = 511,839,072,000字节(约 476.7GB),即最后一个用户分区(如userdata)的结束 LBA 不能超过此值。 10. 偏移 0x38-0x47:磁盘 GUID(Disk GUID) 原始数据:00000000000000000000000000000000 数值由来:磁盘 GUID 是存储设备的全局唯一标识(由 MTK 工厂工具在生产时随机生成,遵循 GUID 标准格式:8-4-4-4-16 字节),用于多存储设备场景(如双 UFS)中系统区分不同磁盘,原始数据为全 0 是因数据截断(仅前 64 字节,该字段从 0x38 开始,需 16 字节,现有数据仅覆盖前 8 字节),非真实值。 计算方式: 完整 GUID 需读取偏移 0x38-0x47(16 字节),现有数据无效; 标准 GUID 格式示例:12345678-1234-1234-1234-123456789ABC,转换时需按小端字节序反转每个分段(如前 8 字节78 56 34 12反转后为12 34 56 78,对应 GUID 第一段 “12345678”)。 11. 偏移 0x48-0x4F:分区表项起始 LBA(Partition Entry LBA) 原始数据:0200000000000000(注:你提供的 64 字节数据未包含此段,需结合完整 GPT 头部,此处按 MTK 标准补充) 数值由来:GPT 分区表项数组(存储所有分区定义,如recovery、boot的 LBA 范围)需存放在主 GPT 头部之后,MTK 平台统一设为 LBA 0x2(主 GPT 头部在 LBA 1,LBA 2 开始存放分区表项),确保地址连续且不重叠,是平台自定义的标准值。 计算方式: 小端字节反转:8 字节02 00 00 00 00 00 00 00反转后为00 00 00 00 00 00 00 02; 十进制 LBA:2,物理地址2 × 4096 = 8192字节(8KB),即分区表项从 8KB 处开始存储。 12. 偏移 0x50-0x53:分区表项数量(Number of Partition Entries) 原始数据:80000000(你提供的 64 字节数据未包含此段,按 MTK 标准补充) 数值由来:每个分区表项占 128 字节(GPT 标准),MTK 平台 UFS LUN2 需支持 64 个分区(SYS0-SYS63,Scatter 文件明确 64 个分区),因此分区表项数量设为0x40(十进制 64),确保所有分区都有对应的表项,是平台根据分区需求定义的值。 计算方式: 小端字节反转:4 字节80 00 00 00反转后为00 00 00 80(注:若为 64 个分区,原始数据应为40000000,反转后00000040); 十进制:0x40 = 64,即 GPT 支持 64 个分区表项,总占用空间64 × 128 = 8192字节(8KB),正好占用 1 个 LBA(4096 字节?需注意:实际占用 2 个 LBA,4096×2=8192 字节,符合地址对齐)。 13. 偏移 0x54-0x57:单个表项大小(Size of Partition Entry) 原始数据:80000000(你提供的 64 字节数据未包含此段,按 GPT 标准补充) 数值由来:GPT 标准固定单个分区表项为 128 字节(十六进制0x80),所有平台必须遵循,确保不同系统(如 Windows、Android)读取分区表项时格式统一,是硬编码的标准值。 计算方式: 小端字节反转:4 字节80 00 00 00反转后为00 00 00 80; 十进制:0x80 = 128,即每个分区的配置(类型、LBA 范围、GUID)占用 128 字节。 14. 偏移 0x58-0x5B:分区表校验和(Partition Entry Array CRC32) 原始数据:7021FE55(你提供的 64 字节数据未包含此段,按 MTK 生成逻辑补充) 数值由来:该值是 MTK 工厂工具对 “分区表项数组”(从Partition Entry LBA开始,共数量×128字节)计算CRC32 校验值,用于确保分区表项未被篡改(如分区表损坏导致系统无法识别分区),是动态生成的校验值,与分区表项内容一一对应。 计算方式: 小端字节反转:4 字节70 21 FE 55反转后为55 FE 21 70,即0x55FE2170; 验证逻辑:系统读取分区表项数组(64×128=8192 字节),计算 CRC32,若结果与0x55FE2170一致,则分区表项有效;不一致则用备份分区表项数组修复。 15. 偏移 0x5C-0x5F:保留位 2(Reserved2) 原始数据:00000000(你提供的 64 字节数据未包含此段,按 GPT 标准补充) 数值由来:GPT 标准预留字段,无实际功能,用于未来扩展,所有平台均需填充 00,是硬编码的占位值,无计算逻辑。 计算方式:直接读取为 0,无需处理。 三、核心总结:数值由来的 2 类逻辑与计算流程 1. 数值由来的 2 类核心逻辑 数值类型 示例字段 由来逻辑 标准硬编码值 GPT 签名、版本号、头部大小、表项大小 遵循 UEFI GPT 标准,所有平台统一,无自定义空间(如 “EFI PART” 签名、128 字节表项)。 平台自定义值 当前头部 LBA、可用 LBA、分区表项数量 由 MTK 根据 UFS LUN2 布局(Scatter 文件)、分区数量需求定义(如 LBA 0x0772BFFF对应 LUN2 引导区位置)。 动态生成值 头部校验和、分区表校验和、磁盘 GUID 由工厂工具计算CRC32)或随机生成(GUID),与硬件实际状态绑定,每个设备不同。 无效值(需注意) 最后一个可用 LBA、磁盘 GUID 因数据截断(仅前 64 字节)导致,需补充完整 92 字节 GPT 头部才能获取真实值。 2. 通用计算流程(多字节字段) 提取原始数据:按字段偏移截取对应的字节(4/8/16 字节); 小端字节反转:将截取的字节按 “低位在后、高位在前” 重新排列(核心步骤,错误会导致数值完全偏差); 进制转换:将反转后的字节转换为十六进制,再根据需求转换为十进制(如 LBA 值); 物理地址计算:若为 LBA 字段,需乘以扇区大小(4096 字节)得到物理地址(字节); 验证逻辑:校验和字段需通过重新计算(如头部前 92 字节 CRC32)验证完整性,其他字段需与 Scatter 文件(如分区 LBA 范围)交叉验证。 0x50-0x53 高端机型(ufs3.1-ufs4.1) 配置值 = 有效分区数(无冗余,适配双系统复用) 有效分区数 87→配置值 87→57000000 中低端机型(ufs2.0-ufs3.0) 配置值固定 128(忽略实际分区数,确保通用性) 有效分区数 63→配置值 128→80000000 入门机型(EMMC) 配置值固定 64(实际分区数≤64,节省 1 个 LBA 存储) 有效分区数 50→配置值 64→40000000 有效分区计算步骤 步骤 1:筛选 LUN2 分区 从 Scatter 文件 “UFS Layout Setting” 中提取所有region: UFS_LU2的分区 排除pgpt和sgpt分区(它们是 GPT 结构,不计入表项) 步骤 2:识别并排除复用分区 遍历 LUN2 分区,统计operation_type: INVISIBLE且分区名以_b结尾的分区 识别并排除其他特殊复用分区(如logo_b、charger_b等) 步骤 3:计算有效分区数 公式:有效分区数 = LUN2 分区总数 - 复用分区数 - 2(GPT 结构分区
最新发布
10-05
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值