diff --git a/Makefile b/Makefile index 2fa70b3..2ff7e0f 100755 --- a/Makefile +++ b/Makefile @@ -30,6 +30,7 @@ OBJS = $(addprefix $(BUILD)/$(TARGET)/, \ hos.o \ hos_config.o \ secmon_exo.o \ + sept.o \ i2c.o \ kfuse.o \ bq24193.o \ diff --git a/README.md b/README.md index 6a53ab8..1a95d3f 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,7 @@ Hekate now has a new storage in the binary that helps it configure it outside of | Offset / Name | Description | | -------------------- | ----------------------------------------------------------------- | -| '0x94' boot_cfg | bit0: Force AutoBoot, bit1: Show launch log. | +| '0x94' boot_cfg | bit0: Force AutoBoot, bit1: Show launch log, bit2: sept run. | | '0x98' autoboot | If `Force AutoBoot`: 0: Force go to menu, else boot that entry. | | '0x9C' autoboot_list | If `Force AutoBoot` and `autoboot` then it boots from ini folder. | | '0xA0' rsvd_cfg | Reserved. | diff --git a/bootloader/frontend/fe_tools.c b/bootloader/frontend/fe_tools.c index 857e455..8e3c7c5 100644 --- a/bootloader/frontend/fe_tools.c +++ b/bootloader/frontend/fe_tools.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (c) 2018 CTCaer + * Copyright (c) 2018-2019 CTCaer * Copyright (c) 2018 Reisyukaku * * This program is free software; you can redistribute it and/or modify it @@ -26,6 +26,7 @@ #include "../hos/hos.h" #include "../hos/pkg1.h" #include "../hos/pkg2.h" +#include "../hos/sept.h" #include "../libs/fatfs/ff.h" #include "../mem/heap.h" #include "../power/max7762x.h" @@ -35,6 +36,7 @@ #include "../utils/btn.h" #include "../utils/util.h" +extern boot_cfg_t *b_cfg; extern hekate_config h_cfg; extern gfx_ctxt_t gfx_ctxt; @@ -96,6 +98,21 @@ void dump_packages12() tsec_ctxt.pkg11_off = pkg1_id->pkg11_off; tsec_ctxt.secmon_base = pkg1_id->secmon_base; + if (kb >= KB_FIRMWARE_VERSION_700 && !h_cfg.sept_run) + { + b_cfg->autoboot = 0; + b_cfg->autoboot_list = 0; + + gfx_printf(&gfx_con, "sept will run to get the keys.\nThen rerun this option."); + btn_wait(); + + if (!reboot_to_sept((u8 *)tsec_ctxt.fw)) + { + gfx_printf(&gfx_con, "Failed to run sept\n"); + goto out_free; + } + } + // Read keyblob. u8 *keyblob = (u8 *)calloc(NX_EMMC_BLOCKSIZE, 1); sdmmc_storage_read(&storage, 0x180000 / NX_EMMC_BLOCKSIZE + kb, 1, keyblob); diff --git a/bootloader/gfx/di.c b/bootloader/gfx/di.c index f82ee9a..fd02d25 100644 --- a/bootloader/gfx/di.c +++ b/bootloader/gfx/di.c @@ -1,6 +1,6 @@ /* * Copyright (c) 2018 naehrwert - * Copyright (C) 2018 CTCaer + * Copyright (c) 2018 CTCaer * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, diff --git a/bootloader/hos/hos.c b/bootloader/hos/hos.c index e6c4686..ced1f97 100644 --- a/bootloader/hos/hos.c +++ b/bootloader/hos/hos.c @@ -22,6 +22,7 @@ #include "hos.h" #include "hos_config.h" +#include "sept.h" #include "secmon_exo.h" #include "../config/config.h" #include "../gfx/di.h" @@ -43,6 +44,7 @@ extern gfx_ctxt_t gfx_ctxt; extern gfx_con_t gfx_con; +extern boot_cfg_t *b_cfg; extern hekate_config h_cfg; extern void sd_unmount(); @@ -416,6 +418,12 @@ int hos_launch(ini_sec_t *cfg) tsec_ctxt.pkg11_off = ctxt.pkg1_id->pkg11_off; tsec_ctxt.secmon_base = ctxt.pkg1_id->secmon_base; + if (ctxt.pkg1_id->kb >= KB_FIRMWARE_VERSION_700 && !h_cfg.sept_run) + { + gfx_printf(&gfx_con, "Failed to run sept\n"); + return 0; + } + if (!keygen(ctxt.keyblob, ctxt.pkg1_id->kb, &tsec_ctxt)) return 0; DPRINTF("Generated keys\n"); @@ -637,6 +645,9 @@ int hos_launch(ini_sec_t *cfg) // Disable display. This must be executed before secmon to provide support for all fw versions. display_end(); + // Clear EMC_SCRATCH0. + EMC(EMC_SCRATCH0) = 0; + // Wait for secmon to get ready. if (smmu_is_used()) smmu_exit(); diff --git a/bootloader/hos/sept.c b/bootloader/hos/sept.c new file mode 100644 index 0000000..ced797c --- /dev/null +++ b/bootloader/hos/sept.c @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include "hos.h" +#include "sept.h" +#include "../config/config.h" +#include "../gfx/di.h" +#include "../ianos/ianos.h" +#include "../libs/fatfs/ff.h" +#include "../mem/heap.h" +#include "../soc/pmc.h" +#include "../soc/t210.h" +#include "../storage/nx_emmc.h" +#include "../storage/sdmmc.h" +#include "../utils/btn.h" +#include "../utils/types.h" + +#include "../gfx/gfx.h" +extern gfx_con_t gfx_con; +#define EPRINTF(text) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFF0000, 0xFFCCCCCC) +#define EPRINTFARGS(text, args...) gfx_printf(&gfx_con, "%k"text"%k\n", 0xFFFF0000, args, 0xFFCCCCCC) + +#define PATCHED_RELOC_SZ 0x94 + +#define WB_RST_ADDR 0x40010ED0 +#define WB_RST_SIZE 0x30 + +u8 warmboot_reboot[] = { + 0x14, 0x00, 0x9F, 0xE5, // LDR R0, =0x7000E450 + 0x01, 0x10, 0xB0, 0xE3, // MOVS R1, #1 + 0x00, 0x10, 0x80, 0xE5, // STR R1, [R0] + 0x0C, 0x00, 0x9F, 0xE5, // LDR R0, =0x7000E400 + 0x10, 0x10, 0xB0, 0xE3, // MOVS R1, #0x10 + 0x00, 0x10, 0x80, 0xE5, // STR R1, [R0] + 0xFE, 0xFF, 0xFF, 0xEA, // LOOP + 0x50, 0xE4, 0x00, 0x70, // #0x7000E450 + 0x00, 0xE4, 0x00, 0x70 // #0x7000E400 +}; + +#define SEPT_PRI_ADDR 0x4003F000 + +#define SEPT_PK1T_ADDR 0xC0400000 +#define SEPT_PK1T_STACK 0x40008000 +#define SEPT_TCSZ_ADDR (SEPT_PK1T_ADDR - 0x4) +#define SEPT_STG1_ADDR (SEPT_PK1T_ADDR + 0x2E100) +#define SEPT_STG2_ADDR (SEPT_PK1T_ADDR + 0x60E0) +#define SEPT_PKG_SZ (0x2F100 + WB_RST_SIZE) + +extern boot_cfg_t *b_cfg; +extern hekate_config h_cfg; +extern void *sd_file_read(char *path); +extern void sd_mount(); +extern void sd_unmount(); +extern void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size); + +void check_sept() +{ + u8 *pkg1 = (u8 *)calloc(1, 0x40000); + + sdmmc_storage_t storage; + sdmmc_t sdmmc; + if (!sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_4, SDMMC_BUS_WIDTH_8, 4)) + { + EPRINTF("Failed to init eMMC."); + goto out_free; + } + sdmmc_storage_set_mmc_partition(&storage, 1); + + // Read package1. + sdmmc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, pkg1); + const pkg1_id_t *pkg1_id = pkg1_identify(pkg1); + if (!pkg1_id) + { + gfx_con.fntsz = 16; + EPRINTF("Unknown pkg1 version."); + goto out_free; + } + + if (pkg1_id->kb >= KB_FIRMWARE_VERSION_700 && !h_cfg.sept_run) + { + sdmmc_storage_end(&storage); + reboot_to_sept((u8 *)pkg1 + pkg1_id->tsec_off); + } + +out_free: + free(pkg1); + sdmmc_storage_end(&storage); +} + +int reboot_to_sept(const u8 *tsec_fw) +{ + FIL fp; + + // Copy warmboot reboot code and TSEC fw. + memcpy((u8 *)(SEPT_PK1T_ADDR - WB_RST_SIZE), (u8 *)warmboot_reboot, sizeof(warmboot_reboot)); + memcpy((void *)SEPT_PK1T_ADDR, tsec_fw, 0x3000); + *(vu32 *)SEPT_TCSZ_ADDR = 0x3000; + + // Copy sept-primary. + if (f_open(&fp, "sept/sept-primary.bin", FA_READ)) + goto error; + + if (f_read(&fp, (u8 *)SEPT_STG1_ADDR, f_size(&fp), NULL)) + { + f_close(&fp); + goto error; + } + f_close(&fp); + + // Copy sept-secondary. + if (f_open(&fp, "sept/sept-secondary.enc", FA_READ)) + goto error; + + if (f_read(&fp, (u8 *)SEPT_STG2_ADDR, f_size(&fp), NULL)) + { + f_close(&fp); + goto error; + } + f_close(&fp); + + // Save auto boot config to payload, if any. + boot_cfg_t *tmp_cfg = malloc(sizeof(boot_cfg_t)); + memcpy(tmp_cfg, b_cfg, sizeof(boot_cfg_t)); + + tmp_cfg->boot_cfg |= (BOOT_CFG_AUTOBOOT_EN | BOOT_CFG_SEPT_RUN); + + if (f_open(&fp, "sept/payload.bin", FA_READ | FA_WRITE)) + goto error; + + u32 magic; + f_lseek(&fp, f_size(&fp) - 6); + f_read(&fp, &magic, 4, NULL); + if (magic == 0x43544349) + { + f_lseek(&fp, PATCHED_RELOC_SZ); + f_write(&fp, tmp_cfg, sizeof(boot_cfg_t), NULL); + } + + f_close(&fp); + + sd_unmount(); + + u32 pk1t_sept = SEPT_PK1T_ADDR - (ALIGN(PATCHED_RELOC_SZ, 0x10) + WB_RST_SIZE); + + void (*sept)() = (void *)pk1t_sept; + + reloc_patcher(WB_RST_ADDR, pk1t_sept, SEPT_PKG_SZ); + + // Patch SDRAM init to perform an SVC immediately after second write. + PMC(APBDEV_PMC_SCRATCH45) = 0x2E38DFFF; + PMC(APBDEV_PMC_SCRATCH46) = 0x6001DC28; + // Set SVC handler to jump to sept-primary in IRAM. + PMC(APBDEV_PMC_SCRATCH33) = SEPT_PRI_ADDR; + PMC(APBDEV_PMC_SCRATCH40) = 0x6000F208; + + display_end(); + + (*sept)(); + + return 1; + +error: + EPRINTF("Failed to run sept\n"); + display_backlight_brightness(h_cfg.backlight, 1000); + + btn_wait(); + + return 0; +} \ No newline at end of file diff --git a/bootloader/hos/sept.h b/bootloader/hos/sept.h new file mode 100644 index 0000000..5b0ecb4 --- /dev/null +++ b/bootloader/hos/sept.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2019 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _SEPT_H_ +#define _SEPT_H_ + +#include "../utils/types.h" + +void check_sept(); +int reboot_to_sept(const u8 *tsec_fw); + +#endif diff --git a/bootloader/main.c b/bootloader/main.c index 6c739fa..86edfd9 100644 --- a/bootloader/main.c +++ b/bootloader/main.c @@ -25,6 +25,7 @@ #include "gfx/logos.h" #include "gfx/tui.h" #include "hos/hos.h" +#include "hos/sept.h" #include "ianos/ianos.h" #include "libs/compr/blz.h" #include "libs/fatfs/ff.h" @@ -270,7 +271,7 @@ void check_power_off_from_hos() } // This is a safe and unused DRAM region for our payloads. -#define IPL_LOAD_ADDR 0x40008000 +// IPL_LOAD_ADDR is defined in makefile. #define EXT_PAYLOAD_ADDR 0xC03C0000 #define PATCHED_RELOC_SZ 0x94 #define RCM_PAYLOAD_ADDR (EXT_PAYLOAD_ADDR + ALIGN(PATCHED_RELOC_SZ, 0x10)) @@ -281,21 +282,23 @@ void check_power_off_from_hos() void (*ext_payload_ptr)() = (void *)EXT_PAYLOAD_ADDR; void (*update_ptr)() = (void *)RCM_PAYLOAD_ADDR; -void reloc_patcher(u32 payload_size) +void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size) { static const u32 START_OFF = 0x7C; + static const u32 STACK_OFF = 0x80; static const u32 PAYLOAD_END_OFF = 0x84; static const u32 IPL_START_OFF = 0x88; - memcpy((u8 *)EXT_PAYLOAD_ADDR, (u8 *)IPL_LOAD_ADDR, PATCHED_RELOC_SZ); + memcpy((u8 *)payload_src, (u8 *)IPL_LOAD_ADDR, PATCHED_RELOC_SZ); - *(vu32 *)(EXT_PAYLOAD_ADDR + START_OFF) = PAYLOAD_ENTRY - ALIGN(PATCHED_RELOC_SZ, 0x10); - *(vu32 *)(EXT_PAYLOAD_ADDR + PAYLOAD_END_OFF) = PAYLOAD_ENTRY + payload_size; - *(vu32 *)(EXT_PAYLOAD_ADDR + IPL_START_OFF) = PAYLOAD_ENTRY; + *(vu32 *)(payload_src + START_OFF) = payload_dst - ALIGN(PATCHED_RELOC_SZ, 0x10); + *(vu32 *)(payload_src + PAYLOAD_END_OFF) = payload_dst + payload_size; + *(vu32 *)(payload_src + STACK_OFF) = 0x40008000; + *(vu32 *)(payload_src + IPL_START_OFF) = payload_dst; if (payload_size == 0x7000) { - memcpy((u8 *)(EXT_PAYLOAD_ADDR + ALIGN(PATCHED_RELOC_SZ, 0x10)), (u8 *)COREBOOT_ADDR, 0x7000); //Bootblock + memcpy((u8 *)(payload_src + ALIGN(PATCHED_RELOC_SZ, 0x10)), (u8 *)COREBOOT_ADDR, 0x7000); //Bootblock *(vu32 *)CBFS_SDRAM_EN_ADDR = 0x4452414D; } } @@ -370,14 +373,15 @@ int launch_payload(char *path, bool update) if (size < 0x30000) { if (!update) - reloc_patcher(ALIGN(size, 0x10)); + reloc_patcher(PAYLOAD_ENTRY, EXT_PAYLOAD_ADDR, ALIGN(size, 0x10)); else memcpy((u8 *)(RCM_PAYLOAD_ADDR + PATCHED_RELOC_SZ), (u8 *)(IPL_LOAD_ADDR + PATCHED_RELOC_SZ), sizeof(boot_cfg_t)); + reconfig_hw_workaround(false, byte_swap_32(*(u32 *)(buf + size - sizeof(u32)))); } else { - reloc_patcher(0x7000); + reloc_patcher(PAYLOAD_ENTRY, EXT_PAYLOAD_ADDR, 0x7000); if (*(vu32 *)CBFS_SDRAM_EN_ADDR != 0x4452414D) return 1; reconfig_hw_workaround(true, 0); @@ -591,6 +595,11 @@ void ini_list_launcher() } } + payload_path = ini_check_payload_section(cfg_tmp); + + if (cfg_tmp && !payload_path) + check_sept(); + cfg_sec = ini_clone_section(cfg_tmp); if (!cfg_sec) @@ -617,8 +626,6 @@ void ini_list_launcher() free(Kc_MENU_LOGO); #endif //MENU_LOGO_ENABLE - payload_path = ini_check_payload_section(cfg_sec); - if (payload_path) { ini_free_section(cfg_sec); @@ -724,6 +731,10 @@ void launch_firmware() } } + payload_path = ini_check_payload_section(cfg_tmp); + + if (cfg_tmp && !payload_path) + check_sept(); cfg_sec = ini_clone_section(cfg_tmp); if (!cfg_sec) @@ -754,8 +765,6 @@ void launch_firmware() free(Kc_MENU_LOGO); #endif //MENU_LOGO_ENABLE - payload_path = ini_check_payload_section(cfg_sec); - if (payload_path) { ini_free_section(cfg_sec); @@ -934,6 +943,11 @@ void auto_launch_firmware() else goto out; + payload_path = ini_check_payload_section(cfg_sec); + + if (!payload_path) + check_sept(); + u8 *bitmap = NULL; if (!(b_cfg->boot_cfg & BOOT_CFG_FROM_LAUNCH)) { @@ -1022,8 +1036,6 @@ void auto_launch_firmware() goto out; } - payload_path = ini_check_payload_section(cfg_sec); - if (payload_path) { ini_free_section(cfg_sec); diff --git a/bootloader/soc/hw_init.c b/bootloader/soc/hw_init.c index 3ad889c..3c598de 100644 --- a/bootloader/soc/hw_init.c +++ b/bootloader/soc/hw_init.c @@ -37,6 +37,7 @@ #include "../utils/util.h" extern sdmmc_t sd_sdmmc; +extern boot_cfg_t *b_cfg; void _config_oscillators() { @@ -145,27 +146,31 @@ void _mbist_workaround() void _config_se_brom() { - // Bootrom part we skipped. - u32 sbk[4] = { - FUSE(FUSE_PRIVATE_KEY0), - FUSE(FUSE_PRIVATE_KEY1), - FUSE(FUSE_PRIVATE_KEY2), - FUSE(FUSE_PRIVATE_KEY3) - }; - // Set SBK to slot 14. - se_aes_key_set(14, sbk, 0x10); + // Skip SBK/SSK if sept was run. + if (!(b_cfg->boot_cfg & BOOT_CFG_SEPT_RUN)) + { + // Bootrom part we skipped. + u32 sbk[4] = { + FUSE(FUSE_PRIVATE_KEY0), + FUSE(FUSE_PRIVATE_KEY1), + FUSE(FUSE_PRIVATE_KEY2), + FUSE(FUSE_PRIVATE_KEY3) + }; + // Set SBK to slot 14. + se_aes_key_set(14, sbk, 0x10); - // Lock SBK from being read. - SE(SE_KEY_TABLE_ACCESS_REG_OFFSET + 14 * 4) = 0x7E; + // Lock SBK from being read. + SE(SE_KEY_TABLE_ACCESS_REG_OFFSET + 14 * 4) = 0x7E; + + // Lock SSK (although it's not set and unused anyways). + SE(SE_KEY_TABLE_ACCESS_REG_OFFSET + 15 * 4) = 0x7E; + } // This memset needs to happen here, else TZRAM will behave weirdly later on. memset((void *)TZRAM_BASE, 0, 0x10000); PMC(APBDEV_PMC_CRYPTO_OP) = 0; SE(SE_INT_STATUS_REG_OFFSET) = 0x1F; - // Lock SSK (although it's not set and unused anyways). - SE(SE_KEY_TABLE_ACCESS_REG_OFFSET + 15 * 4) = 0x7E; - // Clear the boot reason to avoid problems later PMC(APBDEV_PMC_SCRATCH200) = 0x0; PMC(APBDEV_PMC_RST_STATUS) = 0x0; diff --git a/bootloader/utils/types.h b/bootloader/utils/types.h index ca8dc09..78e3497 100644 --- a/bootloader/utils/types.h +++ b/bootloader/utils/types.h @@ -53,6 +53,7 @@ typedef int bool; #define BOOT_CFG_AUTOBOOT_EN (1 << 0) #define BOOT_CFG_FROM_LAUNCH (1 << 1) +#define BOOT_CFG_SEPT_RUN (1 << 7) typedef struct __attribute__((__packed__)) _boot_cfg_t {