From a862b85a4674b26d1b72b9abc04c428a1eec5aec Mon Sep 17 00:00:00 2001 From: CTCaer Date: Sat, 4 Jul 2020 21:43:34 +0300 Subject: [PATCH] hos: Add Mariko warmboot storage and general configurator The Mariko warmboot storage is needed because the warmboot exploit is not existant. Fuses and PA id must match with the proper warmboot binary. Thus for supporting downgrades, we keep a copy of it for future use. --- bootloader/hos/hos.c | 16 +++----- bootloader/hos/pkg1.c | 94 +++++++++++++++++++++++++++++++++++++++++++ bootloader/hos/pkg1.h | 1 + 3 files changed, 100 insertions(+), 11 deletions(-) diff --git a/bootloader/hos/hos.c b/bootloader/hos/hos.c index 042be2f..1a4a616 100644 --- a/bootloader/hos/hos.c +++ b/bootloader/hos/hos.c @@ -866,10 +866,13 @@ int hos_launch(ini_sec_t *cfg) } } + // Configure and manage Warmboot binary. + pkg1_warmboot_config(&ctxt, kb, warmboot_base); + // Replace 'warmboot.bin' if requested. if (ctxt.warmboot) memcpy((void *)warmboot_base, ctxt.warmboot, ctxt.warmboot_size); - else + else if (!h_cfg.t210b01) { // Patch warmboot on T210 to allow downgrading. if (kb >= KB_FIRMWARE_VERSION_700) @@ -883,9 +886,6 @@ int hos_launch(ini_sec_t *cfg) for (u32 i = 0; warmboot_patchset[i].off != 0xFFFFFFFF; i++) *(vu32 *)(ctxt.pkg1_id->warmboot_base + warmboot_patchset[i].off) = warmboot_patchset[i].val; } - // Set warmboot address in PMC if required. - if (kb <= KB_FIRMWARE_VERSION_301) - PMC(APBDEV_PMC_SCRATCH1) = warmboot_base; // Replace 'SecureMonitor' if requested or patch Pkg2 checks if needed. if (ctxt.secmon) @@ -985,7 +985,6 @@ int hos_launch(ini_sec_t *cfg) } // Merge extra KIP1s into loaded ones. - gfx_printf("%kPatching kips%k\n", 0xFFFFBA00, 0xFFCCCCCC); LIST_FOREACH_ENTRY(merge_kip_t, mki, &ctxt.kip1_list, link) pkg2_merge_kip(&kip1_info, (pkg2_kip1_t *)mki->kip1); @@ -1004,6 +1003,7 @@ int hos_launch(ini_sec_t *cfg) } // Patch kip1s in memory if needed. + gfx_printf("%kPatching kips%k\n", 0xFFFFBA00, 0xFFCCCCCC); const char* unappliedPatch = pkg2_patch_kips(&kip1_info, ctxt.kip1_patches); if (unappliedPatch != NULL) { @@ -1034,12 +1034,6 @@ int hos_launch(ini_sec_t *cfg) int bootStateDramPkg2 = 0; int bootStatePkg2Continue = 0; - // Set warmboot PA address ids for 3.0.0 - 3.0.2. - if (kb == KB_FIRMWARE_VERSION_300) - PMC(APBDEV_PMC_SECURE_SCRATCH32) = 0xE3; // Warmboot 3.0.0 PA address id. - else if (kb == KB_FIRMWARE_VERSION_301) - PMC(APBDEV_PMC_SECURE_SCRATCH32) = 0x104; // Warmboot 3.0.1/.2 PA address id. - // Clear pkg1/pkg2 keys. se_aes_key_clear(8); se_aes_key_clear(11); diff --git a/bootloader/hos/pkg1.c b/bootloader/hos/pkg1.c index 1b4a673..cfd16f5 100644 --- a/bootloader/hos/pkg1.c +++ b/bootloader/hos/pkg1.c @@ -24,7 +24,11 @@ #include "../config.h" #include #include +#include #include +#include +#include +#include #include extern hekate_config h_cfg; @@ -215,3 +219,93 @@ const u8 *pkg1_unpack(void *wm_dst, u32 *wb_sz, void *sm_dst, void *ldr_dst, con return sec_map; } + +static void _warmboot_filename(char *out, u32 fuses) +{ + if (fuses < 16) + { + out[19] = '0'; + itoa(fuses, &out[19 + 1], 10); + } + else + itoa(fuses, &out[19], 10); + strcat(out, ".bin"); +} + +void pkg1_warmboot_config(void *hos_ctxt, u32 kb, u32 warmboot_base) +{ + launch_ctxt_t *ctxt = (launch_ctxt_t *)hos_ctxt; + + // Set warmboot address in PMC if required. + if (kb <= KB_FIRMWARE_VERSION_301) + PMC(APBDEV_PMC_SCRATCH1) = warmboot_base; + + if (h_cfg.t210b01) + { + u32 pa_id; + u32 fuses_fw = kb + 2; + u32 fuses_max = KB_FIRMWARE_VERSION_MAX + 3; + u8 burnt_fuses = fuse_count_burnt(fuse_read_odm(7)); + + // Add one more fuse for high versions. + if (kb > KB_FIRMWARE_VERSION_910 || !memcmp(ctxt->pkg1_id->id, "20200303104606", 8)) + fuses_fw++; + + // Save current warmboot in storage cache and check if another one is needed. + if (!ctxt->warmboot) + { + char path[128]; + f_mkdir("warmboot_mariko"); + strcpy(path, "warmboot_mariko/wb_"); + _warmboot_filename(path, fuses_fw); + if (f_stat(path, NULL)) + sd_save_to_file((void *)warmboot_base, ctxt->warmboot_size, path); + + // Load warmboot fw from storage if not matched. + if (burnt_fuses > fuses_fw) + { + u32 tmp_fuses = burnt_fuses; + while (true) + { + _warmboot_filename(path, burnt_fuses); + if (!f_stat(path, NULL)) + { + ctxt->warmboot = sd_file_read(path, &ctxt->warmboot_size); + burnt_fuses = tmp_fuses; + break; + } + if (tmp_fuses >= fuses_max) + break; + tmp_fuses++; + } + } + } + + // Configure Warmboot parameters. + switch (burnt_fuses) + { + case KB_FIRMWARE_VERSION_600 + 2: // 7 fuses burnt. + pa_id = 0x87; + break; + case KB_FIRMWARE_VERSION_620 + 2: // 8 fuses burnt. 0x21 raise. + pa_id = 0xA8; + break; + default: // From 7.0.0 and up PA id raises by 0x21 with a static base. + pa_id = 0x129; + pa_id += 0x21 * (burnt_fuses - KB_FIRMWARE_VERSION_700 - 2); + break; + } + + // Set Warmboot Physical Address ID and lock SECURE_SCRATCH32 register. + PMC(APBDEV_PMC_SECURE_SCRATCH32) = pa_id; + PMC(APBDEV_PMC_SEC_DISABLE3) |= BIT(16); + } + else + { + // Set Warmboot Physical Address ID for 3.0.0 - 3.0.2. + if (kb == KB_FIRMWARE_VERSION_300) + PMC(APBDEV_PMC_SECURE_SCRATCH32) = 0xE3; // Warmboot 3.0.0 PA address id. + else if (kb == KB_FIRMWARE_VERSION_301) + PMC(APBDEV_PMC_SECURE_SCRATCH32) = 0x104; // Warmboot 3.0.1/.2 PA address id. + } +} diff --git a/bootloader/hos/pkg1.h b/bootloader/hos/pkg1.h index ef17300..036b438 100644 --- a/bootloader/hos/pkg1.h +++ b/bootloader/hos/pkg1.h @@ -78,5 +78,6 @@ const pkg1_id_t *pkg1_get_latest(); const pkg1_id_t *pkg1_identify(u8 *pkg1); int pkg1_decrypt(const pkg1_id_t *id, u8 *pkg1); const u8 *pkg1_unpack(void *wm_dst, u32 *wb_sz, void *sm_dst, void *ldr_dst, const pkg1_id_t *id, u8 *pkg1); +void pkg1_warmboot_config(void *hos_ctxt, u32 kb, u32 warmboot_base); #endif