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);
else
snprintf(&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的工程