diff --git a/common/include/atmosphere/target_fw.h b/common/include/atmosphere/target_fw.h index 03f689e94..8cbdb6112 100644 --- a/common/include/atmosphere/target_fw.h +++ b/common/include/atmosphere/target_fw.h @@ -24,11 +24,12 @@ #define ATMOSPHERE_TARGET_FIRMWARE_500 5 #define ATMOSPHERE_TARGET_FIRMWARE_600 6 #define ATMOSPHERE_TARGET_FIRMWARE_620 7 +#define ATMOSPHERE_TARGET_FIRMWARE_700 8 -#define ATMOSPHERE_TARGET_FIRMWARE_CURRENT ATMOSPHERE_TARGET_FIRMWARE_620 +#define ATMOSPHERE_TARGET_FIRMWARE_CURRENT ATMOSPHERE_TARGET_FIRMWARE_700 #define ATMOSPHERE_TARGET_FIRMWARE_MIN ATMOSPHERE_TARGET_FIRMWARE_100 -#define ATMOSPHERE_TARGET_FIRMWARE_MAX ATMOSPHERE_TARGET_FIRMWARE_620 +#define ATMOSPHERE_TARGET_FIRMWARE_MAX ATMOSPHERE_TARGET_FIRMWARE_700 /* TODO: What should this be, for release? */ #define ATMOSPHERE_TARGET_FIRMWARE_DEFAULT_FOR_DEBUG ATMOSPHERE_TARGET_FIRMWARE_CURRENT diff --git a/fusee/fusee-secondary/src/extkeys.c b/fusee/fusee-secondary/src/extkeys.c index 7315d4c5d..b64bdf232 100644 --- a/fusee/fusee-secondary/src/extkeys.c +++ b/fusee/fusee-secondary/src/extkeys.c @@ -197,18 +197,19 @@ void extkeys_initialize_keyset(fusee_extkeys_t *keyset, FILE *f) { continue; } int matched_key = 0; - if (strcmp(key, "tsec_root_key") == 0 || strcmp(key, "tsec_root_key_00") == 0) { - parse_hex_key(keyset->tsec_root_key, value, sizeof(keyset->tsec_root_key)); - matched_key = 1; - } else { - char test_name[0x100] = {0}; - for (unsigned int i = 0; i < 0x20 && !matched_key; i++) { - snprintf(test_name, sizeof(test_name), "master_kek_%02x", i); - if (strcmp(key, test_name) == 0) { - parse_hex_key(keyset->master_keks[i], value, sizeof(keyset->master_keks[i])); - matched_key = 1; - break; - } + char test_name[0x100] = {0}; + for (unsigned int i = 0; i < 0x20 && !matched_key; i++) { + snprintf(test_name, sizeof(test_name), "tsec_root_key_%02x", i); + if (strcmp(key, test_name) == 0) { + parse_hex_key(keyset->tsec_root_keys[i], value, sizeof(keyset->tsec_root_keys[i])); + matched_key = 1; + break; + } + snprintf(test_name, sizeof(test_name), "master_kek_%02x", i); + if (strcmp(key, test_name) == 0) { + parse_hex_key(keyset->master_keks[i], value, sizeof(keyset->master_keks[i])); + matched_key = 1; + break; } } } diff --git a/fusee/fusee-secondary/src/extkeys.h b/fusee/fusee-secondary/src/extkeys.h index 651868995..7a64aab9d 100644 --- a/fusee/fusee-secondary/src/extkeys.h +++ b/fusee/fusee-secondary/src/extkeys.h @@ -22,7 +22,7 @@ #include "masterkey.h" typedef struct { - unsigned char tsec_root_key[0x10]; + unsigned char tsec_root_keys[0x20][0x10]; unsigned char master_keks[0x20][0x10]; } fusee_extkeys_t; diff --git a/fusee/fusee-secondary/src/key_derivation.c b/fusee/fusee-secondary/src/key_derivation.c index 3b934f59c..05cb084e1 100644 --- a/fusee/fusee-secondary/src/key_derivation.c +++ b/fusee/fusee-secondary/src/key_derivation.c @@ -54,8 +54,9 @@ static const uint8_t AL16 masterkey_4x_seed[0x10] = { 0x2D, 0xC1, 0xF4, 0x8D, 0xF3, 0x5B, 0x69, 0x33, 0x42, 0x10, 0xAC, 0x65, 0xDA, 0x90, 0x46, 0x66 }; -static const uint8_t AL16 new_master_kek_seeds[1][0x10] = { +static const uint8_t AL16 new_master_kek_seeds[MASTERKEY_REVISION_700_CURRENT - MASTERKEY_REVISION_600_610][0x10] = { {0x37, 0x4B, 0x77, 0x29, 0x59, 0xB4, 0x04, 0x30, 0x81, 0xF6, 0xE5, 0x8C, 0x6D, 0x36, 0x17, 0x9A}, /* MasterKek seed 06. */ + {0x9A, 0x3E, 0xA9, 0xAB, 0xFD, 0x56, 0x46, 0x1C, 0x9B, 0xF6, 0x48, 0x7F, 0x5C, 0xFA, 0x09, 0x5C}, /* MasterKek seed 07. */ }; static nx_dec_keyblob_t AL16 g_dec_keyblobs[32]; @@ -118,7 +119,7 @@ int load_package1_key(uint32_t revision) { } /* Derive all Switch keys. */ -int derive_nx_keydata(uint32_t target_firmware, const nx_keyblob_t *keyblobs, uint32_t available_revision, const void *tsec_key, void *tsec_root_key, unsigned int *out_keygen_type) { +int derive_nx_keydata(uint32_t target_firmware, const nx_keyblob_t *keyblobs, uint32_t available_revision, const void *tsec_key, void *tsec_root_keys, unsigned int *out_keygen_type) { uint8_t AL16 work_buffer[0x10]; uint8_t AL16 zeroes[0x10] = {0}; @@ -142,14 +143,31 @@ int derive_nx_keydata(uint32_t target_firmware, const nx_keyblob_t *keyblobs, ui /* Do 6.2.0+ keygen. */ if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_620) { - if (memcmp(tsec_root_key, zeroes, 0x10) != 0) { - /* We got a valid key from emulation. */ - set_aes_keyslot(0xC, tsec_root_key, 0x10); - for (unsigned int rev = MASTERKEY_REVISION_620_CURRENT; rev < MASTERKEY_REVISION_MAX; rev++) { - se_aes_ecb_decrypt_block(0xC, work_buffer, 0x10, new_master_kek_seeds[rev - MASTERKEY_REVISION_620_CURRENT], 0x10); + uint32_t desired_keyblob; + switch (target_firmware) { + case ATMOSPHERE_TARGET_FIRMWARE_620: + desired_keyblob = MASTERKEY_REVISION_620; + break; + case ATMOSPHERE_TARGET_FIRMWARE_700: + desired_keyblob = MASTERKEY_REVISION_700_CURRENT; + break; + default: + fatal_error("Unknown target firmware: %02x!", target_firmware); + break; + } + + /* Try emulation result. */ + for (unsigned int rev = MASTERKEY_REVISION_620; rev < MASTERKEY_REVISION_MAX; rev++) { + void *tsec_root_key = (void *)((uintptr_t)tsec_root_keys + 0x10 * (rev - MASTERKEY_REVISION_620)); + if (memcmp(tsec_root_key, zeroes, 0x10) != 0) { + /* We got a valid key from emulation. */ + set_aes_keyslot(0xC, tsec_root_key, 0x10); + se_aes_ecb_decrypt_block(0xC, work_buffer, 0x10, new_master_kek_seeds[rev - MASTERKEY_REVISION_620], 0x10); memcpy(g_dec_keyblobs[rev].master_kek, work_buffer, 0x10); } - } else { + } + + if (memcmp(g_dec_keyblobs[desired_keyblob].master_kek, zeroes, 0x10) == 0) { /* Try reading the keys from a file. */ const char *keyfile = fuse_get_retail_type() != 0 ? "atmosphere/prod.keys" : "atmosphere/dev.keys"; FILE *extkey_file = fopen(keyfile, "r"); @@ -159,20 +177,18 @@ int derive_nx_keydata(uint32_t target_firmware, const nx_keyblob_t *keyblobs, ui } extkeys_initialize_keyset(&extkeys, extkey_file); fclose(extkey_file); - - if (memcmp(extkeys.tsec_root_key, zeroes, 0x10) != 0) { - set_aes_keyslot(0xC, extkeys.tsec_root_key, 0x10); - for (unsigned int rev = MASTERKEY_REVISION_620_CURRENT; rev < MASTERKEY_REVISION_MAX; rev++) { - se_aes_ecb_decrypt_block(0xC, work_buffer, 0x10, new_master_kek_seeds[rev - MASTERKEY_REVISION_620_CURRENT], 0x10); + for (unsigned int rev = MASTERKEY_REVISION_620; rev < MASTERKEY_REVISION_MAX; rev++) { + if (memcmp(extkeys.tsec_root_keys[rev - MASTERKEY_REVISION_620], zeroes, 0x10) != 0) { + set_aes_keyslot(0xC, extkeys.tsec_root_keys[rev - MASTERKEY_REVISION_620], 0x10); + se_aes_ecb_decrypt_block(0xC, work_buffer, 0x10, new_master_kek_seeds[rev - MASTERKEY_REVISION_620], 0x10); memcpy(g_dec_keyblobs[rev].master_kek, work_buffer, 0x10); - } - } else { - for (unsigned int rev = MASTERKEY_REVISION_620_CURRENT; rev < MASTERKEY_REVISION_MAX; rev++) { + } else { memcpy(g_dec_keyblobs[rev].master_kek, extkeys.master_keks[rev], 0x10); } } } + if (memcmp(g_dec_keyblobs[available_revision].master_kek, zeroes, 0x10) == 0) { fatal_error("Error: failed to derive master_kek_%02x!", available_revision); } diff --git a/fusee/fusee-secondary/src/masterkey.h b/fusee/fusee-secondary/src/masterkey.h index 0f1c20a0b..d116f5401 100644 --- a/fusee/fusee-secondary/src/masterkey.h +++ b/fusee/fusee-secondary/src/masterkey.h @@ -20,7 +20,7 @@ /* This is glue code to enable master key support across versions. */ /* TODO: Update to 0x8 on release of new master key. */ -#define MASTERKEY_REVISION_MAX 0x7 +#define MASTERKEY_REVISION_MAX 0x8 #define MASTERKEY_REVISION_100_230 0x00 #define MASTERKEY_REVISION_300 0x01 @@ -28,7 +28,8 @@ #define MASTERKEY_REVISION_400_410 0x03 #define MASTERKEY_REVISION_500_510 0x04 #define MASTERKEY_REVISION_600_610 0x05 -#define MASTERKEY_REVISION_620_CURRENT 0x06 +#define MASTERKEY_REVISION_620 0x06 +#define MASTERKEY_REVISION_700_CURRENT 0x07 #define MASTERKEY_NUM_NEW_DEVICE_KEYS (MASTERKEY_REVISION_MAX - MASTERKEY_REVISION_400_410) diff --git a/fusee/fusee-secondary/src/nxboot.c b/fusee/fusee-secondary/src/nxboot.c index 6a64c38c1..6693401ab 100644 --- a/fusee/fusee-secondary/src/nxboot.c +++ b/fusee/fusee-secondary/src/nxboot.c @@ -212,7 +212,7 @@ static void nxboot_configure_stratosphere(uint32_t target_firmware) { } } -static void nxboot_set_bootreason() { +static void nxboot_set_bootreason(void *bootreason_base) { boot_reason_t boot_reason = {0}; FILE *boot0; nvboot_config_table *bct; @@ -264,7 +264,7 @@ static void nxboot_set_bootreason() { boot_reason.boot_reason_state = 0x04; /* Set in memory. */ - memcpy((void *)MAILBOX_NX_BOOTLOADER_BOOT_REASON_BASE, &boot_reason, sizeof(boot_reason)); + memcpy(bootreason_base, &boot_reason, sizeof(boot_reason)); /* Clean up. */ free(bct); @@ -412,7 +412,12 @@ uint32_t nxboot_main(void) { /* Get the TSEC keys. */ uint8_t tsec_key[0x10] = {0}; uint8_t tsec_root_key[0x10] = {0}; - if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_620) { + if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_700) { + /* TODO: what to do here? */ + if (tsec_get_key(tsec_key, 1, tsec_fw, tsec_fw_size) != 0) { + fatal_error("[NXBOOT]: Failed to get TSEC key!\n"); + } + } else if (target_firmware == ATMOSPHERE_TARGET_FIRMWARE_620) { uint8_t tsec_keys[0x20] = {0}; /* Emulate the TSEC payload on 6.2.0+. */ @@ -438,9 +443,9 @@ uint32_t nxboot_main(void) { nxboot_configure_exosphere(target_firmware, keygen_type); /* Initialize Boot Reason on older firmware versions. */ - if (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware < ATMOSPHERE_TARGET_FIRMWARE_400) { + if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_400) { print(SCREEN_LOG_LEVEL_INFO, "[NXBOOT]: Initializing Boot Reason...\n"); - nxboot_set_bootreason(); + nxboot_set_bootreason((void *)MAILBOX_NX_BOOTLOADER_BOOT_REASON_BASE(target_firmware)); } /* Read the warmboot firmware from a file, otherwise from Atmosphere's implementation. */ diff --git a/fusee/fusee-secondary/src/nxboot.h b/fusee/fusee-secondary/src/nxboot.h index 6a042ea2a..15d31d88a 100644 --- a/fusee/fusee-secondary/src/nxboot.h +++ b/fusee/fusee-secondary/src/nxboot.h @@ -19,12 +19,14 @@ #include "utils.h" -#define MAILBOX_NX_BOOTLOADER_BASE 0x40002000 -#define MAILBOX_NX_BOOTLOADER_BOOT_REASON_BASE (MAILBOX_NX_BOOTLOADER_BASE + 0xE10) -#define MAKE_MAILBOX_NX_BOOTLOADER_REG(n) MAKE_REG32(MAILBOX_NX_BOOTLOADER_BASE + n) +#define MAILBOX_NX_BOOTLOADER_BASE_100_620 0x40002E00 +#define MAILBOX_NX_BOOTLOADER_BASE_700 0x40000000 +#define MAILBOX_NX_BOOTLOADER_BASE(targetfw) ((targetfw >= ATMOSPHERE_TARGET_FIRMWARE_700) ? (MAILBOX_NX_BOOTLOADER_BASE_700) : (MAILBOX_NX_BOOTLOADER_BASE_100_620)) +#define MAKE_MAILBOX_NX_BOOTLOADER_REG(targetfw, n) MAKE_REG32(MAILBOX_NX_BOOTLOADER_BASE(targetfw) + n) -#define MAILBOX_NX_BOOTLOADER_SETUP_STATE MAKE_MAILBOX_NX_BOOTLOADER_REG(0xEF8) -#define MAILBOX_NX_BOOTLOADER_IS_SECMON_AWAKE MAKE_MAILBOX_NX_BOOTLOADER_REG(0xEFC) +#define MAILBOX_NX_BOOTLOADER_BOOT_REASON_BASE(targetfw) (MAILBOX_NX_BOOTLOADER_BASE(targetfw) + 0x10) +#define MAILBOX_NX_BOOTLOADER_SETUP_STATE(targetfw) MAKE_MAILBOX_NX_BOOTLOADER_REG(targetfw, 0xF8) +#define MAILBOX_NX_BOOTLOADER_IS_SECMON_AWAKE(targetfw) MAKE_MAILBOX_NX_BOOTLOADER_REG(targetfw, 0xFC) #define NX_BOOTLOADER_STATE_INIT 0 #define NX_BOOTLOADER_STATE_MOVED_BOOTCONFIG 1 diff --git a/fusee/fusee-secondary/src/nxboot_iram.c b/fusee/fusee-secondary/src/nxboot_iram.c index 0705af10d..41156973d 100644 --- a/fusee/fusee-secondary/src/nxboot_iram.c +++ b/fusee/fusee-secondary/src/nxboot_iram.c @@ -28,6 +28,7 @@ #include "sysreg.h" void nxboot_finish(uint32_t boot_memaddr) { + uint32_t target_firmware = MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware; volatile tegra_se_t *se = se_get_regs(); /* Clear used keyslots. */ @@ -36,7 +37,7 @@ void nxboot_finish(uint32_t boot_memaddr) { /* Lock keyslots. */ set_aes_keyslot_flags(KEYSLOT_SWITCH_MASTERKEY, 0xFF); - if (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware < ATMOSPHERE_TARGET_FIRMWARE_400) { + if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_400) { set_aes_keyslot_flags(KEYSLOT_SWITCH_DEVICEKEY, 0xFF); } else { set_aes_keyslot_flags(KEYSLOT_SWITCH_4XOLDDEVICEKEY, 0xFF); @@ -61,11 +62,11 @@ void nxboot_finish(uint32_t boot_memaddr) { se->_0x0 &= 0xFFFFFFFB; /* Boot up Exosphère. */ - MAILBOX_NX_BOOTLOADER_IS_SECMON_AWAKE = 0; - if (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware < ATMOSPHERE_TARGET_FIRMWARE_400) { - MAILBOX_NX_BOOTLOADER_SETUP_STATE = NX_BOOTLOADER_STATE_LOADED_PACKAGE2; + MAILBOX_NX_BOOTLOADER_IS_SECMON_AWAKE(target_firmware) = 0; + if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_400) { + MAILBOX_NX_BOOTLOADER_SETUP_STATE(target_firmware) = NX_BOOTLOADER_STATE_LOADED_PACKAGE2; } else { - MAILBOX_NX_BOOTLOADER_SETUP_STATE = NX_BOOTLOADER_STATE_DRAM_INITIALIZED_4X; + MAILBOX_NX_BOOTLOADER_SETUP_STATE(target_firmware) = NX_BOOTLOADER_STATE_DRAM_INITIALIZED_4X; } /* Terminate the display. */ @@ -88,15 +89,15 @@ void nxboot_finish(uint32_t boot_memaddr) { } /* Wait for Exosphère to wake up. */ - while (MAILBOX_NX_BOOTLOADER_IS_SECMON_AWAKE == 0) { + while (MAILBOX_NX_BOOTLOADER_IS_SECMON_AWAKE(target_firmware) == 0) { udelay(1); } /* Signal Exosphère. */ - if (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware < ATMOSPHERE_TARGET_FIRMWARE_400) { - MAILBOX_NX_BOOTLOADER_SETUP_STATE = NX_BOOTLOADER_STATE_FINISHED; + if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_400) { + MAILBOX_NX_BOOTLOADER_SETUP_STATE(target_firmware) = NX_BOOTLOADER_STATE_FINISHED; } else { - MAILBOX_NX_BOOTLOADER_SETUP_STATE = NX_BOOTLOADER_STATE_FINISHED_4X; + MAILBOX_NX_BOOTLOADER_SETUP_STATE(target_firmware) = NX_BOOTLOADER_STATE_FINISHED_4X; } /* Halt ourselves in waitevent state. */ diff --git a/stratosphere/loader/source/ldr_ro_service.hpp b/stratosphere/loader/source/ldr_ro_service.hpp index 05bd9d058..2a12d5f1d 100644 --- a/stratosphere/loader/source/ldr_ro_service.hpp +++ b/stratosphere/loader/source/ldr_ro_service.hpp @@ -26,6 +26,7 @@ enum RoServiceCmd { Ro_Cmd_LoadNrr = 2, Ro_Cmd_UnloadNrr = 3, Ro_Cmd_Initialize = 4, + Ro_Cmd_LoadNrrEx = 10, }; class RelocatableObjectsService final : public IServiceObject { @@ -47,6 +48,7 @@ class RelocatableObjectsService final : public IServiceObject { Result LoadNrr(PidDescriptor pid_desc, u64 nrr_address, u64 nrr_size); Result UnloadNrr(PidDescriptor pid_desc, u64 nrr_address); Result Initialize(PidDescriptor pid_desc, CopiedHandle process_h); + Result LoadNrrEx(PidDescriptor pid_desc, u64 nrr_address, u64 nrr_size); public: DEFINE_SERVICE_DISPATCH_TABLE { MakeServiceCommandMeta(),