Refactored the firmware loader and LP0 config.

This commit is contained in:
nwert 2018-06-08 23:07:25 +12:00
parent 120e8f5870
commit 24e172b5fb
3 changed files with 140 additions and 145 deletions

265
ipl/hos.c
View file

@ -38,14 +38,41 @@ extern gfx_con_t gfx_con;
//#define DPRINTF(...) gfx_printf(&gfx_con, __VA_ARGS__) //#define DPRINTF(...) gfx_printf(&gfx_con, __VA_ARGS__)
#define DPRINTF(...) #define DPRINTF(...)
enum KB_FIRMWARE_VERSION { typedef struct _launch_ctxt_t
KB_FIRMWARE_VERSION_100_200 = 0, {
KB_FIRMWARE_VERSION_300 = 1, void *keyblob;
KB_FIRMWARE_VERSION_301 = 2,
KB_FIRMWARE_VERSION_400 = 3, void *pkg1;
KB_FIRMWARE_VERSION_500 = 4, const pkg1_id_t *pkg1_id;
KB_FIRMWARE_VERSION_MAX 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 #define NUM_KEYBLOB_KEYS 5
static const u8 keyblob_keyseeds[NUM_KEYBLOB_KEYS][0x10] = { 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] = static const u8 console_keyseed_4xx[0x10] =
{ 0x0C, 0x91, 0x09, 0xDB, 0x93, 0x93, 0x07, 0x81, 0x07, 0x3C, 0xC4, 0x16, 0x22, 0x7C, 0x6C, 0x28 }; { 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) u32 crc32c(const u8 *buf, u32 len)
{ {
int i; u32 crc = 0xFFFFFFFF;
u32 crc = 0; while (len--)
{
crc = ~crc; crc ^= *buf++;
while (len--) { for (int i = 0; i < 8; i++)
crc ^= *buf++; crc = crc & 1 ? (crc >> 1) ^ CRC32C_POLY : crc >> 1;
for (i = 0; i < 8; i++) }
crc = crc & 1 ? (crc >> 1) ^ CRC32C_POLY : crc >> 1; return ~crc;
}
return ~crc;
} }
static void _se_lock() static void _se_lock()
@ -117,7 +141,6 @@ static void _se_lock()
gfx_hexdump(&gfx_con, SE_BASE, (void *)SE_BASE, 0x400);*/ gfx_hexdump(&gfx_con, SE_BASE, (void *)SE_BASE, 0x400);*/
} }
// <-- key derivation algorithm
int keygen(u8 *keyblob, u32 kb, void *tsec_fw) int keygen(u8 *keyblob, u32 kb, void *tsec_fw)
{ {
u8 tmp[0x10]; 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); 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_100_200:
case KB_FIRMWARE_VERSION_300: case KB_FIRMWARE_VERSION_300:
case KB_FIRMWARE_VERSION_301: case KB_FIRMWARE_VERSION_301:
@ -181,44 +205,13 @@ int keygen(u8 *keyblob, u32 kb, void *tsec_fw)
break; break;
} }
// Package2 key //Package2 key.
se_key_acc_ctrl(0x08, 0x15); se_key_acc_ctrl(0x08, 0x15);
se_aes_unwrap_key(0x08, 0x0C, key8_keyseed); se_aes_unwrap_key(0x08, 0x0C, key8_keyseed);
return 1; 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) static int _read_emmc_pkg1(launch_ctxt_t *ctxt)
{ {
int res = 0; 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) static int _config_svcperm(launch_ctxt_t *ctxt, const char *value)
{ {
if (*(u8 *)value == '1') if (*value == '1')
{ {
DPRINTF("Disabled SVC verification\n"); DPRINTF("Disabled SVC verification\n");
ctxt->svcperm = 1; ctxt->svcperm = 1;
} }
return 1; return 1;
} }
static int _config_debugmode(launch_ctxt_t *ctxt, const char *value) static int _config_debugmode(launch_ctxt_t *ctxt, const char *value)
{ {
if (*(u8 *)value == '1') if (*value == '1')
{ {
DPRINTF("Enabled Debug mode\n"); DPRINTF("Enabled Debug mode\n");
ctxt->debugmode = 1; ctxt->debugmode = 1;
} }
return 1; return 1;
} }
@ -395,15 +386,17 @@ int hos_launch(ini_sec_t *cfg)
int bootStateDramPkg2; int bootStateDramPkg2;
int bootStatePkg2Continue; int bootStatePkg2Continue;
launch_ctxt_t ctxt; launch_ctxt_t ctxt;
memset(&ctxt, 0, sizeof(launch_ctxt_t)); memset(&ctxt, 0, sizeof(launch_ctxt_t));
list_init(&ctxt.kip1_list); list_init(&ctxt.kip1_list);
gfx_clear_grey(&gfx_ctxt, 0x1B); gfx_clear_grey(&gfx_ctxt, 0x1B);
gfx_con_setpos(&gfx_con, 0, 0); gfx_con_setpos(&gfx_con, 0, 0);
//Try to parse config if present.
if (cfg && !_config(&ctxt, cfg)) if (cfg && !_config(&ctxt, cfg))
return 0; return 0;
gfx_printf(&gfx_con, "Initializing...\n\n"); gfx_printf(&gfx_con, "Initializing...\n\n");
//Read package1 and the correct keyblob. //Read package1 and the correct keyblob.
@ -411,9 +404,11 @@ int hos_launch(ini_sec_t *cfg)
return 0; return 0;
gfx_printf(&gfx_con, "Loaded package1 and keyblob\n"); gfx_printf(&gfx_con, "Loaded package1 and keyblob\n");
//Generate keys. //Generate keys.
keygen(ctxt.keyblob, ctxt.pkg1_id->kb, (u8 *)ctxt.pkg1 + ctxt.pkg1_id->tsec_off); keygen(ctxt.keyblob, ctxt.pkg1_id->kb, (u8 *)ctxt.pkg1 + ctxt.pkg1_id->tsec_off);
DPRINTF("Generated keys\n"); DPRINTF("Generated keys\n");
//Decrypt and unpack package1 if we require parts of it. //Decrypt and unpack package1 if we require parts of it.
if (!ctxt.warmboot || !ctxt.secmon) 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); 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"); gfx_printf(&gfx_con, "Decrypted and unpacked package1\n");
} }
//Replace 'warmboot.bin' if requested. //Replace 'warmboot.bin' if requested.
if (ctxt.warmboot) if (ctxt.warmboot)
memcpy((void *)ctxt.pkg1_id->warmboot_base, ctxt.warmboot, ctxt.warmboot_size); memcpy((void *)ctxt.pkg1_id->warmboot_base, ctxt.warmboot, ctxt.warmboot_size);
//Set warmboot address in PMC if required. //Set warmboot address in PMC if required.
if (ctxt.pkg1_id->set_warmboot) if (ctxt.pkg1_id->set_warmboot)
PMC(APBDEV_PMC_SCRATCH1) = 0x8000D000; PMC(APBDEV_PMC_SCRATCH1) = 0x8000D000;
//Replace 'SecureMonitor' if requested. //Replace 'SecureMonitor' if requested.
if (ctxt.secmon) { if (ctxt.secmon)
memcpy((void *)ctxt.pkg1_id->secmon_base, ctxt.secmon, ctxt.secmon_size); memcpy((void *)ctxt.pkg1_id->secmon_base, ctxt.secmon, ctxt.secmon_size);
}
else else
{ {
//Else we patch it to allow for an unsigned package2 and patched kernel. //Else we patch it to allow for an unsigned package2 and patched kernel.
patch_t *secmon_patchset = ctxt.pkg1_id->secmon_patchset; 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); u32 kernel_crc32 = crc32c((u8 *)ctxt.kernel, ctxt.kernel_size);
for (u32 i = 0; secmon_patchset[i].off != 0xFFFFFFFF; i++) ctxt.pkg2_kernel_id = pkg2_identify(kernel_crc32);
*(vu32 *)(ctxt.pkg1_id->secmon_base + secmon_patchset[i].off) = secmon_patchset[i].val;
gfx_printf(&gfx_con, "Loaded warmboot.bin and secmon\n"); //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;
//Read package2. if (kernel_patchset != NULL)
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; gfx_printf(&gfx_con, "%kPatching kernel%k\n", 0xFF00BAFF, 0xFFCCCCCC);
ctxt.kernel_size = pkg2_hdr->sec_size[PKG2_SEC_KERNEL]; //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)
if (ctxt.svcperm || ctxt.debugmode) *(vu32 *)(ctxt.kernel + kernel_patchset[0].off) = kernel_patchset[0].val;
{ if (ctxt.debugmode && kernel_patchset[1].off != 0xFFFFFFFF)
u32 kernel_crc32 = crc32c((u8 *)ctxt.kernel, ctxt.kernel_size); *(vu32 *)(ctxt.kernel + kernel_patchset[1].off) = kernel_patchset[1].val;
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;
}
}
} }
//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); f_mount(NULL, "", 1);
gfx_printf(&gfx_con, "\n%kBooting...%k\n", 0xFF00FF96, 0xFFCCCCCC); 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(0x8);
se_aes_key_clear(0xB); se_aes_key_clear(0xB);
switch (ctxt.pkg1_id->kb) { switch (ctxt.pkg1_id->kb)
case KB_FIRMWARE_VERSION_100_200: {
case KB_FIRMWARE_VERSION_300: case KB_FIRMWARE_VERSION_100_200:
case KB_FIRMWARE_VERSION_301: case KB_FIRMWARE_VERSION_300:
se_key_acc_ctrl(0xC, 0xFF); case KB_FIRMWARE_VERSION_301:
se_key_acc_ctrl(0xD, 0xFF); se_key_acc_ctrl(0xC, 0xFF);
bootStateDramPkg2 = 2; se_key_acc_ctrl(0xD, 0xFF);
bootStatePkg2Continue = 3; bootStateDramPkg2 = 2;
break; bootStatePkg2Continue = 3;
default: break;
case KB_FIRMWARE_VERSION_400: default:
case KB_FIRMWARE_VERSION_500: case KB_FIRMWARE_VERSION_400:
se_key_acc_ctrl(0xC, 0xFF); case KB_FIRMWARE_VERSION_500:
se_key_acc_ctrl(0xF, 0xFF); se_key_acc_ctrl(0xC, 0xFF);
bootStateDramPkg2 = 2; se_key_acc_ctrl(0xF, 0xFF);
bootStatePkg2Continue = 4; bootStateDramPkg2 = 2;
break; bootStatePkg2Continue = 4;
break;
} }
//TODO: Don't Clear 'BootConfig' for retail >1.0.0. //TODO: Don't Clear 'BootConfig' for retail >1.0.0.
memset((void *)0x4003D000, 0, 0x3000); memset((void *)0x4003D000, 0, 0x3000);
//pkg2_decrypt((void *)0xA9800000);
//sleep(10000);
//btn_wait();
//return 0;
//Lock SE before starting 'SecureMonitor'. //Lock SE before starting 'SecureMonitor'.
_se_lock(); _se_lock();

View file

@ -268,7 +268,6 @@ void config_se_brom()
// Clear the boot reason to avoid problems later // Clear the boot reason to avoid problems later
PMC(APBDEV_PMC_SCRATCH200) = 0x0; PMC(APBDEV_PMC_SCRATCH200) = 0x0;
PMC(APBDEV_PMC_RST_STATUS_0) = 0x0; PMC(APBDEV_PMC_RST_STATUS_0) = 0x0;
PMC(APBDEV_PMC_SCRATCH49_0) = 0x0;
} }
void config_hw() void config_hw()

View file

@ -45,6 +45,7 @@ void sdram_lp0_save_params(const void *params)
#define c32(value, pmcreg) pmc->pmcreg = value #define c32(value, pmcreg) pmc->pmcreg = value
//TODO: pkg1.1 reads them from MC. //TODO: pkg1.1 reads them from MC.
//Patch carveout parameters.
sdram->McGeneralizedCarveout1Bom = 0; sdram->McGeneralizedCarveout1Bom = 0;
sdram->McGeneralizedCarveout1BomHi = 0; sdram->McGeneralizedCarveout1BomHi = 0;
sdram->McGeneralizedCarveout1Size128kb = 0; sdram->McGeneralizedCarveout1Size128kb = 0;
@ -116,6 +117,19 @@ void sdram_lp0_save_params(const void *params)
sdram->McGeneralizedCarveout5ForceInternalAccess4 = 0; sdram->McGeneralizedCarveout5ForceInternalAccess4 = 0;
sdram->McGeneralizedCarveout5Cfg0 = 0x8F; 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(EmcClockSource, 7:0, scratch6, 15:8);
s(EmcClockSourceDll, 7:0, scratch6, 23:16); s(EmcClockSourceDll, 7:0, scratch6, 23:16);
s(EmcClockSource, 31:29, scratch6, 26:24); s(EmcClockSource, 31:29, scratch6, 26:24);
@ -786,9 +800,8 @@ void sdram_lp0_save_params(const void *params)
s32(EmcBctSpare6, scratch40); s32(EmcBctSpare6, scratch40);
s32(EmcBctSpare5, scratch42); s32(EmcBctSpare5, scratch42);
s32(EmcBctSpare4, scratch44); s32(EmcBctSpare4, scratch44);
s32(SwizzleRankByteEncode, scratch45); s32(EmcBctSpare3, scratch45);
//s32(EmcBctSpare2, scratch46); s32(EmcBctSpare2, scratch46);
pmc->scratch46 = 0x40000DD8;
s32(EmcBctSpare1, scratch47); s32(EmcBctSpare1, scratch47);
s32(EmcBctSpare0, scratch48); s32(EmcBctSpare0, scratch48);
s32(EmcBctSpare9, scratch50); s32(EmcBctSpare9, scratch50);