From 24e172b5fbb9c0848285a55f573bc81319237137 Mon Sep 17 00:00:00 2001 From: nwert Date: Fri, 8 Jun 2018 23:07:25 +1200 Subject: [PATCH] Refactored the firmware loader and LP0 config. --- ipl/hos.c | 265 ++++++++++++++++++++++-------------------------- ipl/main.c | 1 - ipl/sdram_lp0.c | 19 +++- 3 files changed, 140 insertions(+), 145 deletions(-) diff --git a/ipl/hos.c b/ipl/hos.c index 4b454e1..fe196fe 100755 --- a/ipl/hos.c +++ b/ipl/hos.c @@ -38,14 +38,41 @@ extern gfx_con_t gfx_con; //#define DPRINTF(...) gfx_printf(&gfx_con, __VA_ARGS__) #define DPRINTF(...) -enum KB_FIRMWARE_VERSION { - KB_FIRMWARE_VERSION_100_200 = 0, - KB_FIRMWARE_VERSION_300 = 1, - KB_FIRMWARE_VERSION_301 = 2, - KB_FIRMWARE_VERSION_400 = 3, - KB_FIRMWARE_VERSION_500 = 4, - KB_FIRMWARE_VERSION_MAX -}; +typedef struct _launch_ctxt_t +{ + void *keyblob; + + void *pkg1; + const pkg1_id_t *pkg1_id; + const pkg2_kernel_id_t *pkg2_kernel_id; + + void *warmboot; + u32 warmboot_size; + void *secmon; + u32 secmon_size; + + void *pkg2; + u32 pkg2_size; + + void *kernel; + u32 kernel_size; + link_t kip1_list; + + int svcperm; + int debugmode; +} launch_ctxt_t; + +typedef struct _merge_kip_t +{ + void *kip1; + link_t link; +} merge_kip_t; + +#define KB_FIRMWARE_VERSION_100_200 0 +#define KB_FIRMWARE_VERSION_300 1 +#define KB_FIRMWARE_VERSION_301 2 +#define KB_FIRMWARE_VERSION_400 3 +#define KB_FIRMWARE_VERSION_500 4 #define NUM_KEYBLOB_KEYS 5 static const u8 keyblob_keyseeds[NUM_KEYBLOB_KEYS][0x10] = { @@ -74,20 +101,17 @@ static const u8 master_keyseed_4xx[0x10] = static const u8 console_keyseed_4xx[0x10] = { 0x0C, 0x91, 0x09, 0xDB, 0x93, 0x93, 0x07, 0x81, 0x07, 0x3C, 0xC4, 0x16, 0x22, 0x7C, 0x6C, 0x28 }; -#define CRC32C_POLY 0x82f63b78 - +#define CRC32C_POLY 0x82F63B78 u32 crc32c(const u8 *buf, u32 len) { - int i; - u32 crc = 0; - - crc = ~crc; - while (len--) { - crc ^= *buf++; - for (i = 0; i < 8; i++) - crc = crc & 1 ? (crc >> 1) ^ CRC32C_POLY : crc >> 1; - } - return ~crc; + u32 crc = 0xFFFFFFFF; + while (len--) + { + crc ^= *buf++; + for (int i = 0; i < 8; i++) + crc = crc & 1 ? (crc >> 1) ^ CRC32C_POLY : crc >> 1; + } + return ~crc; } static void _se_lock() @@ -117,7 +141,6 @@ static void _se_lock() gfx_hexdump(&gfx_con, SE_BASE, (void *)SE_BASE, 0x400);*/ } -// <-- key derivation algorithm int keygen(u8 *keyblob, u32 kb, void *tsec_fw) { u8 tmp[0x10]; @@ -157,7 +180,8 @@ int keygen(u8 *keyblob, u32 kb, void *tsec_fw) se_aes_crypt_block_ecb(0x0C, 0, tmp, master_keyseed_retail); - switch (kb) { + switch (kb) + { case KB_FIRMWARE_VERSION_100_200: case KB_FIRMWARE_VERSION_300: case KB_FIRMWARE_VERSION_301: @@ -181,44 +205,13 @@ int keygen(u8 *keyblob, u32 kb, void *tsec_fw) break; } - // Package2 key + //Package2 key. se_key_acc_ctrl(0x08, 0x15); se_aes_unwrap_key(0x08, 0x0C, key8_keyseed); return 1; } - -typedef struct _launch_ctxt_t -{ - void *keyblob; - - void *pkg1; - const pkg1_id_t *pkg1_id; - const pkg2_kernel_id_t *pkg2_kernel_id; - - void *warmboot; - u32 warmboot_size; - void *secmon; - u32 secmon_size; - - void *pkg2; - u32 pkg2_size; - - void *kernel; - u32 kernel_size; - link_t kip1_list; - - int svcperm; - int debugmode; -} launch_ctxt_t; - -typedef struct _merge_kip_t -{ - void *kip1; - link_t link; -} merge_kip_t; - static int _read_emmc_pkg1(launch_ctxt_t *ctxt) { int res = 0; @@ -344,23 +337,21 @@ static int _config_kip1(launch_ctxt_t *ctxt, const char *value) static int _config_svcperm(launch_ctxt_t *ctxt, const char *value) { - if (*(u8 *)value == '1') + if (*value == '1') { DPRINTF("Disabled SVC verification\n"); ctxt->svcperm = 1; } - return 1; } static int _config_debugmode(launch_ctxt_t *ctxt, const char *value) { - if (*(u8 *)value == '1') + if (*value == '1') { DPRINTF("Enabled Debug mode\n"); ctxt->debugmode = 1; } - return 1; } @@ -395,15 +386,17 @@ int hos_launch(ini_sec_t *cfg) int bootStateDramPkg2; int bootStatePkg2Continue; launch_ctxt_t ctxt; + memset(&ctxt, 0, sizeof(launch_ctxt_t)); list_init(&ctxt.kip1_list); gfx_clear_grey(&gfx_ctxt, 0x1B); gfx_con_setpos(&gfx_con, 0, 0); + //Try to parse config if present. if (cfg && !_config(&ctxt, cfg)) return 0; - + gfx_printf(&gfx_con, "Initializing...\n\n"); //Read package1 and the correct keyblob. @@ -411,9 +404,11 @@ int hos_launch(ini_sec_t *cfg) return 0; gfx_printf(&gfx_con, "Loaded package1 and keyblob\n"); + //Generate keys. keygen(ctxt.keyblob, ctxt.pkg1_id->kb, (u8 *)ctxt.pkg1 + ctxt.pkg1_id->tsec_off); DPRINTF("Generated keys\n"); + //Decrypt and unpack package1 if we require parts of it. if (!ctxt.warmboot || !ctxt.secmon) { @@ -421,85 +416,77 @@ int hos_launch(ini_sec_t *cfg) pkg1_unpack((void *)ctxt.pkg1_id->warmboot_base, (void *)ctxt.pkg1_id->secmon_base, NULL, ctxt.pkg1_id, ctxt.pkg1); gfx_printf(&gfx_con, "Decrypted and unpacked package1\n"); } + //Replace 'warmboot.bin' if requested. if (ctxt.warmboot) memcpy((void *)ctxt.pkg1_id->warmboot_base, ctxt.warmboot, ctxt.warmboot_size); //Set warmboot address in PMC if required. if (ctxt.pkg1_id->set_warmboot) PMC(APBDEV_PMC_SCRATCH1) = 0x8000D000; + //Replace 'SecureMonitor' if requested. - if (ctxt.secmon) { + if (ctxt.secmon) memcpy((void *)ctxt.pkg1_id->secmon_base, ctxt.secmon, ctxt.secmon_size); - } else { //Else we patch it to allow for an unsigned package2 and patched kernel. patch_t *secmon_patchset = ctxt.pkg1_id->secmon_patchset; + gfx_printf(&gfx_con, "%kPatching Security Monitor%k\n", 0xFF00BAFF, 0xFFCCCCCC); + for (u32 i = 0; secmon_patchset[i].off != 0xFFFFFFFF; i++) + *(vu32 *)(ctxt.pkg1_id->secmon_base + secmon_patchset[i].off) = secmon_patchset[i].val; + } - if (secmon_patchset != NULL) + gfx_printf(&gfx_con, "Loaded warmboot.bin and secmon\n"); + + //Read package2. + if (!_read_emmc_pkg2(&ctxt)) + return 0; + + gfx_printf(&gfx_con, "Read package2\n"); + + //Decrypt package2 and parse KIP1 blobs in INI1 section. + pkg2_hdr_t *pkg2_hdr = pkg2_decrypt(ctxt.pkg2); + + LIST_INIT(kip1_info); + pkg2_parse_kips(&kip1_info, pkg2_hdr); + + gfx_printf(&gfx_con, "Parsed ini1\n"); + + //Use the kernel included in package2 in case we didn't load one already. + if (!ctxt.kernel) + { + ctxt.kernel = pkg2_hdr->data; + ctxt.kernel_size = pkg2_hdr->sec_size[PKG2_SEC_KERNEL]; + + if (ctxt.svcperm || ctxt.debugmode) { - gfx_printf(&gfx_con, "%kPatching Security Monitor%k\n", 0xFF00BAFF, 0xFFCCCCCC); - for (u32 i = 0; secmon_patchset[i].off != 0xFFFFFFFF; i++) - *(vu32 *)(ctxt.pkg1_id->secmon_base + secmon_patchset[i].off) = secmon_patchset[i].val; + u32 kernel_crc32 = crc32c((u8 *)ctxt.kernel, ctxt.kernel_size); + ctxt.pkg2_kernel_id = pkg2_identify(kernel_crc32); - gfx_printf(&gfx_con, "Loaded warmboot.bin and secmon\n"); - - //Read package2. - if (!_read_emmc_pkg2(&ctxt)) - return 0; - - gfx_printf(&gfx_con, "Read package2\n"); - //Decrypt package2 and parse KIP1 blobs in INI1 section. - pkg2_hdr_t *pkg2_hdr = pkg2_decrypt(ctxt.pkg2); - - LIST_INIT(kip1_info); - pkg2_parse_kips(&kip1_info, pkg2_hdr); - - gfx_printf(&gfx_con, "Parsed ini1\n"); - - //Use the kernel included in package2 in case we didn't load one already. - if (!ctxt.kernel) + //In case a kernel patch option is set; allows to disable SVC verification or/and enable debug mode. + patch_t *kernel_patchset = ctxt.pkg2_kernel_id->kernel_patchset; + if (kernel_patchset != NULL) { - ctxt.kernel = pkg2_hdr->data; - ctxt.kernel_size = pkg2_hdr->sec_size[PKG2_SEC_KERNEL]; - - if (ctxt.svcperm || ctxt.debugmode) - { - u32 kernel_crc32 = crc32c((u8 *)ctxt.kernel, ctxt.kernel_size); - ctxt.pkg2_kernel_id = pkg2_identify(kernel_crc32); - - //In case a kernel patch option is set. Allows to disable Svc Verififcation or/and enable Debug mode - patch_t *kernel_patchset = ctxt.pkg2_kernel_id->kernel_patchset; - - if (kernel_patchset != NULL) - { - gfx_printf(&gfx_con, "%kPatching kernel%k\n", 0xFF00BAFF, 0xFFCCCCCC); - if (ctxt.svcperm && kernel_patchset[0].off != 0xFFFFFFFF) - *(vu32 *)(ctxt.kernel + kernel_patchset[0].off) = kernel_patchset[0].val; - if (ctxt.debugmode && kernel_patchset[1].off != 0xFFFFFFFF) - *(vu32 *)(ctxt.kernel + kernel_patchset[1].off) = kernel_patchset[1].val; - } - } + gfx_printf(&gfx_con, "%kPatching kernel%k\n", 0xFF00BAFF, 0xFFCCCCCC); + //TODO: this is a bit ugly, perhaps attach a 'key' to the patchset and pass it via ini. + if (ctxt.svcperm && kernel_patchset[0].off != 0xFFFFFFFF) + *(vu32 *)(ctxt.kernel + kernel_patchset[0].off) = kernel_patchset[0].val; + if (ctxt.debugmode && kernel_patchset[1].off != 0xFFFFFFFF) + *(vu32 *)(ctxt.kernel + kernel_patchset[1].off) = kernel_patchset[1].val; } - - //Merge extra KIP1s into loaded ones. - gfx_printf(&gfx_con, "%kPatching kernel initial processes%k\n", 0xFF00BAFF, 0xFFCCCCCC); - LIST_FOREACH_ENTRY(merge_kip_t, mki, &ctxt.kip1_list, link) - pkg2_merge_kip(&kip1_info, (pkg2_kip1_t *)mki->kip1); - - //Rebuild and encrypt package2. - pkg2_build_encrypt((void *)0xA9800000, ctxt.kernel, ctxt.kernel_size, &kip1_info); - gfx_printf(&gfx_con, "Rebuilt and loaded package2\n"); - } else { - //Read package2. - if (!_read_emmc_pkg2(&ctxt)) - return 0; - - gfx_printf(&gfx_con, "Loaded package2\n"); - memcpy((void *)0xA9800000, ctxt.pkg2, ctxt.pkg2_size); } } - // Unmount SD Card + + //Merge extra KIP1s into loaded ones. + gfx_printf(&gfx_con, "%kPatching kernel initial processes%k\n", 0xFF00BAFF, 0xFFCCCCCC); + LIST_FOREACH_ENTRY(merge_kip_t, mki, &ctxt.kip1_list, link) + pkg2_merge_kip(&kip1_info, (pkg2_kip1_t *)mki->kip1); + + //Rebuild and encrypt package2. + pkg2_build_encrypt((void *)0xA9800000, ctxt.kernel, ctxt.kernel_size, &kip1_info); + gfx_printf(&gfx_con, "Rebuilt and loaded package2\n"); + + //Unmount SD card. f_mount(NULL, "", 1); gfx_printf(&gfx_con, "\n%kBooting...%k\n", 0xFF00FF96, 0xFFCCCCCC); @@ -507,33 +494,29 @@ int hos_launch(ini_sec_t *cfg) se_aes_key_clear(0x8); se_aes_key_clear(0xB); - switch (ctxt.pkg1_id->kb) { - case KB_FIRMWARE_VERSION_100_200: - case KB_FIRMWARE_VERSION_300: - case KB_FIRMWARE_VERSION_301: - se_key_acc_ctrl(0xC, 0xFF); - se_key_acc_ctrl(0xD, 0xFF); - bootStateDramPkg2 = 2; - bootStatePkg2Continue = 3; - break; - default: - case KB_FIRMWARE_VERSION_400: - case KB_FIRMWARE_VERSION_500: - se_key_acc_ctrl(0xC, 0xFF); - se_key_acc_ctrl(0xF, 0xFF); - bootStateDramPkg2 = 2; - bootStatePkg2Continue = 4; - break; + switch (ctxt.pkg1_id->kb) + { + case KB_FIRMWARE_VERSION_100_200: + case KB_FIRMWARE_VERSION_300: + case KB_FIRMWARE_VERSION_301: + se_key_acc_ctrl(0xC, 0xFF); + se_key_acc_ctrl(0xD, 0xFF); + bootStateDramPkg2 = 2; + bootStatePkg2Continue = 3; + break; + default: + case KB_FIRMWARE_VERSION_400: + case KB_FIRMWARE_VERSION_500: + se_key_acc_ctrl(0xC, 0xFF); + se_key_acc_ctrl(0xF, 0xFF); + bootStateDramPkg2 = 2; + bootStatePkg2Continue = 4; + break; } //TODO: Don't Clear 'BootConfig' for retail >1.0.0. memset((void *)0x4003D000, 0, 0x3000); - //pkg2_decrypt((void *)0xA9800000); - //sleep(10000); - //btn_wait(); - //return 0; - //Lock SE before starting 'SecureMonitor'. _se_lock(); diff --git a/ipl/main.c b/ipl/main.c index c0966f8..c2d478b 100755 --- a/ipl/main.c +++ b/ipl/main.c @@ -268,7 +268,6 @@ void config_se_brom() // Clear the boot reason to avoid problems later PMC(APBDEV_PMC_SCRATCH200) = 0x0; PMC(APBDEV_PMC_RST_STATUS_0) = 0x0; - PMC(APBDEV_PMC_SCRATCH49_0) = 0x0; } void config_hw() diff --git a/ipl/sdram_lp0.c b/ipl/sdram_lp0.c index 7417eec..785231c 100755 --- a/ipl/sdram_lp0.c +++ b/ipl/sdram_lp0.c @@ -45,6 +45,7 @@ void sdram_lp0_save_params(const void *params) #define c32(value, pmcreg) pmc->pmcreg = value //TODO: pkg1.1 reads them from MC. + //Patch carveout parameters. sdram->McGeneralizedCarveout1Bom = 0; sdram->McGeneralizedCarveout1BomHi = 0; sdram->McGeneralizedCarveout1Size128kb = 0; @@ -116,6 +117,19 @@ void sdram_lp0_save_params(const void *params) sdram->McGeneralizedCarveout5ForceInternalAccess4 = 0; sdram->McGeneralizedCarveout5Cfg0 = 0x8F; + //Patch SDRAM parameters. + u32 t0 = sdram->EmcSwizzleRank0Byte0 << 5 >> 29 > sdram->EmcSwizzleRank0Byte0 << 1 >> 29; + u32 t1 = (t0 & 0xFFFFFFEF) | ((sdram->EmcSwizzleRank1Byte0 << 5 >> 29 > sdram->EmcSwizzleRank1Byte0 << 1 >> 29) << 4); + u32 t2 = (t1 & 0xFFFFFFFD) | ((sdram->EmcSwizzleRank0Byte1 << 5 >> 29 > sdram->EmcSwizzleRank0Byte1 << 1 >> 29) << 1); + u32 t3 = (t2 & 0xFFFFFFDF) | ((sdram->EmcSwizzleRank1Byte1 << 5 >> 29 > sdram->EmcSwizzleRank1Byte1 << 1 >> 29) << 5); + u32 t4 = (t3 & 0xFFFFFFFB) | ((sdram->EmcSwizzleRank0Byte2 << 5 >> 29 > sdram->EmcSwizzleRank0Byte2 << 1 >> 29) << 2); + u32 t5 = (t4 & 0xFFFFFFBF) | ((sdram->EmcSwizzleRank1Byte2 << 5 >> 29 > sdram->EmcSwizzleRank1Byte2 << 1 >> 29) << 6); + u32 t6 = (t5 & 0xFFFFFFF7) | ((sdram->EmcSwizzleRank0Byte3 << 5 >> 29 > sdram->EmcSwizzleRank0Byte3 << 1 >> 29) << 3); + u32 t7 = (t6 & 0xFFFFFF7F) | ((sdram->EmcSwizzleRank1Byte3 << 5 >> 29 > sdram->EmcSwizzleRank1Byte3 << 1 >> 29) << 7); + sdram->SwizzleRankByteEncode = t7; + sdram->EmcBctSpare2 = 0x40000DD8; + sdram->EmcBctSpare3 = t7; + s(EmcClockSource, 7:0, scratch6, 15:8); s(EmcClockSourceDll, 7:0, scratch6, 23:16); s(EmcClockSource, 31:29, scratch6, 26:24); @@ -786,9 +800,8 @@ void sdram_lp0_save_params(const void *params) s32(EmcBctSpare6, scratch40); s32(EmcBctSpare5, scratch42); s32(EmcBctSpare4, scratch44); - s32(SwizzleRankByteEncode, scratch45); - //s32(EmcBctSpare2, scratch46); - pmc->scratch46 = 0x40000DD8; + s32(EmcBctSpare3, scratch45); + s32(EmcBctSpare2, scratch46); s32(EmcBctSpare1, scratch47); s32(EmcBctSpare0, scratch48); s32(EmcBctSpare9, scratch50);