From fa0e9061299eff22095923125ba82ca118e2b5d2 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Sat, 8 Sep 2018 23:51:52 -0700 Subject: [PATCH] exosphere: Add support for 6.0.0. --- exosphere/src/bootup.c | 26 +++++++++++-- exosphere/src/bootup.h | 2 + exosphere/src/exocfg.h | 3 +- exosphere/src/lp0.c | 5 ++- exosphere/src/masterkey.c | 6 ++- exosphere/src/masterkey.h | 7 ++-- exosphere/src/mc.c | 38 +++++++++++-------- exosphere/src/mc.h | 1 + exosphere/src/package2.c | 78 ++++++++++++++++++++++++++++++--------- exosphere/src/package2.h | 1 + exosphere/src/smc_api.c | 1 + exosphere/src/smc_user.c | 41 +++++++++++++++++--- exosphere/src/titlekey.c | 26 ++++++++++--- exosphere/src/titlekey.h | 3 ++ exosphere/src/utils.c | 7 ++-- 15 files changed, 186 insertions(+), 59 deletions(-) diff --git a/exosphere/src/bootup.c b/exosphere/src/bootup.c index 2ea2e7077..8709fd03c 100644 --- a/exosphere/src/bootup.c +++ b/exosphere/src/bootup.c @@ -46,6 +46,23 @@ static bool g_has_booted_up = false; + +void setup_dram_magic_numbers(void) { + /* TODO: Why does these DRAM write occur? */ + unsigned int target_fw = exosphere_get_target_firmware(); + if (EXOSPHERE_TARGET_FIRMWARE_400 <= target_fw) { + (*(volatile uint32_t *)(0x8005FFFC)) = 0xC0EDBBCC; + flush_dcache_range((void *)0x8005FFFC, (void *)0x80060000); + if (EXOSPHERE_TARGET_FIRMWARE_600 <= target_fw) { + (*(volatile uint32_t *)(0x8005FF00)) = 0x00000083; + (*(volatile uint32_t *)(0x8005FF04)) = 0x00000002; + (*(volatile uint32_t *)(0x8005FF08)) = 0x00000210; + flush_dcache_range((void *)0x8005FF00, (void *)0x8005FF0C); + } + } + __dsb_sy(); +} + void bootup_misc_mmio(void) { /* Initialize Fuse registers. */ fuse_init(); @@ -66,10 +83,8 @@ void bootup_misc_mmio(void) { se_generate_random_key(KEYSLOT_SWITCH_SRKGENKEY, KEYSLOT_SWITCH_RNGKEY); se_generate_srk(KEYSLOT_SWITCH_SRKGENKEY); - /* TODO: Why does this DRAM write occur? */ - if (!g_has_booted_up && exosphere_get_target_firmware() >= EXOSPHERE_TARGET_FIRMWARE_400) { - /* 4.x writes this magic number into DRAM. Why? */ - (*(volatile uint32_t *)(0x8005FFFC)) = 0xC0EDBBCC; + if (!g_has_booted_up && EXOSPHERE_TARGET_FIRMWARE_600 > exosphere_get_target_firmware() && exosphere_get_target_firmware() >= EXOSPHERE_TARGET_FIRMWARE_400) { + setup_dram_magic_numbers(); } /* Todo: What? */ @@ -219,6 +234,9 @@ void bootup_misc_mmio(void) { } void setup_4x_mmio(void) { + if (exosphere_get_target_firmware() >= EXOSPHERE_TARGET_FIRMWARE_600) { + configure_gpu_ucode_carveout(); + } /* TODO: What are these MC reg writes? */ MAKE_MC_REG(0x65C) = 0xFFFFF000; MAKE_MC_REG(0x660) = 0; diff --git a/exosphere/src/bootup.h b/exosphere/src/bootup.h index c9169e5a5..43f35441f 100644 --- a/exosphere/src/bootup.h +++ b/exosphere/src/bootup.h @@ -102,6 +102,8 @@ void bootup_misc_mmio(void); void setup_4x_mmio(void); +void setup_dram_magic_numbers(void); + void setup_current_core_state(void); void identity_unmap_iram_cd_tzram(void); diff --git a/exosphere/src/exocfg.h b/exosphere/src/exocfg.h index 786abf36b..5ed924b48 100644 --- a/exosphere/src/exocfg.h +++ b/exosphere/src/exocfg.h @@ -32,9 +32,10 @@ #define EXOSPHERE_TARGET_FIRMWARE_300 3 #define EXOSPHERE_TARGET_FIRMWARE_400 4 #define EXOSPHERE_TARGET_FIRMWARE_500 5 +#define EXOSPHERE_TARGET_FIRMWARE_600 6 /* TODO: What should this be, for release? */ -#define EXOSPHERE_TARGET_FIRMWARE_DEFAULT_FOR_DEBUG EXOSPHERE_TARGET_FIRMWARE_500 +#define EXOSPHERE_TARGET_FIRMWARE_DEFAULT_FOR_DEBUG EXOSPHERE_TARGET_FIRMWARE_600 #define EXOSPHERE_LOOSEN_PACKAGE2_RESTRICTIONS_FOR_DEBUG 1 #define MAILBOX_BASE_PHYS (MMIO_GET_DEVICE_PA(MMIO_DEVID_NXBOOTLOADER_MAILBOX)) diff --git a/exosphere/src/lp0.c b/exosphere/src/lp0.c index e7de872ab..e6e19d3bf 100644 --- a/exosphere/src/lp0.c +++ b/exosphere/src/lp0.c @@ -244,12 +244,13 @@ void save_se_and_power_down_cpu(void) { /* TODO: uart_log("OYASUMI"); */ } - __dsb_sy(); - finalize_powerdown(); } uint32_t cpu_suspend(uint64_t power_state, uint64_t entrypoint, uint64_t argument) { + /* TODO: 6.0.0 introduces heavy deja vu mitigations. */ + /* Exosphere may want to implement these. */ + /* Ensure SMC call is to enter deep sleep. */ if ((power_state & 0x17FFF) != 0x1001B) { return 0xFFFFFFFD; diff --git a/exosphere/src/masterkey.c b/exosphere/src/masterkey.c index d7cbaa764..89e175267 100644 --- a/exosphere/src/masterkey.c +++ b/exosphere/src/masterkey.c @@ -39,6 +39,7 @@ static const uint8_t mkey_vectors_dev[MASTERKEY_REVISION_MAX][0x10] = {0x97, 0x29, 0xB0, 0x32, 0x43, 0x14, 0x8C, 0xA6, 0x85, 0xE9, 0x5A, 0x94, 0x99, 0x39, 0xAC, 0x5D}, /* Master key 01 encrypted with Master key 02. */ {0x2C, 0xCA, 0x9C, 0x31, 0x1E, 0x07, 0xB0, 0x02, 0x97, 0x0A, 0xD8, 0x03, 0xA2, 0x76, 0x3F, 0xA3}, /* Master key 02 encrypted with Master key 03. */ {0x9B, 0x84, 0x76, 0x14, 0x72, 0x94, 0x52, 0xCB, 0x54, 0x92, 0x9B, 0xC4, 0x8C, 0x5B, 0x0F, 0xBA}, /* Master key 03 encrypted with Master key 04. */ + {0x78, 0xD5, 0xF1, 0x20, 0x3D, 0x16, 0xE9, 0x30, 0x32, 0x27, 0x34, 0x6F, 0xCF, 0xE0, 0x27, 0xDC}, /* Master key 04 encrypted with Master key 05. */ }; /* Retail unit keys. */ @@ -49,6 +50,7 @@ static const uint8_t mkey_vectors[MASTERKEY_REVISION_MAX][0x10] = {0xDE, 0xCF, 0xEB, 0xEB, 0x10, 0xAE, 0x74, 0xD8, 0xAD, 0x7C, 0xF4, 0x9E, 0x62, 0xE0, 0xE8, 0x72}, /* Master key 01 encrypted with Master key 02. */ {0x0A, 0x0D, 0xDF, 0x34, 0x22, 0x06, 0x6C, 0xA4, 0xE6, 0xB1, 0xEC, 0x71, 0x85, 0xCA, 0x4E, 0x07}, /* Master key 02 encrypted with Master key 03. */ {0x6E, 0x7D, 0x2D, 0xC3, 0x0F, 0x59, 0xC8, 0xFA, 0x87, 0xA8, 0x2E, 0xD5, 0x89, 0x5E, 0xF3, 0xE9}, /* Master key 03 encrypted with Master key 04. */ + {0xEB, 0xF5, 0x6F, 0x83, 0x61, 0x9E, 0xF8, 0xFA, 0xE0, 0x87, 0xD7, 0xA1, 0x4E, 0x25, 0x36, 0xEE}, /* Master key 04 encrypted with Master key 05. */ }; bool check_mkey_revision(unsigned int revision, bool is_retail) { @@ -121,7 +123,7 @@ unsigned int mkey_get_keyslot(unsigned int revision) { void set_old_devkey(unsigned int revision, const uint8_t *key) { - if (revision < MASTERKEY_REVISION_400_410 || MASTERKEY_REVISION_500_CURRENT <= revision) { + if (revision < MASTERKEY_REVISION_400_410 || MASTERKEY_REVISION_600_CURRENT <= revision) { generic_panic(); } @@ -138,7 +140,7 @@ unsigned int devkey_get_keyslot(unsigned int revision) { } if (revision >= 1) { - if (revision == MASTERKEY_REVISION_500_CURRENT) { + if (revision == MASTERKEY_REVISION_600_CURRENT) { return KEYSLOT_SWITCH_DEVICEKEY; } else { /* Load into a temp keyslot. */ diff --git a/exosphere/src/masterkey.h b/exosphere/src/masterkey.h index 8c445aaf6..0ca987ee0 100644 --- a/exosphere/src/masterkey.h +++ b/exosphere/src/masterkey.h @@ -19,14 +19,15 @@ /* This is glue code to enable master key support across versions. */ -/* TODO: Update to 0x6 on release of new master key. */ -#define MASTERKEY_REVISION_MAX 0x5 +/* TODO: Update to 0x7 on release of new master key. */ +#define MASTERKEY_REVISION_MAX 0x6 #define MASTERKEY_REVISION_100_230 0x00 #define MASTERKEY_REVISION_300 0x01 #define MASTERKEY_REVISION_301_302 0x02 #define MASTERKEY_REVISION_400_410 0x03 -#define MASTERKEY_REVISION_500_CURRENT 0x04 +#define MASTERKEY_REVISION_500_510 0x04 +#define MASTERKEY_REVISION_600_CURRENT 0x05 #define MASTERKEY_NUM_NEW_DEVICE_KEYS (MASTERKEY_REVISION_MAX - MASTERKEY_REVISION_400_410) diff --git a/exosphere/src/mc.c b/exosphere/src/mc.c index d4234e077..97c9e5e45 100644 --- a/exosphere/src/mc.c +++ b/exosphere/src/mc.c @@ -38,6 +38,26 @@ volatile security_carveout_t *get_carveout_by_id(unsigned int carveout) { return NULL; } +void configure_gpu_ucode_carveout(void) { + /* Starting in 6.0.0, Carveout 2 is configured later on. */ + /* This is a helper function to make this easier... */ + volatile security_carveout_t *carveout = get_carveout_by_id(2); + carveout->paddr_low = 0x80020000; + carveout->paddr_high = 0; + carveout->size_big_pages = 2; /* 0x40000 */ + carveout->flags_0 = 0; + carveout->flags_1 = 0; + carveout->flags_2 = 0x3000000; + carveout->flags_3 = 0; + carveout->flags_4 = 0x300; + carveout->flags_5 = 0; + carveout->flags_6 = 0; + carveout->flags_7 = 0; + carveout->flags_8 = 0; + carveout->flags_9 = 0; + carveout->allowed_clients = 0x440167E; +} + void configure_default_carveouts(void) { /* Configure Carveout 1 (UNUSED) */ volatile security_carveout_t *carveout = get_carveout_by_id(1); @@ -57,21 +77,9 @@ void configure_default_carveouts(void) { carveout->allowed_clients = 0x04000006; /* Configure Carveout 2 (GPU UCODE) */ - carveout = get_carveout_by_id(2); - carveout->paddr_low = 0x80020000; - carveout->paddr_high = 0; - carveout->size_big_pages = 2; /* 0x40000 */ - carveout->flags_0 = 0; - carveout->flags_1 = 0; - carveout->flags_2 = 0x3000000; - carveout->flags_3 = 0; - carveout->flags_4 = 0x300; - carveout->flags_5 = 0; - carveout->flags_6 = 0; - carveout->flags_7 = 0; - carveout->flags_8 = 0; - carveout->flags_9 = 0; - carveout->allowed_clients = 0x440167E; + if (exosphere_get_target_firmware() < EXOSPHERE_TARGET_FIRMWARE_600) { + configure_gpu_ucode_carveout(); + } /* Configure Carveout 3 (UNUSED GPU) */ carveout = get_carveout_by_id(3); diff --git a/exosphere/src/mc.h b/exosphere/src/mc.h index b399e304e..22d8a971a 100644 --- a/exosphere/src/mc.h +++ b/exosphere/src/mc.h @@ -79,6 +79,7 @@ typedef struct { volatile security_carveout_t *get_carveout_by_id(unsigned int carveout); void configure_default_carveouts(void); +void configure_gpu_ucode_carveout(void); void configure_kernel_carveout(unsigned int carveout_id, uint64_t address, uint64_t size); diff --git a/exosphere/src/package2.c b/exosphere/src/package2.c index 5d6a20add..afc35dd93 100644 --- a/exosphere/src/package2.c +++ b/exosphere/src/package2.c @@ -38,20 +38,31 @@ extern void *__start_cold_addr; extern size_t __bin_size; + +static const uint8_t new_device_key_sources[MASTERKEY_NUM_NEW_DEVICE_KEYS][0x10] = { + {0x8B, 0x4E, 0x1C, 0x22, 0x42, 0x07, 0xC8, 0x73, 0x56, 0x94, 0x08, 0x8B, 0xCC, 0x47, 0x0F, 0x5D}, /* 4.x New Device Key Source. */ + {0x6C, 0xEF, 0xC6, 0x27, 0x8B, 0xEC, 0x8A, 0x91, 0x99, 0xAB, 0x24, 0xAC, 0x4F, 0x1C, 0x8F, 0x1C}, /* 5.x New Device Key Source. */ + {0x70, 0x08, 0x1B, 0x97, 0x44, 0x64, 0xF8, 0x91, 0x54, 0x9D, 0xC6, 0x84, 0x8F, 0x1A, 0xB2, 0xE4} /* 6.x New Device Key Source. */ +}; + +static const uint8_t new_device_keygen_sources[MASTERKEY_NUM_NEW_DEVICE_KEYS][0x10] = { + {0x88, 0x62, 0x34, 0x6E, 0xFA, 0xF7, 0xD8, 0x3F, 0xE1, 0x30, 0x39, 0x50, 0xF0, 0xB7, 0x5D, 0x5D}, /* 4.x New Device Keygen Source. */ + {0x06, 0x1E, 0x7B, 0xE9, 0x6D, 0x47, 0x8C, 0x77, 0xC5, 0xC8, 0xE7, 0x94, 0x9A, 0xA8, 0x5F, 0x2E}, /* 5.x New Device Keygen Source. */ + {0x99, 0xFA, 0x98, 0xBD, 0x15, 0x1C, 0x72, 0xFD, 0x7D, 0x9A, 0xD5, 0x41, 0x00, 0xFD, 0xB2, 0xEF} /* 6.x New Device Keygen Source. */ +}; + +static const uint8_t new_device_keygen_sources_dev[MASTERKEY_NUM_NEW_DEVICE_KEYS][0x10] = { + {0xD6, 0xBD, 0x9F, 0xC6, 0x18, 0x09, 0xE1, 0x96, 0x20, 0x39, 0x60, 0xD2, 0x89, 0x83, 0x31, 0x34}, /* 4.x New Device Keygen Source. */ + {0x59, 0x2D, 0x20, 0x69, 0x33, 0xB5, 0x17, 0xBA, 0xCF, 0xB1, 0x4E, 0xFD, 0xE4, 0xC2, 0x7B, 0xA8}, /* 5.x New Device Keygen Source. */ + {0xF6, 0xD8, 0x59, 0x63, 0x8F, 0x47, 0xCB, 0x4A, 0xD8, 0x74, 0x05, 0x7F, 0x88, 0x92, 0x33, 0xA5} /* 6.x New Device Keygen Source. */ +}; + static void derive_new_device_keys(unsigned int keygen_keyslot) { uint8_t work_buffer[0x10]; - static const uint8_t new_device_key_sources[MASTERKEY_NUM_NEW_DEVICE_KEYS][0x10] = { - {0x8B, 0x4E, 0x1C, 0x22, 0x42, 0x07, 0xC8, 0x73, 0x56, 0x94, 0x08, 0x8B, 0xCC, 0x47, 0x0F, 0x5D}, /* 4.x New Device Key Source. */ - {0x6C, 0xEF, 0xC6, 0x27, 0x8B, 0xEC, 0x8A, 0x91, 0x99, 0xAB, 0x24, 0xAC, 0x4F, 0x1C, 0x8F, 0x1C} /* 5.x New Device Key Source. */ - }; - - static const uint8_t new_device_keygen_sources[MASTERKEY_NUM_NEW_DEVICE_KEYS][0x10] = { - {0x88, 0x62, 0x34, 0x6E, 0xFA, 0xF7, 0xD8, 0x3F, 0xE1, 0x30, 0x39, 0x50, 0xF0, 0xB7, 0x5D, 0x5D}, /* 4.x New Device Keygen Source. */ - {0x06, 0x1E, 0x7B, 0xE9, 0x6D, 0x47, 0x8C, 0x77, 0xC5, 0xC8, 0xE7, 0x94, 0x9A, 0xA8, 0x5F, 0x2E} /* 5.x New Device Keygen Source. */ - }; + bool is_retail = configitem_is_retail(); for (unsigned int revision = 0; revision < MASTERKEY_NUM_NEW_DEVICE_KEYS; revision++) { se_aes_ecb_decrypt_block(keygen_keyslot, work_buffer, 0x10, new_device_key_sources[revision], 0x10); - decrypt_data_into_keyslot(KEYSLOT_SWITCH_TEMPKEY, mkey_get_keyslot(0), new_device_keygen_sources[revision], 0x10); + decrypt_data_into_keyslot(KEYSLOT_SWITCH_TEMPKEY, mkey_get_keyslot(0), is_retail ? new_device_keygen_sources[revision] : new_device_keygen_sources_dev[revision], 0x10); if (revision < MASTERKEY_NUM_NEW_DEVICE_KEYS - 1) { se_aes_ecb_decrypt_block(KEYSLOT_SWITCH_TEMPKEY, work_buffer, 0x10, work_buffer, 0x10); set_old_devkey(revision + MASTERKEY_REVISION_400_410, work_buffer); @@ -110,6 +121,7 @@ static void setup_se(void) { derive_new_device_keys(KEYSLOT_SWITCH_4XNEWDEVICEKEYGENKEY); break; case EXOSPHERE_TARGET_FIRMWARE_500: + case EXOSPHERE_TARGET_FIRMWARE_600: derive_new_device_keys(KEYSLOT_SWITCH_5XNEWDEVICEKEYGENKEY); break; } @@ -136,14 +148,18 @@ static void setup_boot_config(void) { if (configitem_is_retail()) { bootconfig_clear(); } else { - flush_dcache_range((uint8_t *)NX_BOOTLOADER_BOOTCONFIG_POINTER, (uint8_t *)NX_BOOTLOADER_BOOTCONFIG_POINTER + sizeof(bootconfig_t)); - bootconfig_load_and_verify((bootconfig_t *)NX_BOOTLOADER_BOOTCONFIG_POINTER); + void *bootconfig_ptr = NX_BOOTLOADER_BOOTCONFIG_POINTER; + if (exosphere_get_target_firmware() >= EXOSPHERE_TARGET_FIRMWARE_600) { + bootconfig_ptr = NX_BOOTLOADER_BOOTCONFIG_POINTER_6X; + } + flush_dcache_range((uint8_t *)bootconfig_ptr, (uint8_t *)bootconfig_ptr + sizeof(bootconfig_t)); + bootconfig_load_and_verify((bootconfig_t *)bootconfig_ptr); } } static void package2_crypt_ctr(unsigned int master_key_rev, void *dst, size_t dst_size, const void *src, size_t src_size, const void *ctr, size_t ctr_size) { /* Derive package2 key. */ - const uint8_t package2_key_source[0x10] = {0xFB, 0x8B, 0x6A, 0x9C, 0x79, 0x00, 0xC8, 0x49, 0xEF, 0xD2, 0x4D, 0x85, 0x4D, 0x30, 0xA0, 0xC7}; + static const uint8_t package2_key_source[0x10] = {0xFB, 0x8B, 0x6A, 0x9C, 0x79, 0x00, 0xC8, 0x49, 0xEF, 0xD2, 0x4D, 0x85, 0x4D, 0x30, 0xA0, 0xC7}; flush_dcache_range((uint8_t *)dst, (uint8_t *)dst + dst_size); flush_dcache_range((uint8_t *)src, (uint8_t *)src + src_size); unsigned int keyslot = mkey_get_keyslot(master_key_rev); @@ -399,7 +415,22 @@ static void load_package2_sections(package2_meta_t *metadata, uint32_t master_ke } static void copy_warmboot_bin_to_dram() { - uint8_t *warmboot_src = (uint8_t *)0x4003B000; + uint8_t *warmboot_src; + switch (exosphere_get_target_firmware()) { + case EXOSPHERE_TARGET_FIRMWARE_100: + case EXOSPHERE_TARGET_FIRMWARE_200: + case EXOSPHERE_TARGET_FIRMWARE_300: + default: + generic_panic(); + break; + case EXOSPHERE_TARGET_FIRMWARE_400: + case EXOSPHERE_TARGET_FIRMWARE_500: + warmboot_src = (uint8_t *)0x4003B000; + break; + case EXOSPHERE_TARGET_FIRMWARE_600: + warmboot_src = (uint8_t *)0x4003D800; + break; + } uint8_t *warmboot_dst = (uint8_t *)0x8000D000; const size_t warmboot_size = 0x2000; @@ -448,8 +479,18 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) { MAKE_REG32(PMC_BASE + 0x054) = 0x8000D000; MAKE_REG32(PMC_BASE + 0x0A0) &= 0xFFF3FFFF; MAKE_REG32(PMC_BASE + 0x818) &= 0xFFFFFFFE; - MAKE_REG32(PMC_BASE + 0x334) |= 0x10; - MAKE_REG32(PMC_BASE + 0x360) = 6; + MAKE_REG32(PMC_BASE + 0x334) |= 0x10; + switch (exosphere_get_target_firmware()) { + case EXOSPHERE_TARGET_FIRMWARE_400: + MAKE_REG32(PMC_BASE + 0x360) = 5; + break; + case EXOSPHERE_TARGET_FIRMWARE_500: + MAKE_REG32(PMC_BASE + 0x360) = 6; + break; + case EXOSPHERE_TARGET_FIRMWARE_600: + MAKE_REG32(PMC_BASE + 0x360) = 0x87; + break; + } } wait(1000); @@ -465,7 +506,7 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) { randomcache_init(); /* memclear the initial copy of Exosphere running in IRAM (relocated to TZRAM by earlier code). */ - memset((void *)reloc_list->reloc_base, 0, reloc_list->loaded_bin_size); + //memset((void *)reloc_list->reloc_base, 0, reloc_list->loaded_bin_size); /* Let NX Bootloader know that we're running. */ MAILBOX_NX_BOOTLOADER_IS_SECMON_AWAKE = 1; @@ -490,6 +531,9 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) { if (exosphere_get_target_firmware() >= EXOSPHERE_TARGET_FIRMWARE_400) { sync_with_nx_bootloader(NX_BOOTLOADER_STATE_DRAM_INITIALIZED_4X); copy_warmboot_bin_to_dram(); + if (exosphere_get_target_firmware() >= EXOSPHERE_TARGET_FIRMWARE_600) { + setup_dram_magic_numbers(); + } sync_with_nx_bootloader(NX_BOOTLOADER_STATE_LOADED_PACKAGE2_4X); } else { sync_with_nx_bootloader(NX_BOOTLOADER_STATE_LOADED_PACKAGE2); diff --git a/exosphere/src/package2.h b/exosphere/src/package2.h index 66f4494a7..ec0dfba3e 100644 --- a/exosphere/src/package2.h +++ b/exosphere/src/package2.h @@ -50,6 +50,7 @@ static inline uintptr_t get_nx_bootloader_mailbox_base(void) { #define MAILBOX_NX_BOOTLOADER_BOOT_REASON (MAILBOX_NX_BOOTLOADER_BASE + 0xE10ULL) #define NX_BOOTLOADER_BOOTCONFIG_POINTER ((void *)(0x4003D000ull)) +#define NX_BOOTLOADER_BOOTCONFIG_POINTER_6X ((void *)(0x4003F800ull)) #define NX_BOOTLOADER_PACKAGE2_LOAD_ADDRESS ((void *)(0xA9800000ull)) diff --git a/exosphere/src/smc_api.c b/exosphere/src/smc_api.c index ca1d49d36..f391dc539 100644 --- a/exosphere/src/smc_api.c +++ b/exosphere/src/smc_api.c @@ -158,6 +158,7 @@ void set_version_specific_smcs(void) { /* Do nothing. */ break; case EXOSPHERE_TARGET_FIRMWARE_500: + case EXOSPHERE_TARGET_FIRMWARE_600: /* No more LoadSecureExpModKey. */ g_smc_user_table[0xE].handler = NULL; g_smc_user_table[0xC].id = 0xC300D60C; diff --git a/exosphere/src/smc_user.c b/exosphere/src/smc_user.c index acf21ebe1..c2b1fbecb 100644 --- a/exosphere/src/smc_user.c +++ b/exosphere/src/smc_user.c @@ -40,6 +40,20 @@ static uint8_t g_imported_exponents[4][0x100]; static uint8_t g_rsausecase_to_cryptousecase[5] = {1, 2, 3, 5, 6}; +static bool is_user_keyslot_valid(unsigned int keyslot) { + switch (exosphere_get_target_firmware()) { + case EXOSPHERE_TARGET_FIRMWARE_100: + case EXOSPHERE_TARGET_FIRMWARE_200: + case EXOSPHERE_TARGET_FIRMWARE_300: + case EXOSPHERE_TARGET_FIRMWARE_400: + case EXOSPHERE_TARGET_FIRMWARE_500: + return keyslot <= 3; + case EXOSPHERE_TARGET_FIRMWARE_600: + default: + return keyslot <= 5; + } +} + void set_exp_mod_done(bool done) { g_exp_mod_done = done; } @@ -152,7 +166,7 @@ uint32_t user_generate_aes_kek(smc_args_t *args) { /* 5.0.0+ Bounds checking. */ if (exosphere_get_target_firmware() >= EXOSPHERE_TARGET_FIRMWARE_500) { if (is_personalized) { - if (master_key_rev > MASTERKEY_REVISION_500_CURRENT || ((1 << (master_key_rev + 1)) & 0x33) == 0) { + if (master_key_rev > MASTERKEY_REVISION_600_CURRENT || ((1 << (master_key_rev + 1)) & 0x73) == 0) { return 2; } if (mask_id > 3 || usecase >= CRYPTOUSECASE_MAX_5X) { @@ -238,7 +252,7 @@ uint32_t user_load_aes_key(smc_args_t *args) { uint64_t wrapped_key[2]; uint32_t keyslot = (uint32_t)args->X[1]; - if (keyslot > 3) { + if (!is_user_keyslot_valid(keyslot)) { return 2; } @@ -278,6 +292,10 @@ uint32_t crypt_aes_done_handler(void) { uint32_t user_crypt_aes(smc_args_t *args) { uint32_t keyslot = args->X[1] & 3; uint32_t mode = (args->X[1] >> 4) & 3; + + if (exosphere_get_target_firmware() >= EXOSPHERE_TARGET_FIRMWARE_600) { + keyslot = args->X[1] & 7; + } uint64_t iv_ctr[2]; iv_ctr[0] = args->X[2]; @@ -287,7 +305,7 @@ uint32_t user_crypt_aes(smc_args_t *args) { uint32_t out_ll_paddr = (uint32_t)(args->X[5]); size_t size = args->X[6]; - if (size & 0xF) { + if (!is_user_keyslot_valid(keyslot) || size & 0xF) { return 2; } @@ -406,7 +424,7 @@ uint32_t user_compute_cmac(smc_args_t *args) { upage_ref_t page_ref; /* Validate keyslot and size. */ - if (keyslot > 3 || args->X[3] > 0x400) { + if (!is_user_keyslot_valid(keyslot) || args->X[3] > 0x400) { return 2; } @@ -642,7 +660,16 @@ uint32_t user_unwrap_rsa_oaep_wrapped_titlekey(smc_args_t *args) { void *user_wrapped_key = (void *)args->X[1]; void *user_modulus = (void *)args->X[2]; - unsigned int master_key_rev = (unsigned int)args->X[7]; + unsigned int option = (unsigned int)args->X[7]; + unsigned int master_key_rev; + unsigned int titlekey_type; + if (exosphere_get_target_firmware() >= EXOSPHERE_TARGET_FIRMWARE_600) { + master_key_rev = option & 0x3F; + titlekey_type = (option >> 6) & 1; + } else { + master_key_rev = option; + titlekey_type = 0; + } if(master_key_rev > 0) { master_key_rev -= 1; @@ -673,6 +700,7 @@ uint32_t user_unwrap_rsa_oaep_wrapped_titlekey(smc_args_t *args) { tkey_set_expected_label_hash(&args->X[3]); tkey_set_master_key_rev(master_key_rev); + tkey_set_type(titlekey_type); /* Hardcode RSA keyslot 0. */ set_rsa_keyslot(0, modulus, 0x100, g_imported_exponents[0], 0x100); @@ -686,7 +714,7 @@ uint32_t user_load_titlekey(smc_args_t *args) { uint64_t sealed_titlekey[2]; uint32_t keyslot = (uint32_t)args->X[1]; - if (keyslot > 3) { + if (!is_user_keyslot_valid(keyslot)) { return 2; } @@ -721,6 +749,7 @@ uint32_t user_unwrap_aes_wrapped_titlekey(smc_args_t *args) { } tkey_set_master_key_rev(master_key_rev); + tkey_set_type(0); tkey_aes_unwrap(titlekey, 0x10, aes_wrapped_titlekey, 0x10); seal_titlekey(sealed_titlekey, 0x10, titlekey, 0x10); diff --git a/exosphere/src/titlekey.c b/exosphere/src/titlekey.c index 3b6d957a8..b5a35b6f5 100644 --- a/exosphere/src/titlekey.c +++ b/exosphere/src/titlekey.c @@ -19,6 +19,7 @@ #include "utils.h" #include "arm.h" +#include "exocfg.h" #include "titlekey.h" #include "masterkey.h" @@ -26,6 +27,7 @@ static uint64_t g_tkey_expected_label_hash[4]; static unsigned int g_tkey_master_key_rev = MASTERKEY_REVISION_MAX; +static unsigned int g_tkey_type = 0; /* Set the expected db prefix. */ void tkey_set_expected_label_hash(uint64_t *label_hash) { @@ -41,6 +43,17 @@ void tkey_set_master_key_rev(unsigned int master_key_rev) { g_tkey_master_key_rev = master_key_rev; } +static void tkey_validate_type(unsigned int type) { + if (type > TITLEKEY_TYPE_MAX || (type > 0 && exosphere_get_target_firmware() < EXOSPHERE_TARGET_FIRMWARE_600)) { + generic_panic(); + } +} + +void tkey_set_type(unsigned int type) { + tkey_validate_type(type); + g_tkey_type = type; +} + /* Reference for MGF1 can be found here: https://en.wikipedia.org/wiki/Mask_generation_function#MGF1 */ void calculate_mgf1_and_xor(void *masked, size_t masked_size, const void *seed, size_t seed_size) { uint8_t cur_hash[0x20]; @@ -152,18 +165,19 @@ size_t tkey_rsa_oaep_unwrap(void *dst, size_t dst_size, void *src, size_t src_si return wrapped_titlekey_size; } +static const uint8_t titlekek_sources[TITLEKEY_TYPE_MAX+1][0x10] = { + {0x1E, 0xDC, 0x7B, 0x3B, 0x60, 0xE6, 0xB4, 0xD8, 0x78, 0xB8, 0x17, 0x15, 0x98, 0x5E, 0x62, 0x9B}, + {0x3B, 0x78, 0xF2, 0x61, 0x0F, 0x9D, 0x5A, 0xE2, 0x7B, 0x4E, 0x45, 0xAF, 0xCB, 0x0B, 0x67, 0x4D} +}; + void tkey_aes_unwrap(void *dst, size_t dst_size, const void *src, size_t src_size) { if (g_tkey_master_key_rev >= MASTERKEY_REVISION_MAX || dst_size != 0x10 || src_size != 0x10) { generic_panic(); } - - const uint8_t titlekek_source[0x10] = { - 0x1E, 0xDC, 0x7B, 0x3B, 0x60, 0xE6, 0xB4, 0xD8, 0x78, 0xB8, 0x17, 0x15, 0x98, 0x5E, 0x62, 0x9B - }; - + /* Generate the appropriate titlekek into keyslot 9. */ unsigned int master_keyslot = mkey_get_keyslot(g_tkey_master_key_rev); - decrypt_data_into_keyslot(KEYSLOT_SWITCH_TEMPKEY, master_keyslot, titlekek_source, 0x10); + decrypt_data_into_keyslot(KEYSLOT_SWITCH_TEMPKEY, master_keyslot, titlekek_sources[g_tkey_type], 0x10); /* Unwrap the titlekey using the titlekek. */ se_aes_ecb_decrypt_block(KEYSLOT_SWITCH_TEMPKEY, dst, 0x10, src, 0x10); diff --git a/exosphere/src/titlekey.h b/exosphere/src/titlekey.h index bfcf95d44..8b4593911 100644 --- a/exosphere/src/titlekey.h +++ b/exosphere/src/titlekey.h @@ -19,8 +19,11 @@ #include +#define TITLEKEY_TYPE_MAX 0x1 + void tkey_set_expected_label_hash(uint64_t *label_hash); void tkey_set_master_key_rev(unsigned int master_key_rev); +void tkey_set_type(unsigned int type); size_t tkey_rsa_oaep_unwrap(void *dst, size_t dst_size, void *src, size_t src_size); diff --git a/exosphere/src/utils.c b/exosphere/src/utils.c index e2b421071..a01243e8a 100644 --- a/exosphere/src/utils.c +++ b/exosphere/src/utils.c @@ -30,14 +30,15 @@ __attribute__ ((noreturn)) void panic(uint32_t code) { APBDEV_PMC_SCRATCH200_0 = code; } - /* Uncomment for Debugging. + /* // Uncomment for Debugging. uint64_t temp_reg; MAKE_REG32(MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_DEBUG_IRAM)) = APBDEV_PMC_SCRATCH200_0; SAVE_SYSREG64(ESR_EL3, 0x10); SAVE_SYSREG64(ELR_EL3, 0x18); SAVE_SYSREG64(FAR_EL3, 0x20); MAKE_REG32(MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_RTC_PMC) + 0x450ull) = 0x2; - MAKE_REG32(MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_RTC_PMC) + 0x400ull) = 0x10; */ + MAKE_REG32(MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_RTC_PMC) + 0x400ull) = 0x10; + */ /* TODO: Custom Panic Driver, which displays to screen without rebooting. */ /* For now, just use NX BOOTLOADER's panic. */ @@ -48,7 +49,7 @@ __attribute__ ((noreturn)) void panic(uint32_t code) { } __attribute__ ((noreturn)) void generic_panic(void) { - /* Uncomment for Debugging. + /* //Uncomment for Debugging. uint64_t temp_reg; do { __asm__ __volatile__ ("mov %0, LR" : "=r"(temp_reg) :: "memory"); } while (false); MAKE_REG32(MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_DEBUG_IRAM) + 0x28) = (uint32_t)((temp_reg >> 0) & 0xFFFFFFFFULL);