ceemmc是emuelec官方闭源的刷入emmc的工具,但在4.3以后就官方不提供了,好在旧版本的ceemmc是二进制程序,放到新系统上也能用,于是乎分析其工作原理,自己折腾,自己将4.5游戏系统刷入emmc的一点经验总结(单系统模式)
1.根据emmc中现有的分区表分析现有分区状态和可用空间,并且迁移cache、data、code等分区,并计算出创建CE_FLASH、CE_STORAGE分区所需的偏移量(4.3版本的ceemmc下,bootloader占用4M、 env占用8M、 misc占用8M、 logo占用8M、dtbo占用8M、 reserved占用64MB、CE_FLASH占用2GB,CE_STORAGE占用剩余的所有空间
2.在emmc中创建包含CE_FLASH、CE_STORAGE的新的分区表
因为ceemmc是不开源的,看不到源码,所以以上2步是通过二进制逆向分析了解的(可能理解不全面)
这里的关键是创建一张新的分区表以替换/dev/reserved中旧的分区表信息(可能还有别的辅助步骤,比如修改dtb信息),使设备开机时就会在/dev目录虚拟出CE_FLASH、CE_STORAGE两个disk设备,然后在开机配置选项文件(cfg_load)中指定启动disk设备为CE_FLASH、CE_STORAGE就可以实现emmc开机了,参考代码如下:
v6 = fopen(a2, "rb+");if ( v6 ){v5 = calloc(1LL, 0x40000LL);if ( v5 ){for ( i = 0; i <= 1; ++i ){if ( (unsigned int)fseek(v6, (i + 16LL) << 18, 0LL) ){puts("Error seek file!");free(v5);fclose();return 0xFFFFFFFFLL;}if ( fread(v5, 0x40000LL, 1LL, v6) != 1 ){puts("Error reading file!");free(v5);fclose();return 0xFFFFFFFFLL;}if ( (signed int)sub_402520(v5, (__int64)"/partitions") < 0 ){printf("Could not remove node '%s' from dtb%d!\n", "/partitions", i);free(v5);fclose();return 0xFFFFFFFFLL;}if ( (unsigned int)fseek(v6, (i + 16LL) << 18, 0LL) ){puts("Error seek file!");free(v5);fclose();return 0xFFFFFFFFLL;}if ( fwrite(v5, 0x40000LL, 1LL, v6) != 1 ){puts("Error writing file!");free(v5);fclose();return 0xFFFFFFFFLL;}}
v15 = *(_DWORD *)a1;if ( (unsigned int)strcmp((const char *)(a1 + 262128), "A~D") ){printf("Error dtb magic: %s!\n", v4 + 262128);return 0xFFFFFFFFLL;}if ( (unsigned __int16)v15 == 35615 ){v17 = (int *)calloc(1LL, 5242880LL);if ( !v17 ){puts("malloc failed for gzip_buf!");return 0xFFFFFFFFLL;}v11 = sub_4097A8(v17, 5242880LL, v16, &v5);if ( (v11 & 0x80000000) != 0 ){printf("Failed to decompress gzipped dtb: %d!\n", v11);free(v17);return 0xFFFFFFFFLL;}v16 = (__int64)v17;v15 = *v17;}if ( v15 == -302117424 ){sub_401DE0(v16, v3);sub_40B95C(v16);*(_DWORD *)(v4 + 262140) = sub_401E48(v4);}else if ( v15 == 1598836033 ){v13 = 0;v10 = *(_DWORD *)(v16 + 4);if ( v10 == 1 ){v13 = 4;}else if ( v10 == 2 ){v13 = 16;}v9 = 3 * v13;v8 = 3 * v13 + 8;v12 = *(_DWORD *)(v16 + 8);for ( i = 0; v12 > i; ++i ){v7 = *(_DWORD *)(v16 + i * v8 + (unsigned __int64)v9 + 12);if ( *(_DWORD *)(v16 + v7) == -302117424 ){sub_401DE0(v16 + v7, v3);sub_40B95C(v16 + v7);}}*(_DWORD *)(v4 + 262140) = sub_401E48(v4);}if ( v17 ){v11 = sub_40976C(v4, (__int64)&v6, (__int64)v17, v5);if ( (v11 & 0x80000000) != 0 ){printf("Failed to compress data to dtb: %d!\n", v11);
3.挂载CE_FLASH、CE_STORAGE分区,并复制相应的数据:
以下以创建挂载CE_FLASH为例子
losetup --find 找出可用loop设备,比如loop1
将分区挂载成loop设备:
losetup /dev/loop1 /dev/mmcblk0 --offset <偏移量>
格式化分区
mkfs.vfat -n "CE_FLASH" /dev/loop1; sync
参考代码
memset(&v11, 0LL, 10240LL);printf("\nStarting to format the new '%s' partition...\n", v10);if ( v7 && v6 )snprintf(&v11,10240LL,"mke2fs -F -L \"%s\" -t ext4 -m 0 \"%s\" -O %s -E offset=%lld %lldm; sync",v10,v9,v8,v7,v6 >> 20);elsesnprintf(&v11, 10240LL, "mke2fs -F -L \"%s\" -t ext4 -m 0 \"%s\" -O %s; sync", v10, v9, v8);if ( (signed int)sub_402C3C(&v11, 0LL, stdout) >= 0 )return 0LL;printf("Error executing cmd '%s'\n", &v11);return 0xFFFFFFFFLL;
}
创建挂载目标目录
mkdir -p /media/CE_FLASH
挂载
mount -o rw,loop /dev/loop1 /media/CE_FLASH
拷贝数据
rsync -ah --info=progress2 /flash/ /media/CE_FLASH
这样就完成了从外置设备/flash中拷贝数据到emmc中的CE_FLASH的工程