更换CPU后,RPMB无法访问,必须同时更换eMMC
MTK平台的RPMB(Replay Protected Memory Block) solution中,rpmb key的生成是和CPU ID相绑定,如果遇到fail IC,或HW交叉实验中需要更换CPU(BB chip),那么就需要把eMMC一同做更换。原因是rpmb key具有OTP(One Time Programmable)特性,一旦被写入eMMC无法更改也无法擦除(JEDEC eMMC spec规定),eMMC vendor可能会有特殊方法清除。而不同的CPU计算出的rpmb key会不同,更换CPU后,就无法计算出和当前eMMC中对应的key了。
具体的code是在vendor/mediatek/proprietary/bootable/bootloader/preloader/platform/<PLATFORM>/src/security/trustzone/tz_init.c的trustzone_post_init()函数中以下这段:
#if CFG_TEE_SUPPORT #if CFG_MICROTRUST_TEE_SUPPORT u8 rpmb_key[KEY_LEN]; kdflib_get_msg_auth_key(teearg->hwuid, 16, rpmb_key, KEY_LEN); teei_key_param_prepare(TEE_PARAMETER_ADDR,(u8 *)teearg->hwuid,rpmb_key); #else u8 rpmb_key[32]; seclib_get_msg_auth_key(teearg->hwuid, 16, rpmb_key, 32); #endif mmc_rpmb_set_key(rpmb_key); teearg->tee_rpmb_size = mmc_rpmb_get_size(); DBG_MSG("%s TEE RPMB Size : 0x%x\n", MOD, teearg->tee_rpmb_size); #endif目前的solution是默认download后第一次开机就会生成并把rpmb key写入到eMMC。
对于分析问题需要HW交叉实验的场景,如果需要用到RPMB的话,则必须要同时更换eMMC。
对于产线遇到Fail IC的场景,我们提供以下的rpmb key延迟绑定的solution可以帮助客户有效减少Fail IC带来的eMMC额外成本损失。
[SOLUTION]
所谓rpmb key延迟绑定,就是产线依需求来决定何时触发绑定rpmb key(把rpmb key写入eMMC)的操作。建议是在产线比较靠后的工位,确认手机除rpmb之外的其他功能都正常后,再trigger programming rpmb key 到eMMC,之后再测试与rpmb相关的功能。建议的solution是可以利用sw reboot时在rtc寄存器中设置标记的方法作为判断标志。
1. 贵司可以在工模中新增一个按钮"Reboot for Set RPMB Key",点击按钮后(或者新增一个AT指令),执行以下操作:
property_set(“sys.powerctl”, “reboot,bootloader”); while(1) { pause(); }如果是用Java code来实做的话,可以参考上面的code对应改写即可。
reboot命令参数可以根据需求客制化,这里是利用现成的bootloader参数,对应重启到fastboot mode。我们就是利用kernel在重启前向RTC寄存器写入的特殊flag作为preloader写rpmb key的判断标志位。
2. Preloader也需要做对应的修改。
2.1 vendor/mediatek/proprietary/bootable/bootloader/preloader/platform/<PLATFORM>/src/security/trustzone/tz_init.c
找到void trustzone_post_init(void)函数,在上面定义一个全局变量:
U16 rpmb_key_set_flag = 0;在这个函数中找到以下这段:
#if CFG_TEE_SUPPORT u8 rpmb_key[32]; seclib_get_msg_auth_key(teearg->hwuid, 16, rpmb_key, 32); mmc_rpmb_set_key(rpmb_key); teearg->tee_rpmb_size = mmc_rpmb_get_size(); DBG_MSG("%s TEE RPMB Size : 0x%x\n", MOD, teearg->tee_rpmb_size); #endif
修改为:
找到bool rtc_boot_check(void)这个函数,在这个函数上面添加:
测试时可以再执行特殊重启前先测试看RPMB是否不能读写。特殊重启后RPMB即可正常读写。
#if CFG_TEE_SUPPORT u8 rpmb_key[32]; if (rpmb_key_set_flag != 0) { seclib_get_msg_auth_key(teearg->hwuid, 16, rpmb_key, 32); mmc_rpmb_set_key(rpmb_key); } teearg->tee_rpmb_size = mmc_rpmb_get_size(); DBG_MSG("%s TEE RPMB Size : 0x%x\n", MOD, teearg->tee_rpmb_size); #endif2.2 vendor/mediatek/proprietary/bootable/bootloader/preloader/platform/<PLATFORM>/src/drivers/rtc.c
找到bool rtc_boot_check(void)这个函数,在这个函数上面添加:
extern U16 rpmb_key_set_flag;在这个函数中找到以下这行:
pdn1 = RTC_Read(RTC_PDN1);在这行的后面添加以下的代码:
if (pdn1 & RTC_PDN1_FAST_BOOT) { rpmb_key_set_flag = 1; }贵司测试时,可以先修改Preloader,下adb reboot bootloader来做测试,测试通过后再客制化工模的按钮。
测试时可以再执行特殊重启前先测试看RPMB是否不能读写。特殊重启后RPMB即可正常读写。
3. RTC寄存器客制化
上面我们提供的sample是直接利用了现有的fastboot mode的rtc register bit。如果贵司想要更换为其他的rtc bit来作为trigger rpmb key programming的flag的话,需要客制化kernel中相关的code。
3.1 kernel-3.18/drivers/watchdog/mediatek/wdk/wd_api.c
void arch_reset(char mode, const char *cmd) 函数中以下这段:
if (cmd && !strcmp(cmd, "charger")) { /* do nothing */ } else if (cmd && !strcmp(cmd, "recovery")) { rtc_mark_recovery(); } else if (cmd && !strcmp(cmd, "bootloader")) { rtc_mark_fast(); } else if (cmd && !strcmp(cmd, "kpoc")) { #ifdef CONFIG_MTK_KERNEL_POWER_OFF_CHARGING rtc_mark_kpoc(); #endif } else { reboot = 1; }
以上这段就是执行reboot命令时对传入的参数处理的部分,会set rtc对应bit。
如果想换成其他rtc bit和reboot参数的话,可以模仿recovery或bootlooaer参数的处理方法自行添加。之后只需要对应修改preloader即可。