diff --git a/Makefile b/Makefile
index a380a5d94..113f24aec 100644
--- a/Makefile
+++ b/Makefile
@@ -61,7 +61,8 @@ dist: all
cp fusee/fusee-secondary/fusee-secondary.bin atmosphere-$(AMSVER)/sept/payload.bin
cp sept/sept-primary/sept-primary.bin atmosphere-$(AMSVER)/sept/sept-primary.bin
cp sept/sept-secondary/sept-secondary.bin atmosphere-$(AMSVER)/sept/sept-secondary.bin
- cp sept/sept-secondary/sept-secondary.enc atmosphere-$(AMSVER)/sept/sept-secondary.enc
+ cp sept/sept-secondary/sept-secondary_00.enc atmosphere-$(AMSVER)/sept/sept-secondary_00.enc
+ cp sept/sept-secondary/sept-secondary_01.enc atmosphere-$(AMSVER)/sept/sept-secondary_01.enc
cp common/defaults/BCT.ini atmosphere-$(AMSVER)/atmosphere/BCT.ini
cp common/defaults/loader.ini atmosphere-$(AMSVER)/atmosphere/loader.ini
cp common/defaults/system_settings.ini atmosphere-$(AMSVER)/atmosphere/system_settings.ini
diff --git a/common/defaults/kip_patches/default_nogc/6B09B67B29C020246DC34F5A04F5D3090215C46F37BD079442977A85B8243BA5.ips b/common/defaults/kip_patches/default_nogc/6B09B67B29C020246DC34F5A04F5D3090215C46F37BD079442977A85B8243BA5.ips
new file mode 100644
index 000000000..05869a6e9
Binary files /dev/null and b/common/defaults/kip_patches/default_nogc/6B09B67B29C020246DC34F5A04F5D3090215C46F37BD079442977A85B8243BA5.ips differ
diff --git a/common/defaults/kip_patches/default_nogc/B4CAE1F24965D92ED24EBE9E97F609C363834471BF18CA375CB6A1DEB77755EA.ips b/common/defaults/kip_patches/default_nogc/B4CAE1F24965D92ED24EBE9E97F609C363834471BF18CA375CB6A1DEB77755EA.ips
new file mode 100644
index 000000000..6e66bc3bb
Binary files /dev/null and b/common/defaults/kip_patches/default_nogc/B4CAE1F24965D92ED24EBE9E97F609C363834471BF18CA375CB6A1DEB77755EA.ips differ
diff --git a/common/include/atmosphere/target_fw.h b/common/include/atmosphere/target_fw.h
index 4f944b293..4e368c44f 100644
--- a/common/include/atmosphere/target_fw.h
+++ b/common/include/atmosphere/target_fw.h
@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
-
+
#ifndef ATMOSPHERE_TARGET_FIRMWARE_H
#define ATMOSPHERE_TARGET_FIRMWARE_H
@@ -26,11 +26,12 @@
#define ATMOSPHERE_TARGET_FIRMWARE_620 7
#define ATMOSPHERE_TARGET_FIRMWARE_700 8
#define ATMOSPHERE_TARGET_FIRMWARE_800 9
+#define ATMOSPHERE_TARGET_FIRMWARE_810 10
-#define ATMOSPHERE_TARGET_FIRMWARE_CURRENT ATMOSPHERE_TARGET_FIRMWARE_800
+#define ATMOSPHERE_TARGET_FIRMWARE_CURRENT ATMOSPHERE_TARGET_FIRMWARE_810
#define ATMOSPHERE_TARGET_FIRMWARE_MIN ATMOSPHERE_TARGET_FIRMWARE_100
-#define ATMOSPHERE_TARGET_FIRMWARE_MAX ATMOSPHERE_TARGET_FIRMWARE_800
+#define ATMOSPHERE_TARGET_FIRMWARE_MAX ATMOSPHERE_TARGET_FIRMWARE_810
/* TODO: What should this be, for release? */
#define ATMOSPHERE_TARGET_FIRMWARE_DEFAULT_FOR_DEBUG ATMOSPHERE_TARGET_FIRMWARE_CURRENT
diff --git a/common/include/atmosphere/version.h b/common/include/atmosphere/version.h
index fd07c5b20..b0afdfc7b 100644
--- a/common/include/atmosphere/version.h
+++ b/common/include/atmosphere/version.h
@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
-
+
#ifndef ATMOSPHERE_VERSION_H
#define ATMOSPHERE_VERSION_H
@@ -22,7 +22,7 @@
#define ATMOSPHERE_RELEASE_VERSION_MICRO 0
#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MAJOR 8
-#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MINOR 0
-#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MICRO 1
+#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MINOR 1
+#define ATMOSPHERE_SUPPORTED_HOS_VERSION_MICRO 0
#endif
\ No newline at end of file
diff --git a/emummc/source/FS/FS_offsets.c b/emummc/source/FS/FS_offsets.c
index 7f0cff371..1f578cd68 100644
--- a/emummc/source/FS/FS_offsets.c
+++ b/emummc/source/FS/FS_offsets.c
@@ -39,6 +39,8 @@
#include "offsets/700_exfat.h"
#include "offsets/800.h"
#include "offsets/800_exfat.h"
+#include "offsets/810.h"
+#include "offsets/810_exfat.h"
#include "../utils/fatal.h"
#define GET_OFFSET_STRUCT_NAME(vers) g_offsets##vers
@@ -88,6 +90,8 @@ DEFINE_OFFSET_STRUCT(_700);
DEFINE_OFFSET_STRUCT(_700_EXFAT);
DEFINE_OFFSET_STRUCT(_800);
DEFINE_OFFSET_STRUCT(_800_EXFAT);
+DEFINE_OFFSET_STRUCT(_810);
+DEFINE_OFFSET_STRUCT(_810_EXFAT);
const fs_offsets_t *get_fs_offsets(enum FS_VER version) {
switch (version) {
@@ -137,6 +141,10 @@ const fs_offsets_t *get_fs_offsets(enum FS_VER version) {
return &(GET_OFFSET_STRUCT_NAME(_800));
case FS_VER_8_0_0_EXFAT:
return &(GET_OFFSET_STRUCT_NAME(_800_EXFAT));
+ case FS_VER_8_1_0:
+ return &(GET_OFFSET_STRUCT_NAME(_810));
+ case FS_VER_8_1_0_EXFAT:
+ return &(GET_OFFSET_STRUCT_NAME(_810_EXFAT));
default:
fatal_abort(Fatal_UnknownVersion);
}
diff --git a/emummc/source/FS/FS_versions.h b/emummc/source/FS/FS_versions.h
index 8dd88827c..e952ee48e 100644
--- a/emummc/source/FS/FS_versions.h
+++ b/emummc/source/FS/FS_versions.h
@@ -56,6 +56,9 @@ enum FS_VER
FS_VER_8_0_0,
FS_VER_8_0_0_EXFAT,
+ FS_VER_8_1_0,
+ FS_VER_8_1_0_EXFAT,
+
FS_VER_MAX,
};
diff --git a/emummc/source/FS/offsets/810.h b/emummc/source/FS/offsets/810.h
new file mode 100644
index 000000000..02f60dcd9
--- /dev/null
+++ b/emummc/source/FS/offsets/810.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2019 m4xw
+ * Copyright (c) 2019 Atmosphere-NX
+ *
+ * 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 __FS_810_H__
+#define __FS_810_H__
+
+// Accessor vtable getters
+#define FS_OFFSET_810_SDMMC_ACCESSOR_GC 0x15EA20
+#define FS_OFFSET_810_SDMMC_ACCESSOR_SD 0x15E790
+#define FS_OFFSET_810_SDMMC_ACCESSOR_NAND 0x15AC80
+
+// Hooks
+#define FS_OFFSET_810_SDMMC_WRAPPER_READ 0x152A80
+#define FS_OFFSET_810_SDMMC_WRAPPER_WRITE 0x152B60
+#define FS_OFFSET_810_RTLD 0x5B4
+#define FS_OFFSET_810_RTLD_DESTINATION 0x9C
+
+#define FS_OFFSET_810_CLKRST_SET_MIN_V_CLK_RATE 0x16F370
+
+// Misc funcs
+#define FS_OFFSET_810_LOCK_MUTEX 0x14B6D0
+#define FS_OFFSET_810_UNLOCK_MUTEX 0x14B720
+
+// Misc Data
+#define FS_OFFSET_810_SD_MUTEX 0xF1A3E8
+#define FS_OFFSET_810_NAND_MUTEX 0xF15BE8
+#define FS_OFFSET_810_ACTIVE_PARTITION 0xF15C28
+#define FS_OFFSET_810_SDMMC_DAS_HANDLE 0xE167C0
+
+// NOPs
+#define FS_OFFSET_810_SHUTDOWN_SD 0xBAF6C
+#define FS_OFFSET_810_SD_DAS_INIT 0x87D58
+
+// Nintendo Paths
+#define FS_OFFSET_810_NINTENDO_PATHS \
+{ \
+ {.opcode_reg = 3, .adrp_offset = 0x0007F5F0, .add_rel_offset = 4}, \
+ {.opcode_reg = 3, .adrp_offset = 0x00081084, .add_rel_offset = 4}, \
+ {.opcode_reg = 3, .adrp_offset = 0x00081278, .add_rel_offset = 4}, \
+ {.opcode_reg = 3, .adrp_offset = 0x00081654, .add_rel_offset = 4}, \
+ {.opcode_reg = 4, .adrp_offset = 0x00081818, .add_rel_offset = 4}, \
+ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0} \
+}
+
+#endif // __FS_810_H__
diff --git a/emummc/source/FS/offsets/810_exfat.h b/emummc/source/FS/offsets/810_exfat.h
new file mode 100644
index 000000000..bd8240582
--- /dev/null
+++ b/emummc/source/FS/offsets/810_exfat.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2019 m4xw
+ * Copyright (c) 2019 Atmosphere-NX
+ *
+ * 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 __FS_810_EXFAT_H__
+#define __FS_810_EXFAT_H__
+
+// Accessor vtable getters
+#define FS_OFFSET_810_EXFAT_SDMMC_ACCESSOR_GC 0x169FD0
+#define FS_OFFSET_810_EXFAT_SDMMC_ACCESSOR_SD 0x169D40
+#define FS_OFFSET_810_EXFAT_SDMMC_ACCESSOR_NAND 0x166230
+
+// Hooks
+#define FS_OFFSET_810_EXFAT_SDMMC_WRAPPER_READ 0x15E030
+#define FS_OFFSET_810_EXFAT_SDMMC_WRAPPER_WRITE 0x15E110
+#define FS_OFFSET_810_EXFAT_RTLD 0x5B4
+#define FS_OFFSET_810_EXFAT_RTLD_DESTINATION 0x9C
+
+#define FS_OFFSET_810_EXFAT_CLKRST_SET_MIN_V_CLK_RATE 0x17A920
+
+// Misc funcs
+#define FS_OFFSET_810_EXFAT_LOCK_MUTEX 0x156C80
+#define FS_OFFSET_810_EXFAT_UNLOCK_MUTEX 0x156CD0
+
+// Misc Data
+#define FS_OFFSET_810_EXFAT_SD_MUTEX 0xFFE3E8
+#define FS_OFFSET_810_EXFAT_NAND_MUTEX 0xFF9BE8
+#define FS_OFFSET_810_EXFAT_ACTIVE_PARTITION 0xFF9C28
+#define FS_OFFSET_810_EXFAT_SDMMC_DAS_HANDLE 0xEFAA20
+
+// NOPs
+#define FS_OFFSET_810_EXFAT_SHUTDOWN_SD 0xC651C
+#define FS_OFFSET_810_EXFAT_SD_DAS_INIT 0x93308
+
+// Nintendo Paths
+#define FS_OFFSET_810_EXFAT_NINTENDO_PATHS \
+{ \
+ {.opcode_reg = 3, .adrp_offset = 0x0008ABA0, .add_rel_offset = 4}, \
+ {.opcode_reg = 3, .adrp_offset = 0x0008C634, .add_rel_offset = 4}, \
+ {.opcode_reg = 3, .adrp_offset = 0x0008C828, .add_rel_offset = 4}, \
+ {.opcode_reg = 3, .adrp_offset = 0x0008CC04, .add_rel_offset = 4}, \
+ {.opcode_reg = 4, .adrp_offset = 0x0008CDC8, .add_rel_offset = 4}, \
+ {.opcode_reg = 0, .adrp_offset = 0, .add_rel_offset = 0} \
+}
+
+#endif // __FS_810_EXFAT_H__
diff --git a/exosphere/src/exocfg.c b/exosphere/src/exocfg.c
index 7cf9488bd..974766178 100644
--- a/exosphere/src/exocfg.c
+++ b/exosphere/src/exocfg.c
@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
-
+
#include
#include
@@ -34,13 +34,13 @@ unsigned int exosphere_load_config(void) {
generic_panic();
}
g_has_loaded_config = true;
-
+
const unsigned int magic = MAILBOX_EXOSPHERE_CONFIG.magic;
-
+
if (magic == MAGIC_EXOSPHERE_CONFIG) {
g_exosphere_cfg = MAILBOX_EXOSPHERE_CONFIG;
}
-
+
return g_exosphere_cfg.target_firmware;
}
@@ -48,7 +48,7 @@ unsigned int exosphere_get_target_firmware(void) {
if (!g_has_loaded_config) {
generic_panic();
}
-
+
return g_exosphere_cfg.target_firmware;
}
@@ -56,15 +56,15 @@ unsigned int exosphere_should_perform_620_keygen(void) {
if (!g_has_loaded_config) {
generic_panic();
}
-
- return g_exosphere_cfg.target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_620 && EXOSPHERE_CHECK_FLAG(EXOSPHERE_FLAG_PERFORM_620_KEYGEN);
+
+ return false;
}
unsigned int exosphere_should_override_debugmode_priv(void) {
if (!g_has_loaded_config) {
generic_panic();
}
-
+
return EXOSPHERE_CHECK_FLAG(EXOSPHERE_FLAG_IS_DEBUGMODE_PRIV);
}
@@ -72,7 +72,7 @@ unsigned int exosphere_should_override_debugmode_user(void) {
if (!g_has_loaded_config) {
generic_panic();
}
-
+
return EXOSPHERE_CHECK_FLAG(EXOSPHERE_FLAG_IS_DEBUGMODE_USER);
}
@@ -80,7 +80,7 @@ unsigned int exosphere_should_disable_usermode_exception_handlers(void) {
if (!g_has_loaded_config) {
generic_panic();
}
-
+
return EXOSPHERE_CHECK_FLAG(EXOSPHERE_FLAG_DISABLE_USERMODE_EXCEPTION_HANDLERS);
}
diff --git a/exosphere/src/exocfg.h b/exosphere/src/exocfg.h
index 316aa5646..16f37ec19 100644
--- a/exosphere/src/exocfg.h
+++ b/exosphere/src/exocfg.h
@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
-
+
#ifndef EXOSPHERE_EXOSPHERE_CONFIG_H
#define EXOSPHERE_EXOSPHERE_CONFIG_H
@@ -36,7 +36,7 @@
/* Exosphere config in DRAM shares physical/virtual mapping. */
#define MAILBOX_EXOSPHERE_CONFIG_PHYS MAILBOX_EXOSPHERE_CONFIG
-#define EXOSPHERE_FLAG_PERFORM_620_KEYGEN (1 << 0u)
+#define EXOSPHERE_FLAG_PERFORM_620_KEYGEN_DEPRECATED (1 << 0u)
#define EXOSPHERE_FLAG_IS_DEBUGMODE_PRIV (1 << 1u)
#define EXOSPHERE_FLAG_IS_DEBUGMODE_USER (1 << 2u)
#define EXOSPHERE_FLAG_DISABLE_USERMODE_EXCEPTION_HANDLERS (1 << 3u)
diff --git a/exosphere/src/masterkey.c b/exosphere/src/masterkey.c
index b894a7721..d4fbea5f6 100644
--- a/exosphere/src/masterkey.c
+++ b/exosphere/src/masterkey.c
@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
-
+
#include
#include
#include
@@ -42,6 +42,7 @@ static const uint8_t mkey_vectors_dev[MASTERKEY_REVISION_MAX][0x10] =
{0x78, 0xD5, 0xF1, 0x20, 0x3D, 0x16, 0xE9, 0x30, 0x32, 0x27, 0x34, 0x6F, 0xCF, 0xE0, 0x27, 0xDC}, /* Master key 04 encrypted with Master key 05. */
{0x6F, 0xD2, 0x84, 0x1D, 0x05, 0xEC, 0x40, 0x94, 0x5F, 0x18, 0xB3, 0x81, 0x09, 0x98, 0x8D, 0x4E}, /* Master key 05 encrypted with Master key 06. */
{0x37, 0xAF, 0xAB, 0x35, 0x79, 0x09, 0xD9, 0x48, 0x29, 0xD2, 0xDB, 0xA5, 0xA5, 0xF5, 0x30, 0x19}, /* Master key 06 encrypted with Master key 07. */
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* TODO: Master key 07 encrypted with Master key 08. */
};
/* Retail unit keys. */
@@ -55,6 +56,7 @@ static const uint8_t mkey_vectors[MASTERKEY_REVISION_MAX][0x10] =
{0xEB, 0xF5, 0x6F, 0x83, 0x61, 0x9E, 0xF8, 0xFA, 0xE0, 0x87, 0xD7, 0xA1, 0x4E, 0x25, 0x36, 0xEE}, /* Master key 04 encrypted with Master key 05. */
{0x1E, 0x1E, 0x22, 0xC0, 0x5A, 0x33, 0x3C, 0xB9, 0x0B, 0xA9, 0x03, 0x04, 0xBA, 0xDB, 0x07, 0x57}, /* Master key 05 encrypted with Master key 06. */
{0xA4, 0xD4, 0x52, 0x6F, 0xD1, 0xE4, 0x36, 0xAA, 0x9F, 0xCB, 0x61, 0x27, 0x1C, 0x67, 0x65, 0x1F}, /* Master key 06 encrypted with Master key 07. */
+ {0xEA, 0x60, 0xB3, 0xEA, 0xCE, 0x8F, 0x24, 0x46, 0x7D, 0x33, 0x9C, 0xD1, 0xBC, 0x24, 0x98, 0x29}, /* Master key 07 encrypted with Master key 08. */
};
bool check_mkey_revision(unsigned int revision, bool is_retail) {
@@ -83,7 +85,7 @@ void mkey_detect_revision(void) {
if (g_determined_mkey_revision) {
generic_panic();
}
-
+
for (unsigned int rev = 0; rev < MASTERKEY_REVISION_MAX; rev++) {
if (check_mkey_revision(rev, configitem_is_retail())) {
g_determined_mkey_revision = true;
@@ -91,7 +93,7 @@ void mkey_detect_revision(void) {
break;
}
}
-
+
/* We must have determined the master key, or we're not running on a Switch. */
if (!g_determined_mkey_revision) {
/* Panic in bright red. */
@@ -125,7 +127,6 @@ 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_MAX <= revision) {
generic_panic();
@@ -135,23 +136,17 @@ void set_old_devkey(unsigned int revision, const uint8_t *key) {
}
unsigned int devkey_get_keyslot(unsigned int revision) {
- if (!g_determined_mkey_revision || revision >= MASTERKEY_REVISION_MAX) {
+ if (!g_determined_mkey_revision || revision > g_mkey_revision) {
generic_panic();
}
- if (revision > g_mkey_revision) {
- generic_panic();
- }
-
- if (revision >= 1) {
- if (revision == MASTERKEY_REVISION_MAX) {
- return KEYSLOT_SWITCH_DEVICEKEY;
- } else {
- /* Load into a temp keyslot. */
- set_aes_keyslot(KEYSLOT_SWITCH_TEMPKEY, g_old_devicekeys[revision - MASTERKEY_REVISION_400_410], 0x10);
- return KEYSLOT_SWITCH_TEMPKEY;
- }
- } else {
+ if (revision < MASTERKEY_REVISION_400_410) {
return KEYSLOT_SWITCH_4XOLDDEVICEKEY;
+ } else if (revision < g_mkey_revision) {
+ /* Load into a temp keyslot. */
+ set_aes_keyslot(KEYSLOT_SWITCH_TEMPKEY, g_old_devicekeys[revision - MASTERKEY_REVISION_400_410], 0x10);
+ return KEYSLOT_SWITCH_TEMPKEY;
+ } else {
+ return KEYSLOT_SWITCH_DEVICEKEY;
}
-}
\ No newline at end of file
+}
diff --git a/exosphere/src/masterkey.h b/exosphere/src/masterkey.h
index dab9bfbb2..90b6ec236 100644
--- a/exosphere/src/masterkey.h
+++ b/exosphere/src/masterkey.h
@@ -13,14 +13,14 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
-
+
#ifndef EXOSPHERE_MASTERKEY_H
#define EXOSPHERE_MASTERKEY_H
/* This is glue code to enable master key support across versions. */
-/* TODO: Update to 0x9 on release of new master key. */
-#define MASTERKEY_REVISION_MAX 0x8
+/* TODO: Update to 0xA on release of new master key. */
+#define MASTERKEY_REVISION_MAX 0x9
#define MASTERKEY_REVISION_100_230 0x00
#define MASTERKEY_REVISION_300 0x01
@@ -29,7 +29,8 @@
#define MASTERKEY_REVISION_500_510 0x04
#define MASTERKEY_REVISION_600_610 0x05
#define MASTERKEY_REVISION_620 0x06
-#define MASTERKEY_REVISION_700_CURRENT 0x07
+#define MASTERKEY_REVISION_700_800 0x07
+#define MASTERKEY_REVISION_810_CURRENT 0x08
#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 ccb6b8647..6a6ac75dc 100644
--- a/exosphere/src/mc.c
+++ b/exosphere/src/mc.c
@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
-
+
#include
#include "memory_map.h"
@@ -28,7 +28,7 @@ typedef struct {
static saved_carveout_info_t g_saved_carveouts[2] = {
{0x80060000ull, KERNEL_CARVEOUT_SIZE_MAX},
{0x00000000ull, 0x00000000ull}
-};
+};
volatile security_carveout_t *get_carveout_by_id(unsigned int carveout) {
if (CARVEOUT_ID_MIN <= carveout && carveout <= CARVEOUT_ID_MAX) {
@@ -130,7 +130,7 @@ void configure_kernel_carveout(unsigned int carveout_id, uint64_t address, uint6
if (carveout_id != 4 && carveout_id != 5) {
generic_panic();
}
-
+
g_saved_carveouts[carveout_id-4].address = address;
g_saved_carveouts[carveout_id-4].size = size;
@@ -140,8 +140,12 @@ void configure_kernel_carveout(unsigned int carveout_id, uint64_t address, uint6
carveout->size_big_pages = (uint32_t)(size >> 17);
carveout->client_access_0 = (BIT(CSR_PTCR) | BIT(CSR_DISPLAY0A) | BIT(CSR_DISPLAY0AB) | BIT(CSR_DISPLAY0B) | BIT(CSR_DISPLAY0BB) | BIT(CSR_DISPLAY0C) | BIT(CSR_DISPLAY0CB) | BIT(CSR_AFIR) | BIT(CSR_DISPLAYHC) | BIT(CSR_DISPLAYHCB) | BIT(CSR_HDAR) | BIT(CSR_HOST1XDMAR) | BIT(CSR_HOST1XR) | BIT(CSR_NVENCSRD) | BIT(CSR_PPCSAHBDMAR) | BIT(CSR_PPCSAHBSLVR));
carveout->client_access_1 = (BIT(CSR_MPCORER) | BIT(CSW_NVENCSWR) | BIT(CSW_AFIW) | BIT(CSW_HDAW) | BIT(CSW_HOST1XW) | BIT(CSW_MPCOREW) | BIT(CSW_PPCSAHBDMAW) | BIT(CSW_PPCSAHBSLVW));
- if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_800) {
- carveout->client_access_2 = (BIT(CSR_XUSB_HOSTR) | BIT(CSW_XUSB_HOSTW) | BIT(CSR_XUSB_DEVR) | BIT(CSW_XUSB_DEVW));
+ if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_810) {
+ carveout->client_access_2 = (BIT(CSR_XUSB_HOSTR) | BIT(CSW_XUSB_HOSTW) | BIT(CSR_XUSB_DEVR) | BIT(CSW_XUSB_DEVW));
+ carveout->client_access_3 = (BIT(CSR_SDMMCRA) | BIT(CSR_SDMMCRAA) | BIT(CSR_SDMMCRAB) | BIT(CSW_SDMMCWA) | BIT(CSW_SDMMCWAA) | BIT(CSW_SDMMCWAB) | BIT(CSR_VICSRD) | BIT(CSW_VICSWR) | BIT(CSR_DISPLAYD) | BIT(CSR_APER) | BIT(CSW_APEW) | BIT(CSR_NVJPGSRD) | BIT(CSW_NVJPGSWR));
+ carveout->client_access_4 = (BIT(CSR_SESRD) | BIT(CSW_SESWR));
+ } else if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_800) {
+ carveout->client_access_2 = (BIT(CSR_XUSB_HOSTR) | BIT(CSW_XUSB_HOSTW) | BIT(CSR_XUSB_DEVR) | BIT(CSW_XUSB_DEVW));
carveout->client_access_3 = (BIT(CSR_SDMMCRA) | BIT(CSR_SDMMCRAA) | BIT(CSR_SDMMCRAB) | BIT(CSW_SDMMCWA) | BIT(CSW_SDMMCWAA) | BIT(CSW_SDMMCWAB) | BIT(CSR_VICSRD) | BIT(CSW_VICSWR) | BIT(CSR_DISPLAYD) | BIT(CSR_NVDECSRD) | BIT(CSW_NVDECSWR) | BIT(CSR_APER) | BIT(CSW_APEW) | BIT(CSR_NVJPGSRD) | BIT(CSW_NVJPGSWR));
carveout->client_access_4 = (BIT(CSR_SESRD) | BIT(CSW_SESWR) | BIT(CSR_TSECSRDB) | BIT(CSW_TSECSWRB));
} else {
diff --git a/exosphere/src/package2.c b/exosphere/src/package2.c
index 66d8828fe..76d3a8504 100644
--- a/exosphere/src/package2.c
+++ b/exosphere/src/package2.c
@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
-
+
#include
#include "utils.h"
@@ -43,6 +43,7 @@ static const uint8_t new_device_key_sources[MASTERKEY_NUM_NEW_DEVICE_KEYS][0x10]
{0x70, 0x08, 0x1B, 0x97, 0x44, 0x64, 0xF8, 0x91, 0x54, 0x9D, 0xC6, 0x84, 0x8F, 0x1A, 0xB2, 0xE4}, /* 6.x New Device Key Source. */
{0x8E, 0x09, 0x1F, 0x7A, 0xBB, 0xCA, 0x6A, 0xFB, 0xB8, 0x9B, 0xD5, 0xC1, 0x25, 0x9C, 0xA9, 0x17}, /* 6.2.0 New Device Key Source. */
{0x8F, 0x77, 0x5A, 0x96, 0xB0, 0x94, 0xFD, 0x8D, 0x28, 0xE4, 0x19, 0xC8, 0x16, 0x1C, 0xDB, 0x3D}, /* 7.0.0 New Device Key Source. */
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* TODO: 8.1.0 New Device Key Source to be added on next change-of-keys. */
};
static const uint8_t new_device_keygen_sources[MASTERKEY_NUM_NEW_DEVICE_KEYS][0x10] = {
@@ -51,6 +52,7 @@ static const uint8_t new_device_keygen_sources[MASTERKEY_NUM_NEW_DEVICE_KEYS][0x
{0x99, 0xFA, 0x98, 0xBD, 0x15, 0x1C, 0x72, 0xFD, 0x7D, 0x9A, 0xD5, 0x41, 0x00, 0xFD, 0xB2, 0xEF}, /* 6.x New Device Keygen Source. */
{0x81, 0x3C, 0x6C, 0xBF, 0x5D, 0x21, 0xDE, 0x77, 0x20, 0xD9, 0x6C, 0xE3, 0x22, 0x06, 0xAE, 0xBB}, /* 6.2.0 New Device Keygen Source. */
{0x86, 0x61, 0xB0, 0x16, 0xFA, 0x7A, 0x9A, 0xEA, 0xF6, 0xF5, 0xBE, 0x1A, 0x13, 0x5B, 0x6D, 0x9E}, /* 7.0.0 New Device Keygen Source. */
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* TODO: 8.1.0 New Device Key Source to be added on next change-of-keys. */
};
static const uint8_t new_device_keygen_sources_dev[MASTERKEY_NUM_NEW_DEVICE_KEYS][0x10] = {
@@ -58,45 +60,28 @@ static const uint8_t new_device_keygen_sources_dev[MASTERKEY_NUM_NEW_DEVICE_KEYS
{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. */
{0x20, 0xAB, 0xF2, 0x0F, 0x05, 0xE3, 0xDE, 0x2E, 0xA1, 0xFB, 0x37, 0x5E, 0x8B, 0x22, 0x1A, 0x38}, /* 6.2.0 New Device Keygen Source. */
- {0x60, 0xAE, 0x56, 0x68, 0x11, 0xE2, 0x0C, 0x99, 0xDE, 0x05, 0xAE, 0x68, 0x78, 0x85, 0x04, 0xAE}, /* 6.2.0 New Device Keygen Source. */
-};
-
-static const uint8_t new_master_kek_sources[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}, /* 6.2.0 Master Kek Source. */
- {0x9A, 0x3E, 0xA9, 0xAB, 0xFD, 0x56, 0x46, 0x1C, 0x9B, 0xF6, 0x48, 0x7F, 0x5C, 0xFA, 0x09, 0x5C}, /* 7.0.0 Master Kek Source. */
-};
-
-static const uint8_t keyblob_key_seed_00[0x10] = {
- 0xDF, 0x20, 0x6F, 0x59, 0x44, 0x54, 0xEF, 0xDC, 0x70, 0x74, 0x48, 0x3B, 0x0D, 0xED, 0x9F, 0xD3
-};
-
-static const uint8_t devicekey_seed[0x10] = {
- 0x4F, 0x02, 0x5F, 0x0E, 0xB6, 0x6D, 0x11, 0x0E, 0xDC, 0x32, 0x7D, 0x41, 0x86, 0xC2, 0xF4, 0x78
-};
-
-static const uint8_t devicekey_4x_seed[0x10] = {
- 0x0C, 0x91, 0x09, 0xDB, 0x93, 0x93, 0x07, 0x81, 0x07, 0x3C, 0xC4, 0x16, 0x22, 0x7C, 0x6C, 0x28
-};
-
-static const uint8_t masterkey_seed[0x10] = {
- 0xD8, 0xA2, 0x41, 0x0A, 0xC6, 0xC5, 0x90, 0x01, 0xC6, 0x1D, 0x6A, 0x26, 0x7C, 0x51, 0x3F, 0x3C
-};
-
-static const uint8_t devicekek_4x_seed[0x10] = {
- 0x2D, 0xC1, 0xF4, 0x8D, 0xF3, 0x5B, 0x69, 0x33, 0x42, 0x10, 0xAC, 0x65, 0xDA, 0x90, 0x46, 0x66
+ {0x60, 0xAE, 0x56, 0x68, 0x11, 0xE2, 0x0C, 0x99, 0xDE, 0x05, 0xAE, 0x68, 0x78, 0x85, 0x04, 0xAE}, /* 7.0.0 New Device Keygen Source. */
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* TODO: 8.1.0 New Device Key Source to be added on next change-of-keys. */
};
static void derive_new_device_keys(unsigned int keygen_keyslot) {
uint8_t work_buffer[0x10];
bool is_retail = configitem_is_retail();
for (unsigned int revision = 0; revision < MASTERKEY_NUM_NEW_DEVICE_KEYS; revision++) {
+ const unsigned int relative_revision = revision + MASTERKEY_REVISION_400_410;
+
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), 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);
+ if (relative_revision > mkey_get_revision()) {
+ break;
+ } else if (relative_revision == mkey_get_revision()) {
+ /* On 7.0.0, sept will have derived this key for us already. */
+ if (exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_700) {
+ decrypt_data_into_keyslot(KEYSLOT_SWITCH_DEVICEKEY, KEYSLOT_SWITCH_TEMPKEY, work_buffer, 0x10);
+ }
} else {
- decrypt_data_into_keyslot(KEYSLOT_SWITCH_DEVICEKEY, KEYSLOT_SWITCH_TEMPKEY, work_buffer, 0x10);
+ se_aes_ecb_decrypt_block(KEYSLOT_SWITCH_TEMPKEY, work_buffer, 0x10, work_buffer, 0x10);
+ set_old_devkey(relative_revision, work_buffer);
}
}
set_aes_keyslot_flags(KEYSLOT_SWITCH_DEVICEKEY, 0xFF);
@@ -118,7 +103,8 @@ static void setup_se(void) {
se->_0x0 &= 0xFFFEFFFF; /* Clear bit 16. */
(void)(se->FLAGS_REG);
__dsb_sy();
-
+
+ /* NOTE: On 8.1.0+, Nintendo does not make keyslots 0-5 unreadable. */
se->_0x4 = 0;
se->AES_KEY_READ_DISABLE_REG = 0;
se->RSA_KEY_READ_DISABLE_REG = 0;
@@ -136,33 +122,6 @@ static void setup_se(void) {
for (unsigned int i = 0; i < KEYSLOT_RSA_MAX; i++) {
set_rsa_keyslot_flags(i, 0x41);
}
-
- if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_620 && exosphere_should_perform_620_keygen()) {
- unsigned int master_kek_source_ind;
- switch (exosphere_get_target_firmware()) {
- case ATMOSPHERE_TARGET_FIRMWARE_620:
- master_kek_source_ind = MASTERKEY_REVISION_620 - MASTERKEY_REVISION_620;
- break;
- case ATMOSPHERE_TARGET_FIRMWARE_700:
- case ATMOSPHERE_TARGET_FIRMWARE_800:
- master_kek_source_ind = MASTERKEY_REVISION_700_CURRENT - MASTERKEY_REVISION_620;
- break;
- default:
- generic_panic();
- break;
- }
- /* Start by generating device keys. */
- se_aes_ecb_decrypt_block(KEYSLOT_SWITCH_6XTSECKEY, work_buffer, 0x10, keyblob_key_seed_00, 0x10);
- decrypt_data_into_keyslot(KEYSLOT_SWITCH_4XOLDDEVICEKEY, KEYSLOT_SWITCH_6XSBK, work_buffer, 0x10);
- decrypt_data_into_keyslot(KEYSLOT_SWITCH_4XNEWCONSOLEKEYGENKEY, KEYSLOT_SWITCH_4XOLDDEVICEKEY, devicekey_4x_seed, 0x10);
- decrypt_data_into_keyslot(KEYSLOT_SWITCH_4XOLDDEVICEKEY, KEYSLOT_SWITCH_4XOLDDEVICEKEY, devicekey_seed, 0x10);
-
- /* Next, generate the master kek, and from there master key/device kek. We use different keyslots than Nintendo, here. */
- decrypt_data_into_keyslot(KEYSLOT_SWITCH_6XTSECROOTKEY, KEYSLOT_SWITCH_6XTSECROOTKEY, new_master_kek_sources[master_kek_source_ind], 0x10);
- decrypt_data_into_keyslot(KEYSLOT_SWITCH_MASTERKEY, KEYSLOT_SWITCH_6XTSECROOTKEY, masterkey_seed, 0x10);
- decrypt_data_into_keyslot(KEYSLOT_SWITCH_5XNEWDEVICEKEYGENKEY, KEYSLOT_SWITCH_6XTSECROOTKEY, devicekek_4x_seed, 0x10);
- clear_aes_keyslot(KEYSLOT_SWITCH_6XTSECROOTKEY);
- }
/* Detect Master Key revision. */
mkey_detect_revision();
@@ -181,6 +140,7 @@ static void setup_se(void) {
case ATMOSPHERE_TARGET_FIRMWARE_620:
case ATMOSPHERE_TARGET_FIRMWARE_700:
case ATMOSPHERE_TARGET_FIRMWARE_800:
+ case ATMOSPHERE_TARGET_FIRMWARE_810:
derive_new_device_keys(KEYSLOT_SWITCH_5XNEWDEVICEKEYGENKEY);
break;
}
@@ -198,7 +158,7 @@ static void setup_se(void) {
set_aes_keyslot_flags(KEYSLOT_SWITCH_SESSIONKEY, 0xFF);
/* Generate test vector for our keys. */
- se_generate_stored_vector();
+ se_generate_stored_vector();
}
static void setup_boot_config(void) {
@@ -287,7 +247,7 @@ static bool validate_package2_metadata(package2_meta_t *metadata) {
if (metadata->magic != MAGIC_PK21) {
return false;
}
-
+
/* Package2 size, version number is stored XORed in header CTR. */
/* Nintendo, what the fuck? */
@@ -370,7 +330,7 @@ static bool validate_package2_metadata(package2_meta_t *metadata) {
/* Perform version checks. */
/* We will be compatible with all package2s released before current, but not newer ones. */
- if (metadata->version_max >= PACKAGE2_MINVER_THEORETICAL && metadata->version_min < PACKAGE2_MAXVER_700_CURRENT) {
+ if (metadata->version_max >= PACKAGE2_MINVER_THEORETICAL && metadata->version_min < PACKAGE2_MAXVER_810_CURRENT) {
return true;
}
@@ -495,21 +455,22 @@ static void copy_warmboot_bin_to_dram() {
break;
case ATMOSPHERE_TARGET_FIRMWARE_700:
case ATMOSPHERE_TARGET_FIRMWARE_800:
+ case ATMOSPHERE_TARGET_FIRMWARE_810:
warmboot_src = (uint8_t *)0x4003E000;
break;
}
uint8_t *warmboot_dst = (uint8_t *)0x8000D000;
const size_t warmboot_size = 0x2000;
-
+
/* Flush cache, to ensure warmboot is where we need it to be. */
flush_dcache_range(warmboot_src, warmboot_src + warmboot_size);
__dsb_sy();
-
+
/* Copy warmboot. */
for (size_t i = 0; i < warmboot_size; i += sizeof(uint32_t)) {
write32le(warmboot_dst, i, read32le(warmboot_src, i));
}
-
+
/* Flush cache, to ensure warmboot is where we need it to be. */
flush_dcache_range(warmboot_dst, warmboot_dst + warmboot_size);
__dsb_sy();
@@ -544,12 +505,12 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) {
/* Setup the Security Engine. */
setup_se();
-
+
/* Perform initial PMC register writes, if relevant. */
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_400) {
- MAKE_REG32(PMC_BASE + 0x054) = 0x8000D000;
- MAKE_REG32(PMC_BASE + 0x0A0) &= 0xFFF3FFFF;
- MAKE_REG32(PMC_BASE + 0x818) &= 0xFFFFFFFE;
+ MAKE_REG32(PMC_BASE + 0x054) = 0x8000D000;
+ MAKE_REG32(PMC_BASE + 0x0A0) &= 0xFFF3FFFF;
+ MAKE_REG32(PMC_BASE + 0x818) &= 0xFFFFFFFE;
MAKE_REG32(PMC_BASE + 0x334) |= 0x10;
switch (exosphere_get_target_firmware()) {
case ATMOSPHERE_TARGET_FIRMWARE_400:
@@ -568,6 +529,9 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) {
case ATMOSPHERE_TARGET_FIRMWARE_800:
MAKE_REG32(PMC_BASE + 0x360) = 0x129;
break;
+ case ATMOSPHERE_TARGET_FIRMWARE_810:
+ MAKE_REG32(PMC_BASE + 0x360) = 0x14A;
+ break;
}
}
@@ -585,7 +549,7 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) {
/* 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); */
-
+
/* Let NX Bootloader know that we're running. */
MAILBOX_NX_BOOTLOADER_IS_SECMON_AWAKE(exosphere_get_target_firmware()) = 1;
@@ -597,7 +561,7 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) {
/* Load Boot Config into global. */
setup_boot_config();
-
+
/* Set sysctr0 registers based on bootconfig. */
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_400) {
uint64_t sysctr0_val = bootconfig_get_value_for_sysctr0();
@@ -620,7 +584,7 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) {
/* Make PMC (2.x+), MC (4.x+) registers secure-only */
secure_additional_devices();
-
+
/* Remove the identity mapping for iRAM-C+D & TZRAM */
/* For our crt0 to work, this doesn't actually unmap TZRAM */
identity_unmap_iram_cd_tzram();
@@ -630,7 +594,7 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) {
flush_dcache_range((uint8_t *)NX_BOOTLOADER_PACKAGE2_LOAD_ADDRESS, (uint8_t *)NX_BOOTLOADER_PACKAGE2_LOAD_ADDRESS + sizeof(header));
memcpy(&header, NX_BOOTLOADER_PACKAGE2_LOAD_ADDRESS, sizeof(header));
flush_dcache_range((uint8_t *)&header, (uint8_t *)&header + sizeof(header));
-
+
/* Perform signature checks. */
/* Special exosphere patching enable: All-zeroes signature + decrypted header implies unsigned and decrypted package2. */
if (header.signature[0] == 0 && memcmp(header.signature, header.signature + 1, sizeof(header.signature) - 1) == 0 && header.metadata.magic == MAGIC_PK21) {
@@ -641,7 +605,7 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) {
/* Decrypt header, get key revision required. */
uint32_t package2_mkey_rev = decrypt_and_validate_header(&header);
-
+
/* Copy hash, if necessary. */
if (bootconfig_is_recovery_boot()) {
bootconfig_set_package2_hash_for_recovery(NX_BOOTLOADER_PACKAGE2_LOAD_ADDRESS, get_package2_size(&header.metadata));
@@ -649,7 +613,7 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) {
/* Load Package2 Sections. */
load_package2_sections(&header.metadata, package2_mkey_rev);
-
+
/* Clean up cache. */
flush_dcache_all();
invalidate_icache_all(); /* non-broadcasting */
@@ -660,7 +624,7 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) {
/* Remove the DRAM identity mapping. */
if (0) {
identity_unmap_dram();
- }
+ }
/* Synchronize with NX BOOTLOADER. */
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_400) {
diff --git a/exosphere/src/package2.h b/exosphere/src/package2.h
index 513e75d5a..900047f87 100644
--- a/exosphere/src/package2.h
+++ b/exosphere/src/package2.h
@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
-
+
#ifndef EXOSPHERE_PACKAGE2_H
#define EXOSPHERE_PACKAGE2_H
@@ -70,7 +70,8 @@ static inline uintptr_t get_nx_bootloader_mailbox_base(unsigned int targetfw) {
#define PACKAGE2_MAXVER_500_510 0x7
#define PACKAGE2_MAXVER_600_610 0x8
#define PACKAGE2_MAXVER_620 0x9
-#define PACKAGE2_MAXVER_700_CURRENT 0xA
+#define PACKAGE2_MAXVER_700_800 0xA
+#define PACKAGE2_MAXVER_810_CURRENT 0xB
#define PACKAGE2_MINVER_100 0x3
#define PACKAGE2_MINVER_200 0x4
@@ -80,7 +81,8 @@ static inline uintptr_t get_nx_bootloader_mailbox_base(unsigned int targetfw) {
#define PACKAGE2_MINVER_500_510 0x8
#define PACKAGE2_MINVER_600_610 0x9
#define PACKAGE2_MINVER_620 0xA
-#define PACKAGE2_MINVER_700_CURRENT 0xB
+#define PACKAGE2_MINVER_700_800 0xB
+#define PACKAGE2_MINVER_810_CURRENT 0xC
typedef struct {
union {
diff --git a/exosphere/src/smc_api.c b/exosphere/src/smc_api.c
index 5a5d6cadc..495682b3e 100644
--- a/exosphere/src/smc_api.c
+++ b/exosphere/src/smc_api.c
@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
-
+
#include
#include
@@ -185,6 +185,7 @@ void set_version_specific_smcs(void) {
case ATMOSPHERE_TARGET_FIRMWARE_620:
case ATMOSPHERE_TARGET_FIRMWARE_700:
case ATMOSPHERE_TARGET_FIRMWARE_800:
+ case ATMOSPHERE_TARGET_FIRMWARE_810:
/* No more LoadSecureExpModKey. */
g_smc_user_table[0xE].handler = NULL;
g_smc_user_table[0xC].id = 0xC300D60C;
@@ -256,7 +257,7 @@ void call_smc_handler(uint32_t handler_id, smc_args_t *args) {
unsigned char smc_id, call_range;
unsigned int result;
unsigned int (*smc_handler)(smc_args_t *args);
-
+
/* Validate top-level handler. */
if (handler_id >= SMC_HANDLER_COUNT) {
generic_panic();
@@ -288,17 +289,17 @@ void call_smc_handler(uint32_t handler_id, smc_args_t *args) {
if ((smc_handler = g_smc_tables[handler_id].handlers[smc_id].handler) == NULL) {
generic_panic();
}
-
+
bool is_aes_kek = handler_id == SMC_HANDLER_USER && args->X[0] == 0xC3000007;
-#if DEBUG_LOG_SMCS
- uint64_t num;
+#if DEBUG_LOG_SMCS
+ uint64_t num;
if (handler_id == SMC_HANDLER_USER) {
num = atomic_fetch_add(&num_smcs_called, 1);
*(volatile smc_args_t *)(get_iram_address_for_debug() + 0x100 + ((0x80 * num) & 0x3FFF)) = *args;
}
#endif
-
+
/* Call function. */
if (exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_800 ||
(g_smc_tables[handler_id].handlers[smc_id].blacklist_mask & g_smc_blacklist_mask) == 0) {
@@ -307,15 +308,15 @@ void call_smc_handler(uint32_t handler_id, smc_args_t *args) {
/* Call not allowed due to current boot conditions. */
args->X[0] = 6;
}
-
-#if DEBUG_LOG_SMCS
+
+#if DEBUG_LOG_SMCS
if (handler_id == SMC_HANDLER_USER) {
*(volatile smc_args_t *)(get_iram_address_for_debug() + 0x100 + ((0x80 * num + 0x40) & 0x3FFF)) = *args;
}
#endif
-
+
#if DEBUG_PANIC_ON_FAILURE
- if (args->X[0] && (!is_aes_kek || args->X[3] <= ATMOSPHERE_TARGET_FIRMWARE_DEFAULT_FOR_DEBUG))
+ if (args->X[0] && (!is_aes_kek || args->X[3] <= ATMOSPHERE_TARGET_FIRMWARE_DEFAULT_FOR_DEBUG))
{
MAKE_REG32(get_iram_address_for_debug() + 0x4FF0) = handler_id;
MAKE_REG32(get_iram_address_for_debug() + 0x4FF4) = smc_id;
@@ -695,14 +696,14 @@ uint32_t smc_configure_carveout(smc_args_t *args) {
if (size > KERNEL_CARVEOUT_SIZE_MAX) {
return 2;
}
-
+
/* Ensure validity of carveout index. */
if (carveout_id > 1) {
return 2;
}
/* Configuration is one-shot, and cannot be done multiple times. */
- if (exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_300) {
+ if (exosphere_get_target_firmware() < ATMOSPHERE_TARGET_FIRMWARE_300) {
if (g_configured_carveouts[carveout_id]) {
return 2;
}
diff --git a/exosphere/src/smc_user.c b/exosphere/src/smc_user.c
index c8d9c12d4..cf47e9fd4 100644
--- a/exosphere/src/smc_user.c
+++ b/exosphere/src/smc_user.c
@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
-
+
#include
#include
#include
@@ -52,6 +52,7 @@ static bool is_user_keyslot_valid(unsigned int keyslot) {
case ATMOSPHERE_TARGET_FIRMWARE_620:
case ATMOSPHERE_TARGET_FIRMWARE_700:
case ATMOSPHERE_TARGET_FIRMWARE_800:
+ case ATMOSPHERE_TARGET_FIRMWARE_810:
default:
return keyslot <= 5;
}
@@ -165,7 +166,7 @@ uint32_t user_generate_aes_kek(smc_args_t *args) {
bool is_personalized = (int)(packed_options & 1);
bool is_recovery_boot = configitem_is_recovery_boot();
-
+
/* 5.0.0+ Bounds checking. */
if (exosphere_get_target_firmware() >= ATMOSPHERE_TARGET_FIRMWARE_500) {
if (is_personalized) {
@@ -295,7 +296,7 @@ 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() >= ATMOSPHERE_TARGET_FIRMWARE_600) {
keyslot = args->X[1] & 7;
}
@@ -791,7 +792,7 @@ uint32_t user_encrypt_rsa_key_for_import(smc_args_t *args) {
if (usecase > CRYPTOUSECASE_RSAIMPORT) {
return 2;
- }
+ }
if (usecase == 0) {
if (size < 0x31 || size > 0x240) {
return 2;
@@ -823,7 +824,7 @@ uint32_t user_encrypt_rsa_key_for_import(smc_args_t *args) {
if (secure_copy_to_user(&page_ref, user_address, user_data, size) == 0) {
return 2;
- }
+ }
return 0;
}
@@ -854,7 +855,7 @@ uint32_t user_decrypt_or_import_rsa_key(smc_args_t *args) {
if (usecase > CRYPTOUSECASE_RSAIMPORT) {
return 2;
- }
+ }
if (usecase == 0) {
if (size < 0x31 || size > 0x240) {
return 2;
@@ -881,7 +882,7 @@ uint32_t user_decrypt_or_import_rsa_key(smc_args_t *args) {
case 0:
if (secure_copy_to_user(&page_ref, user_address, user_data, size) == 0) {
return 2;
- }
+ }
return 0;
case 1:
exponent_id = 1;
diff --git a/fusee/fusee-secondary/Makefile b/fusee/fusee-secondary/Makefile
index 844dc8cf0..64fa59ba3 100644
--- a/fusee/fusee-secondary/Makefile
+++ b/fusee/fusee-secondary/Makefile
@@ -99,7 +99,7 @@ SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
KIPFILES := loader.kip pm.kip sm.kip ams_mitm.kip spl.kip boot.kip
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) fusee-primary.bin \
exosphere.bin lp0fw.bin rebootstub.bin thermosphere.bin splash_screen.bmp \
- sept-primary.bin sept-secondary.enc emummc.kip \
+ sept-primary.bin sept-secondary_00.enc sept-secondary_01.enc emummc.kip \
$(KIPFILES)
#---------------------------------------------------------------------------------
@@ -198,22 +198,27 @@ fusee_primary.bin.o fusee_primary_bin.h: fusee-primary.bin
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@$(_bin2o)
-
+
sept_primary.bin.o sept_primary_bin.h: sept-primary.bin
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@$(_bin2o)
-
-sept_secondary.enc.o sept_secondary_enc.h: sept-secondary.enc
+
+sept_secondary_00.enc.o sept_secondary_00.h: sept-secondary_00.enc
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@$(_bin2o)
-
+
+sept_secondary_01.enc.o sept_secondary_01_enc.h: sept-secondary_01.enc
+#---------------------------------------------------------------------------------
+ @echo $(notdir $<)
+ @$(_bin2o)
+
%.bin.o %_bin.h: %.bin
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@$(bin2o)
-
+
%.bmp.o %_bmp.h: %.bmp
#---------------------------------------------------------------------------------
@echo $(notdir $<)
diff --git a/fusee/fusee-secondary/linker.ld b/fusee/fusee-secondary/linker.ld
index 26e8cc445..54a44b73d 100644
--- a/fusee/fusee-secondary/linker.ld
+++ b/fusee/fusee-secondary/linker.ld
@@ -55,7 +55,7 @@ SECTIONS
. = ALIGN(32);
PROVIDE (__chainloader_end__ = ABSOLUTE(.));
} >low_iram :NONE
-
+
.nxboot_loadable :
{
. = ALIGN(32);
@@ -157,7 +157,7 @@ SECTIONS
CONSTRUCTORS
. = ALIGN(32);
} >main
-
+
__data_end__ = ABSOLUTE(.);
PROVIDE (__total_size__ = (__data_end__ - __start__));
@@ -236,8 +236,10 @@ SECTIONS
PROVIDE(__rebootstub_bin_size__ = rebootstub_bin_end - rebootstub_bin);
PROVIDE(__sept_primary_bin_start__ = sept_primary_bin - __start__);
PROVIDE(__sept_primary_bin_size__ = sept_primary_bin_end - sept_primary_bin);
- PROVIDE(__sept_secondary_enc_start__ = sept_secondary_enc - __start__);
- PROVIDE(__sept_secondary_enc_size__ = sept_secondary_enc_end - sept_secondary_enc);
+ PROVIDE(__sept_secondary_00_enc_start__ = sept_secondary_00_enc - __start__);
+ PROVIDE(__sept_secondary_00_enc_size__ = sept_secondary_00_enc_end - sept_secondary_00_enc);
+ PROVIDE(__sept_secondary_01_enc_start__ = sept_secondary_01_enc - __start__);
+ PROVIDE(__sept_secondary_01_enc_size__ = sept_secondary_01_enc_end - sept_secondary_01_enc);
PROVIDE(__sm_kip_start__ = sm_kip - __start__);
PROVIDE(__sm_kip_size__ = sm_kip_end - sm_kip);
PROVIDE(__spl_kip_start__ = spl_kip - __start__);
diff --git a/fusee/fusee-secondary/src/emummc_cfg.h b/fusee/fusee-secondary/src/emummc_cfg.h
index 91d5bb515..77ab9fb8e 100644
--- a/fusee/fusee-secondary/src/emummc_cfg.h
+++ b/fusee/fusee-secondary/src/emummc_cfg.h
@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
-
+
#ifndef EXOSPHERE_EMUMMC_CONFIG_H
#define EXOSPHERE_EMUMMC_CONFIG_H
@@ -73,6 +73,9 @@ typedef enum {
FS_VER_8_0_0,
FS_VER_8_0_0_EXFAT,
+ FS_VER_8_1_0,
+ FS_VER_8_1_0_EXFAT,
+
FS_VER_MAX,
} emummc_fs_ver_t;
diff --git a/fusee/fusee-secondary/src/ips.c b/fusee/fusee-secondary/src/ips.c
index d94b31e5e..dedd00c67 100644
--- a/fusee/fusee-secondary/src/ips.c
+++ b/fusee/fusee-secondary/src/ips.c
@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
-
+
#include
#include
#include
@@ -46,7 +46,7 @@ static bool should_ignore_default_patch(const char *patch_dir) {
if (!g_enable_nogc_patches && strcmp(patch_dir, NOGC_PATCH_DIR) == 0) {
return true;
}
-
+
return false;
}
@@ -64,7 +64,7 @@ static bool has_patch(const char *dir, const char *subdir, const void *hash, siz
if (cur_len >= sizeof(path)) {
return false;
}
-
+
FILE *f = fopen(path, "rb");
if (f != NULL) {
fclose(f);
@@ -77,7 +77,7 @@ static bool has_needed_default_kip_patches(uint64_t title_id, const void *hash,
if (title_id == 0x0100000000000000ULL && g_enable_nogc_patches) {
return has_patch("atmosphere/kip_patches", NOGC_PATCH_DIR, hash, hash_size);
}
-
+
return true;
}
@@ -90,7 +90,7 @@ static void apply_ips_patch(uint8_t *mem, size_t mem_size, size_t prot_size, boo
} else if (!is_ips32 && memcmp(buffer, IPS_TAIL, 3) == 0) {
break;
}
-
+
/* Offset of patch. */
uint32_t patch_offset;
if (is_ips32) {
@@ -98,27 +98,27 @@ static void apply_ips_patch(uint8_t *mem, size_t mem_size, size_t prot_size, boo
} else {
patch_offset = (buffer[0] << 16) | (buffer[1] << 8) | (buffer[2]);
}
-
+
/* Size of patch. */
if (fread(buffer, 2, 1, f_ips) != 1) {
break;
}
uint32_t patch_size = (buffer[0] << 8) | (buffer[1]);
-
+
/* Check for RLE encoding. */
if (patch_size == 0) {
/* Size of RLE. */
if (fread(buffer, 2, 1, f_ips) != 1) {
break;
}
-
+
uint32_t rle_size = (buffer[0] << 8) | (buffer[1]);
-
+
/* Value for RLE. */
if (fread(buffer, 1, 1, f_ips) != 1) {
break;
}
-
+
if (patch_offset < prot_size) {
if (patch_offset + rle_size > prot_size) {
uint32_t diff = prot_size - patch_offset;
@@ -187,7 +187,7 @@ static bool name_matches_hash(const char *name, size_t name_len, const void *has
hash_from_name[id_ofs] |= hex_nybble_to_u8(name[name_ofs++]) << 4;
hash_from_name[id_ofs] |= hex_nybble_to_u8(name[name_ofs++]);
}
-
+
return memcmp(hash, hash_from_name, hash_size) == 0;
}
@@ -204,11 +204,11 @@ static bool has_ips_patches(const char *dir, const void *hash, size_t hash_size)
if (strcmp(pdir_ent->d_name, ".") == 0 || strcmp(pdir_ent->d_name, "..") == 0) {
continue;
}
-
+
if (should_ignore_default_patch(pdir_ent->d_name)) {
continue;
}
-
+
snprintf(path, sizeof(path) - 1, "%s/%s", dir, pdir_ent->d_name);
DIR *patch_dir = opendir(path);
struct dirent *ent;
@@ -218,7 +218,7 @@ static bool has_ips_patches(const char *dir, const void *hash, size_t hash_size)
if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) {
continue;
}
-
+
size_t name_len = strlen(ent->d_name);
if ((4 < name_len && name_len <= 0x44) && ((name_len & 1) == 0) && strcmp(ent->d_name + name_len - 4, ".ips") == 0 && name_matches_hash(ent->d_name, name_len, hash, hash_size)) {
snprintf(path, sizeof(path) - 1, "%s/%s/%s", dir, pdir_ent->d_name, ent->d_name);
@@ -254,11 +254,11 @@ static void apply_ips_patches(const char *dir, void *mem, size_t mem_size, size_
if (strcmp(pdir_ent->d_name, ".") == 0 || strcmp(pdir_ent->d_name, "..") == 0) {
continue;
}
-
+
if (should_ignore_default_patch(pdir_ent->d_name)) {
continue;
}
-
+
snprintf(path, sizeof(path) - 1, "%s/%s", dir, pdir_ent->d_name);
DIR *patch_dir = opendir(path);
struct dirent *ent;
@@ -268,7 +268,7 @@ static void apply_ips_patches(const char *dir, void *mem, size_t mem_size, size_
if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) {
continue;
}
-
+
size_t name_len = strlen(ent->d_name);
if ((4 < name_len && name_len <= 0x44) && ((name_len & 1) == 0) && strcmp(ent->d_name + name_len - 4, ".ips") == 0 && name_matches_hash(ent->d_name, name_len, hash, hash_size)) {
snprintf(path, sizeof(path) - 1, "%s/%s/%s", dir, pdir_ent->d_name, ent->d_name);
@@ -291,7 +291,7 @@ static void apply_ips_patches(const char *dir, void *mem, size_t mem_size, size_
}
closedir(patches_dir);
}
-}
+}
void apply_kernel_ips_patches(void *kernel, size_t kernel_size) {
uint8_t hash[0x20];
@@ -304,16 +304,16 @@ static void kip1_blz_uncompress(void *hdr_end) {
uint32_t addl_size = ((u8_hdr_end[-4]) << 0) | ((u8_hdr_end[-3]) << 8) | ((u8_hdr_end[-2]) << 16) | ((u8_hdr_end[-1]) << 24);
uint32_t header_size = ((u8_hdr_end[-8]) << 0) | ((u8_hdr_end[-7]) << 8) | ((u8_hdr_end[-6]) << 16) | ((u8_hdr_end[-5]) << 24);
uint32_t cmp_and_hdr_size = ((u8_hdr_end[-12]) << 0) | ((u8_hdr_end[-11]) << 8) | ((u8_hdr_end[-10]) << 16) | ((u8_hdr_end[-9]) << 24);
-
+
unsigned char *cmp_start = (unsigned char *)(((uintptr_t)hdr_end) - cmp_and_hdr_size);
uint32_t cmp_ofs = cmp_and_hdr_size - header_size;
uint32_t out_ofs = cmp_and_hdr_size + addl_size;
-
+
while (out_ofs) {
unsigned char control = cmp_start[--cmp_ofs];
for (unsigned int i = 0; i < 8; i++) {
if (control & 0x80) {
- if (cmp_ofs < 2) {
+ if (cmp_ofs < 2) {
fatal_error("KIP1 decompression out of bounds!\n");
}
cmp_ofs -= 2;
@@ -325,7 +325,7 @@ static void kip1_blz_uncompress(void *hdr_end) {
seg_size = out_ofs;
}
out_ofs -= seg_size;
-
+
for (unsigned int j = 0; j < seg_size; j++) {
cmp_start[out_ofs + j] = cmp_start[out_ofs + j + seg_ofs];
}
@@ -350,15 +350,15 @@ kip1_header_t *kip1_uncompress(kip1_header_t *kip, size_t *size) {
new_header.section_headers[i].compressed_size = new_header.section_headers[i].out_size;
}
new_header.flags &= 0xF8;
-
+
*size = kip1_get_size_from_header(&new_header);
-
+
unsigned char *new_kip = calloc(1, *size);
if (new_kip == NULL) {
return NULL;
}
*((kip1_header_t *)new_kip) = new_header;
-
+
size_t new_offset = 0x100;
size_t old_offset = 0x100;
for (unsigned int i = 0; i < 3; i++) {
@@ -369,7 +369,7 @@ kip1_header_t *kip1_uncompress(kip1_header_t *kip, size_t *size) {
new_offset += kip->section_headers[i].out_size;
old_offset += kip->section_headers[i].compressed_size;
}
-
+
return (kip1_header_t *)new_kip;
}
@@ -408,12 +408,15 @@ static const uint8_t g_fs_hashes[FS_VER_MAX][0x8] = {
"\xB2\xF5\x17\x6B\x35\x48\x36\x4D", /* FS_VER_8_0_0 */
"\xDB\xD9\x41\xC0\xC5\x3C\x52\xCC", /* FS_VER_8_0_0_EXFAT */
+
+ "\x6B\x09\xB6\x7B\x29\xC0\x20\x24", /* FS_VER_8_1_0 */
+ "\xB4\xCA\xE1\xF2\x49\x65\xD9\x2E", /* FS_VER_8_1_0_EXFAT */
};
kip1_header_t *apply_kip_ips_patches(kip1_header_t *kip, size_t kip_size, emummc_fs_ver_t *out_fs_ver) {
uint8_t hash[0x20];
se_calculate_sha256(hash, kip, kip_size);
-
+
if (kip->title_id == FS_TITLE_ID) {
bool found = false;
for (size_t i = 0; i < FS_VER_MAX; i++) {
@@ -426,24 +429,24 @@ kip1_header_t *apply_kip_ips_patches(kip1_header_t *kip, size_t kip_size, emummc
fatal_error("[NXBOOT]: Failed to identify FS version...");
}
}
-
+
if (!has_needed_default_kip_patches(kip->title_id, hash, sizeof(hash))) {
fatal_error("[NXBOOT]: Missing default patch for KIP %08x%08x...\n", (uint32_t)(kip->title_id >> 32), (uint32_t)kip->title_id);
}
-
+
if (!has_ips_patches("atmosphere/kip_patches", hash, sizeof(hash))) {
return NULL;
}
print(SCREEN_LOG_LEVEL_MANDATORY, "[NXBOOT]: Patching KIP %08x%08x...\n", (uint32_t)(kip->title_id >> 32), (uint32_t)kip->title_id);
-
-
+
+
size_t uncompressed_kip_size;
kip1_header_t *uncompressed_kip = kip1_uncompress(kip, &uncompressed_kip_size);
- if (uncompressed_kip == NULL) {
+ if (uncompressed_kip == NULL) {
return NULL;
}
-
+
apply_ips_patches("atmosphere/kip_patches", uncompressed_kip, uncompressed_kip_size, 0x100, hash, sizeof(hash));
return uncompressed_kip;
}
diff --git a/fusee/fusee-secondary/src/key_derivation.c b/fusee/fusee-secondary/src/key_derivation.c
index 2a13a7c2c..d4de912be 100644
--- a/fusee/fusee-secondary/src/key_derivation.c
+++ b/fusee/fusee-secondary/src/key_derivation.c
@@ -54,7 +54,8 @@ 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[MASTERKEY_REVISION_700_CURRENT - MASTERKEY_REVISION_600_610][0x10] = {
+/* TODO: Bother adding 8.1.0 here? We'll never call into here... */
+static const uint8_t AL16 new_master_kek_seeds[MASTERKEY_REVISION_700_800 - 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. */
};
@@ -93,17 +94,17 @@ static int decrypt_keyblob(const nx_keyblob_t *keyblobs, uint32_t revision, uint
if (get_keyblob(&keyblob, revision, keyblobs, available_revision) != 0) {
return -1;
}
-
+
se_aes_ecb_decrypt_block(0xD, work_buffer, 0x10, keyblob_seeds[revision], 0x10);
decrypt_data_into_keyslot(keyslot, 0xE, work_buffer, 0x10);
decrypt_data_into_keyslot(0xB, keyslot, keyblob_mac_seed, 0x10);
-
+
/* Validate keyblob. */
se_compute_aes_128_cmac(0xB, work_buffer, 0x10, keyblob.mac + sizeof(keyblob.mac), sizeof(keyblob) - sizeof(keyblob.mac));
if (safe_memcmp(keyblob.mac, work_buffer, 0x10)) {
return -1;
}
-
+
/* Decrypt keyblob. */
se_aes_ctr_crypt(keyslot, &g_dec_keyblobs[revision], sizeof(g_dec_keyblobs[revision]), keyblob.data, sizeof(keyblob.data), keyblob.ctr, sizeof(keyblob.ctr));
return 0;
@@ -113,7 +114,7 @@ int load_package1_key(uint32_t revision) {
if (revision > MASTERKEY_REVISION_600_610) {
return -1;
}
-
+
set_aes_keyslot(0xB, g_dec_keyblobs[revision].package1_key, 0x10);
return 0;
}
@@ -122,17 +123,17 @@ int load_package1_key(uint32_t revision) {
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};
-
+
/* Initialize keygen type. */
*out_keygen_type = 0;
/* TODO: Set keyslot flags properly in preparation of derivation. */
set_aes_keyslot_flags(0xE, 0x15);
set_aes_keyslot_flags(0xD, 0x15);
-
+
/* Set the TSEC key. */
set_aes_keyslot(0xD, tsec_key, 0x10);
-
+
/* Decrypt all keyblobs, setting keyslot 0xF correctly. */
for (unsigned int rev = 0; rev <= MASTERKEY_REVISION_600_610; rev++) {
int ret = decrypt_keyblob(keyblobs, rev, available_revision);
@@ -150,13 +151,16 @@ int derive_nx_keydata(uint32_t target_firmware, const nx_keyblob_t *keyblobs, ui
break;
case ATMOSPHERE_TARGET_FIRMWARE_700:
case ATMOSPHERE_TARGET_FIRMWARE_800:
- desired_keyblob = MASTERKEY_REVISION_700_CURRENT;
+ desired_keyblob = MASTERKEY_REVISION_700_800;
+ break;
+ case ATMOSPHERE_TARGET_FIRMWARE_810:
+ desired_keyblob = MASTERKEY_REVISION_810_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));
@@ -167,7 +171,7 @@ int derive_nx_keydata(uint32_t target_firmware, const nx_keyblob_t *keyblobs, ui
memcpy(g_dec_keyblobs[rev].master_kek, work_buffer, 0x10);
}
}
-
+
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";
@@ -188,13 +192,13 @@ int derive_nx_keydata(uint32_t target_firmware, const nx_keyblob_t *keyblobs, ui
}
}
}
-
-
+
+
if (memcmp(g_dec_keyblobs[available_revision].master_kek, zeroes, 0x10) == 0) {
fatal_error("Error: failed to derive master_kek_%02x!", available_revision);
}
}
-
+
/* Clear the SBK. */
clear_aes_keyslot(0xE);
@@ -225,6 +229,7 @@ int derive_nx_keydata(uint32_t target_firmware, const nx_keyblob_t *keyblobs, ui
case ATMOSPHERE_TARGET_FIRMWARE_620:
case ATMOSPHERE_TARGET_FIRMWARE_700:
case ATMOSPHERE_TARGET_FIRMWARE_800:
+ case ATMOSPHERE_TARGET_FIRMWARE_810:
decrypt_data_into_keyslot(0xA, 0xF, devicekey_4x_seed, 0x10);
decrypt_data_into_keyslot(0xF, 0xF, devicekey_seed, 0x10);
decrypt_data_into_keyslot(0xE, 0xC, masterkey_4x_seed, 0x10);
diff --git a/fusee/fusee-secondary/src/masterkey.c b/fusee/fusee-secondary/src/masterkey.c
index 28b6e3ee4..d2c5a06e7 100644
--- a/fusee/fusee-secondary/src/masterkey.c
+++ b/fusee/fusee-secondary/src/masterkey.c
@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
-
+
#include
#include
#include
@@ -39,6 +39,7 @@ static const uint8_t mkey_vectors_dev[MASTERKEY_REVISION_MAX][0x10] =
{0x78, 0xD5, 0xF1, 0x20, 0x3D, 0x16, 0xE9, 0x30, 0x32, 0x27, 0x34, 0x6F, 0xCF, 0xE0, 0x27, 0xDC}, /* Master key 04 encrypted with Master key 05. */
{0x6F, 0xD2, 0x84, 0x1D, 0x05, 0xEC, 0x40, 0x94, 0x5F, 0x18, 0xB3, 0x81, 0x09, 0x98, 0x8D, 0x4E}, /* Master key 05 encrypted with Master key 06. */
{0x37, 0xAF, 0xAB, 0x35, 0x79, 0x09, 0xD9, 0x48, 0x29, 0xD2, 0xDB, 0xA5, 0xA5, 0xF5, 0x30, 0x19}, /* Master key 06 encrypted with Master key 07. */
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* TODO: Master key 07 encrypted with Master key 08. */
};
/* Retail unit keys. */
@@ -52,6 +53,7 @@ static const uint8_t mkey_vectors[MASTERKEY_REVISION_MAX][0x10] =
{0xEB, 0xF5, 0x6F, 0x83, 0x61, 0x9E, 0xF8, 0xFA, 0xE0, 0x87, 0xD7, 0xA1, 0x4E, 0x25, 0x36, 0xEE}, /* Master key 04 encrypted with Master key 05. */
{0x1E, 0x1E, 0x22, 0xC0, 0x5A, 0x33, 0x3C, 0xB9, 0x0B, 0xA9, 0x03, 0x04, 0xBA, 0xDB, 0x07, 0x57}, /* Master key 05 encrypted with Master key 06. */
{0xA4, 0xD4, 0x52, 0x6F, 0xD1, 0xE4, 0x36, 0xAA, 0x9F, 0xCB, 0x61, 0x27, 0x1C, 0x67, 0x65, 0x1F}, /* Master key 06 encrypted with Master key 07. */
+ {0xEA, 0x60, 0xB3, 0xEA, 0xCE, 0x8F, 0x24, 0x46, 0x7D, 0x33, 0x9C, 0xD1, 0xBC, 0x24, 0x98, 0x29}, /* Master key 07 encrypted with Master key 08. */
};
static bool check_mkey_revision(unsigned int revision, bool is_retail) {
@@ -80,7 +82,7 @@ int mkey_detect_revision(bool is_retail) {
if (g_determined_mkey_revision) {
generic_panic();
}
-
+
for (unsigned int rev = 0; rev < MASTERKEY_REVISION_MAX; rev++) {
if (check_mkey_revision(rev, is_retail)) {
g_determined_mkey_revision = true;
@@ -88,7 +90,7 @@ int mkey_detect_revision(bool is_retail) {
break;
}
}
-
+
/* We must have determined the master key, or we're not running on a Switch. */
if (!g_determined_mkey_revision) {
return -1;
diff --git a/fusee/fusee-secondary/src/masterkey.h b/fusee/fusee-secondary/src/masterkey.h
index 332dbcec5..0ee44eca4 100644
--- a/fusee/fusee-secondary/src/masterkey.h
+++ b/fusee/fusee-secondary/src/masterkey.h
@@ -13,14 +13,14 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
-
+
#ifndef FUSEE_MASTERKEY_H
#define FUSEE_MASTERKEY_H
/* 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 0x8
+/* TODO: Update to 0xA on release of new master key. */
+#define MASTERKEY_REVISION_MAX 0x9
#define MASTERKEY_REVISION_100_230 0x00
#define MASTERKEY_REVISION_300 0x01
@@ -29,7 +29,8 @@
#define MASTERKEY_REVISION_500_510 0x04
#define MASTERKEY_REVISION_600_610 0x05
#define MASTERKEY_REVISION_620 0x06
-#define MASTERKEY_REVISION_700_CURRENT 0x07
+#define MASTERKEY_REVISION_700_800 0x07
+#define MASTERKEY_REVISION_810_CURRENT 0x08
#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 cc7f1cacd..2146a7062 100644
--- a/fusee/fusee-secondary/src/nxboot.c
+++ b/fusee/fusee-secondary/src/nxboot.c
@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
-
+
#include
#include
#include
@@ -53,7 +53,8 @@
#define u8 uint8_t
#define u32 uint32_t
#include "exosphere_bin.h"
-#include "sept_secondary_enc.h"
+#include "sept_secondary_00_enc.h"
+#include "sept_secondary_01_enc.h"
#include "lp0fw_bin.h"
#include "emummc_kip.h"
#include "lib/log.h"
@@ -207,8 +208,15 @@ static uint32_t nxboot_get_target_firmware(const void *package1loader) {
}
case 0x0F: /* 7.0.0 - 7.0.1 */
return ATMOSPHERE_TARGET_FIRMWARE_700;
- case 0x10: /* 8.0.0 */
- return ATMOSPHERE_TARGET_FIRMWARE_800;
+ case 0x10: { /* 8.0.0 - 8.1.0 */
+ if (memcmp(package1loader_header->build_timestamp, "20190314", 8) == 0) {
+ return ATMOSPHERE_TARGET_FIRMWARE_800;
+ } else if (memcmp(package1loader_header->build_timestamp, "20190531", 8) == 0) {
+ return ATMOSPHERE_TARGET_FIRMWARE_810;
+ } else {
+ fatal_error("[NXBOOT] Unable to identify package1!\n");
+ }
+ }
default:
fatal_error("[NXBOOT] Unable to identify package1!\n");
}
@@ -216,7 +224,7 @@ static uint32_t nxboot_get_target_firmware(const void *package1loader) {
static bool nxboot_configure_emummc(exo_emummc_config_t *exo_emummc_config) {
emummc_config_t emummc_cfg = {.enabled = false, .id = 0, .sector = -1, .path = "", .nintendo_path = ""};
-
+
char *emummc_ini = calloc(1, 0x10000);
if (!read_from_file(emummc_ini, 0xFFFF, "emummc/emummc.ini")) {
free(emummc_ini);
@@ -237,12 +245,12 @@ static bool nxboot_configure_emummc(exo_emummc_config_t *exo_emummc_config) {
exo_emummc_config->base_cfg.fs_version = FS_VER_1_0_0; /* Will be filled out later. */
strncpy(exo_emummc_config->emu_dir_path, emummc_cfg.nintendo_path, sizeof(exo_emummc_config->emu_dir_path));
exo_emummc_config->emu_dir_path[sizeof(exo_emummc_config->emu_dir_path) - 1] = '\0';
-
+
if (emummc_cfg.enabled) {
if (emummc_cfg.sector != -1) {
exo_emummc_config->base_cfg.type = EMUMMC_TYPE_PARTITION;
exo_emummc_config->partition_cfg.start_sector = emummc_cfg.sector;
-
+
/* Mount emulated NAND from SD card partition. */
if (nxfs_mount_emummc_partition(emummc_cfg.sector) < 0) {
fatal_error("[NXBOOT] Failed to mount EmuMMC from SD card partition!\n");
@@ -258,24 +266,24 @@ static bool nxboot_configure_emummc(exo_emummc_config_t *exo_emummc_config) {
char emummc_boot0_path[0x300 + 1] = {0};
char emummc_boot1_path[0x300 + 1] = {0};
char emummc_rawnand_path[0x300 + 1] = {0};
-
+
/* Prepare base folder path. */
snprintf(emummc_path, sizeof(emummc_path) - 1, "%s/%s", emummc_cfg.path, "eMMC");
-
+
/* Check if eMMC folder is present. */
if (!is_valid_folder(emummc_path)) {
fatal_error("[NXBOOT] Failed to find EmuMMC eMMC folder!\n");
}
-
+
/* Prepare expected file paths. */
snprintf(emummc_boot0_path, sizeof(emummc_boot0_path) - 1, "%s/%s", emummc_path, "boot0");
snprintf(emummc_boot1_path, sizeof(emummc_boot1_path) - 1, "%s/%s", emummc_path, "boot1");
-
+
/* Check if boot0 and boot1 image files are present. */
if (!is_valid_file(emummc_boot0_path) || !is_valid_file(emummc_boot1_path)) {
fatal_error("[NXBOOT] Failed to find EmuMMC boot0/boot1 image files!\n");
}
-
+
/* Find raw image files (single or multi part). */
for (int i = 0; i < 64; i++) {
snprintf(emummc_rawnand_path, sizeof(emummc_rawnand_path) - 1, "%s/%02d", emummc_path, i);
@@ -295,7 +303,7 @@ static bool nxboot_configure_emummc(exo_emummc_config_t *exo_emummc_config) {
if ((num_parts == 0) || (part_limit == 0)) {
fatal_error("[NXBOOT] Failed to find EmuMMC raw image files!\n");
}
-
+
/* Mount emulated NAND from files. */
if (nxfs_mount_emummc_file(emummc_path, num_parts, part_limit) < 0) {
fatal_error("[NXBOOT] Failed to mount EmuMMC from files!\n");
@@ -304,7 +312,7 @@ static bool nxboot_configure_emummc(exo_emummc_config_t *exo_emummc_config) {
fatal_error("[NXBOOT] Invalid EmuMMC setting!\n");
}
}
-
+
return emummc_cfg.enabled;
}
@@ -337,7 +345,7 @@ static void nxboot_configure_stratosphere(uint32_t target_firmware) {
if (ini_parse_string(get_loader_ctx()->bct0, stratosphere_ini_handler, &strat_cfg) < 0) {
fatal_error("[NXBOOT] Failed to parse BCT.ini!\n");
}
-
+
/* Enable NOGC patches if the user requested it, or if the user is booting into 4.0.0+ with 3.0.2- fuses. */
if (strat_cfg.has_nogc_config) {
if (strat_cfg.enable_nogc) {
@@ -353,7 +361,7 @@ static void nxboot_configure_stratosphere(uint32_t target_firmware) {
static void nxboot_set_bootreason(void *bootreason_base) {
boot_reason_t boot_reason = {0};
- FILE *boot0;
+ FILE *boot0;
nvboot_config_table *bct;
nv_bootloader_info *bootloader_info;
@@ -362,7 +370,7 @@ static void nxboot_set_bootreason(void *bootreason_base) {
if (bct == NULL) {
fatal_error("[NXBOOT] Out of memory!\n");
}
-
+
/* Open boot0. */
boot0 = fopen("boot0:/", "rb");
if (boot0 == NULL) {
@@ -373,25 +381,25 @@ static void nxboot_set_bootreason(void *bootreason_base) {
if (fread(bct, sizeof(nvboot_config_table), 1, boot0) == 0) {
fatal_error("[NXBOOT] Failed to read the BCT!\n");
}
-
+
/* Close boot0. */
fclose(boot0);
-
+
/* Populate bootloader parameters. */
bootloader_info = &bct->bootloader[0];
boot_reason.bootloader_version = bootloader_info->version;
boot_reason.bootloader_start_block = bootloader_info->start_blk;
boot_reason.bootloader_start_page = bootloader_info->start_page;
boot_reason.bootloader_attribute = bootloader_info->attribute;
-
+
uint8_t power_key_intr = 0;
uint8_t rtc_intr = 0;
i2c_query(I2C_5, MAX77620_PWR_I2C_ADDR, MAX77620_REG_ONOFFIRQ, &power_key_intr, 1);
i2c_query(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_REG_RTCINT, &rtc_intr, 1);
-
+
/* Set PMIC value. */
boot_reason.boot_reason_value = ((rtc_intr << 0x08) | power_key_intr);
-
+
/* TODO: Find out what these mean. */
if (power_key_intr & 0x80)
boot_reason.boot_reason_state = 0x01;
@@ -401,10 +409,10 @@ static void nxboot_set_bootreason(void *bootreason_base) {
boot_reason.boot_reason_state = 0x03;
else if (rtc_intr & 0x04)
boot_reason.boot_reason_state = 0x04;
-
+
/* Set in memory. */
memcpy(bootreason_base, &boot_reason, sizeof(boot_reason));
-
+
/* Clean up. */
free(bct);
}
@@ -414,13 +422,13 @@ static void nxboot_move_bootconfig() {
void *bootconfig;
uint32_t bootconfig_addr;
uint32_t bootconfig_size;
-
+
/* Allocate memory for reading BootConfig. */
bootconfig = memalign(0x1000, 0x4000);
if (bootconfig == NULL) {
fatal_error("[NXBOOT] Out of memory!\n");
}
-
+
/* Get BootConfig from the Package2 partition. */
bcfile = fopen("bcpkg21:/", "rb");
if (bcfile == NULL) {
@@ -431,15 +439,15 @@ static void nxboot_move_bootconfig() {
fatal_error("[NXBOOT] Failed to read BootConfig!\n");
}
fclose(bcfile);
-
+
/* Select the actual BootConfig size and destination address. */
bootconfig_addr = (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware < ATMOSPHERE_TARGET_FIRMWARE_600) ? 0x4003D000 : 0x4003F800;
bootconfig_size = (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware < ATMOSPHERE_TARGET_FIRMWARE_400) ? 0x3000 : 0x1000;
-
+
/* Copy the BootConfig into IRAM. */
memset((void *)bootconfig_addr, 0, bootconfig_size);
memcpy((void *)bootconfig_addr, bootconfig, bootconfig_size);
-
+
/* Clean up. */
free(bootconfig);
}
@@ -459,6 +467,8 @@ uint32_t nxboot_main(void) {
size_t package2_size;
void *tsec_fw;
size_t tsec_fw_size;
+ const void *sept_secondary_enc = NULL;
+ size_t sept_secondary_enc_size = 0;
void *warmboot_fw;
size_t warmboot_fw_size;
void *warmboot_memaddr;
@@ -470,7 +480,7 @@ uint32_t nxboot_main(void) {
FILE *boot0, *pk2file;
void *exosphere_memaddr;
exo_emummc_config_t exo_emummc_cfg;
-
+
/* Configure emummc or mount the real NAND. */
if (!nxboot_configure_emummc(&exo_emummc_cfg)) {
emummc = NULL;
@@ -542,7 +552,7 @@ uint32_t nxboot_main(void) {
fatal_error("[NXBOOT] Failed to read Package2!\n");
}
fclose(pk2file);
-
+
/* Read and parse boot0. */
print(SCREEN_LOG_LEVEL_INFO, "[NXBOOT] Reading boot0...\n");
boot0 = fopen("boot0:/", "rb");
@@ -550,7 +560,7 @@ uint32_t nxboot_main(void) {
fatal_error("[NXBOOT] Couldn't parse boot0: %s!\n", strerror(errno));
}
fclose(boot0);
-
+
/* Find the system's target firmware. */
uint32_t target_firmware = nxboot_get_target_firmware(package1loader);
if (!target_firmware)
@@ -561,26 +571,42 @@ uint32_t nxboot_main(void) {
/* Read the TSEC firmware from a file, otherwise from PK1L. */
if (loader_ctx->tsecfw_path[0] != '\0') {
tsec_fw_size = get_file_size(loader_ctx->tsecfw_path);
- if ((tsec_fw_size != 0) && (tsec_fw_size != 0xF00 && tsec_fw_size != 0x2900 && tsec_fw_size != 0x3000)) {
+ if ((tsec_fw_size != 0) && (tsec_fw_size != 0xF00 && tsec_fw_size != 0x2900 && tsec_fw_size != 0x3000 && tsec_fw_size != 0x3300)) {
fatal_error("[NXBOOT] TSEC firmware from %s has a wrong size!\n", loader_ctx->tsecfw_path);
} else if (tsec_fw_size == 0) {
fatal_error("[NXBOOT] Could not read the TSEC firmware from %s!\n", loader_ctx->tsecfw_path);
}
-
+
/* Allocate memory for the TSEC firmware. */
tsec_fw = memalign(0x100, tsec_fw_size);
-
+
if (tsec_fw == NULL) {
fatal_error("[NXBOOT] Out of memory!\n");
}
if (read_from_file(tsec_fw, tsec_fw_size, loader_ctx->tsecfw_path) != tsec_fw_size) {
fatal_error("[NXBOOT] Could not read the TSEC firmware from %s!\n", loader_ctx->tsecfw_path);
}
+
+ if (tsec_fw_size == 0x3000) {
+ sept_secondary_enc = sept_secondary_00_enc;
+ sept_secondary_enc_size = sept_secondary_00_enc_size;
+ } else if (tsec_fw_size == 0x3300) {
+ sept_secondary_enc = sept_secondary_01_enc;
+ sept_secondary_enc_size = sept_secondary_01_enc_size;
+ } else {
+ fatal_error("[NXBOOT] Unable to identify sept revision to run.");
+ }
} else {
if (!package1_get_tsec_fw(&tsec_fw, package1loader, package1loader_size)) {
fatal_error("[NXBOOT] Failed to read the TSEC firmware from Package1loader!\n");
}
- if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_700) {
+ if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_810) {
+ sept_secondary_enc = sept_secondary_01_enc;
+ sept_secondary_enc_size = sept_secondary_01_enc_size;
+ tsec_fw_size = 0x3300;
+ } else if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_700) {
+ sept_secondary_enc = sept_secondary_00_enc;
+ sept_secondary_enc_size = sept_secondary_00_enc_size;
tsec_fw_size = 0x3000;
} else if (target_firmware == ATMOSPHERE_TARGET_FIRMWARE_620) {
tsec_fw_size = 0x2900;
@@ -606,10 +632,10 @@ uint32_t nxboot_main(void) {
get_and_clear_has_run_sept();
} else if (target_firmware == ATMOSPHERE_TARGET_FIRMWARE_620) {
uint8_t tsec_keys[0x20] = {0};
-
+
/* Emulate the TSEC payload on 6.2.0+. */
smmu_emulate_tsec((void *)tsec_keys, package1loader, package1loader_size, package1loader);
-
+
/* Copy back the keys. */
memcpy((void *)tsec_key, (void *)tsec_keys, 0x10);
memcpy((void *)tsec_root_keys, (void *)tsec_keys + 0x10, 0x10);
@@ -619,11 +645,11 @@ uint32_t nxboot_main(void) {
fatal_error("[NXBOOT] Failed to get TSEC key!\n");
}
}
-
+
//fatal_error("Ran sept!");
/* Display splash screen. */
display_splash_screen_bmp(loader_ctx->custom_splash_path, (void *)0xC0000000);
-
+
/* Derive keydata. If on 7.0.0+, sept has already derived keys for us. */
unsigned int keygen_type = 0;
if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_700) {
@@ -665,27 +691,27 @@ uint32_t nxboot_main(void) {
if (warmboot_fw == NULL) {
fatal_error("[NXBOOT] Out of memory!\n");
}
-
+
memcpy(warmboot_fw, lp0fw_bin, warmboot_fw_size);
-
+
if (warmboot_fw_size == 0) {
fatal_error("[NXBOOT] Could not read the warmboot firmware from Package1!\n");
}
}
-
+
/* Patch warmboot firmware for atmosphere. */
if (warmboot_fw != NULL && warmboot_fw_size >= sizeof(warmboot_ams_header_t)) {
warmboot_ams_header_t *ams_header = (warmboot_ams_header_t *)warmboot_fw;
if (ams_header->ams_metadata.magic == WARMBOOT_MAGIC) {
/* Set target firmware */
ams_header->ams_metadata.target_firmware = target_firmware;
-
+
/* Set RSA modulus */
const uint8_t *pkc_modulus = fuse_get_retail_type() != 0 ? retail_pkc_modulus : dev_pkc_modulus;
memcpy(ams_header->rsa_modulus, pkc_modulus, sizeof(ams_header->rsa_modulus));
}
}
-
+
/* Select the right address for the warmboot firmware. */
if (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware < ATMOSPHERE_TARGET_FIRMWARE_400) {
@@ -708,7 +734,7 @@ uint32_t nxboot_main(void) {
}
print(SCREEN_LOG_LEVEL_INFO, "[NXBOOT] Rebuilding package2...\n");
-
+
/* Parse stratosphere config. */
nxboot_configure_stratosphere(MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware);
@@ -770,10 +796,10 @@ uint32_t nxboot_main(void) {
free(package2);
print(SCREEN_LOG_LEVEL_INFO, "[NXBOOT] Powering on the CCPLEX...\n");
-
+
/* Unmount everything. */
nxfs_end();
-
+
/* Return the memory address for booting CPU0. */
return (uint32_t)exosphere_memaddr;
}
diff --git a/fusee/fusee-secondary/src/package2.c b/fusee/fusee-secondary/src/package2.c
index de7af5b70..d9bd92ddc 100644
--- a/fusee/fusee-secondary/src/package2.c
+++ b/fusee/fusee-secondary/src/package2.c
@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
-
+
#include
#include
#include
@@ -66,7 +66,7 @@ void package2_rebuild_and_copy(package2_header_t *package2, uint32_t target_firm
if (thermosphere_size != 0 && package2->metadata.section_sizes[PACKAGE2_SECTION_UNUSED] != 0) {
fatal_error(u8"Error: Package2 has no unused section for Thermosphère!\n");
}
-
+
/* Load Kernel from SD, if possible. */
{
size_t sd_kernel_size = get_file_size("atmosphere/kernel.bin");
@@ -88,13 +88,13 @@ void package2_rebuild_and_copy(package2_header_t *package2, uint32_t target_firm
/* Perform any patches we want to the NX kernel. */
package2_patch_kernel(kernel, kernel_size, is_sd_kernel, (void *)&orig_ini1);
-
+
/* Ensure we know where embedded INI is if present, and we don't if not. */
- if ((target_firmware < ATMOSPHERE_TARGET_FIRMWARE_800 && orig_ini1 != NULL) ||
+ if ((target_firmware < ATMOSPHERE_TARGET_FIRMWARE_800 && orig_ini1 != NULL) ||
(target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_800 && orig_ini1 == NULL)) {
fatal_error("Error: inappropriate kernel embedded ini context");
}
-
+
print(SCREEN_LOG_LEVEL_DEBUG, "Rebuilding the INI1 section...\n");
if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_800) {
package2_get_src_section((void *)&orig_ini1, package2, PACKAGE2_SECTION_INI1);
@@ -232,7 +232,7 @@ static bool package2_validate_metadata(package2_meta_t *metadata, uint8_t data[]
/* Perform version checks. */
/* We will be compatible with all package2s released before current, but not newer ones. */
- if (metadata->version_max >= PACKAGE2_MINVER_THEORETICAL && metadata->version_min < PACKAGE2_MAXVER_700_CURRENT) {
+ if (metadata->version_max >= PACKAGE2_MINVER_THEORETICAL && metadata->version_min < PACKAGE2_MAXVER_810_CURRENT) {
return true;
}
diff --git a/fusee/fusee-secondary/src/package2.h b/fusee/fusee-secondary/src/package2.h
index 1b3d6d492..7427ce85c 100644
--- a/fusee/fusee-secondary/src/package2.h
+++ b/fusee/fusee-secondary/src/package2.h
@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
-
+
#ifndef FUSEE_PACKAGE2_H
#define FUSEE_PACKAGE2_H
@@ -36,7 +36,8 @@
#define PACKAGE2_MAXVER_500_510 0x7
#define PACKAGE2_MAXVER_600_610 0x8
#define PACKAGE2_MAXVER_620 0x9
-#define PACKAGE2_MAXVER_700_CURRENT 0xA
+#define PACKAGE2_MAXVER_700_800 0xA
+#define PACKAGE2_MAXVER_810_CURRENT 0xB
#define PACKAGE2_MINVER_100 0x3
#define PACKAGE2_MINVER_200 0x4
@@ -46,7 +47,8 @@
#define PACKAGE2_MINVER_500_510 0x8
#define PACKAGE2_MINVER_600_610 0x9
#define PACKAGE2_MINVER_620 0xA
-#define PACKAGE2_MINVER_700_CURRENT 0xB
+#define PACKAGE2_MINVER_700_800 0xB
+#define PACKAGE2_MINVER_810_CURRENT 0xC
#define NX_BOOTLOADER_PACKAGE2_LOAD_ADDRESS ((void *)(0xA9800000ull))
@@ -79,7 +81,7 @@ typedef struct {
/* Package2 can be encrypted or unencrypted for these functions: */
static inline size_t package2_meta_get_size(const package2_meta_t *metadata) {
- return metadata->ctr_dwords[0] ^ metadata->ctr_dwords[2] ^ metadata->ctr_dwords[3];
+ return metadata->ctr_dwords[0] ^ metadata->ctr_dwords[2] ^ metadata->ctr_dwords[3];
}
static inline uint8_t package2_meta_get_header_version(const package2_meta_t *metadata) {
diff --git a/fusee/fusee-secondary/src/start.s b/fusee/fusee-secondary/src/start.s
index f6da2a185..c93b588b1 100644
--- a/fusee/fusee-secondary/src/start.s
+++ b/fusee/fusee-secondary/src/start.s
@@ -14,7 +14,7 @@
* along with this program. If not, see .
*/
#include
-
+
.macro CLEAR_GPR_REG_ITER
mov r\@, #0
.endm
@@ -27,7 +27,7 @@
.type _start, %function
_start:
b _crt0
-
+
.word (_metadata - _start)
_crt0:
@@ -67,7 +67,7 @@ _crt0:
ldr r0, [r0]
ldr r1, [r1]
b main
-
+
/* Fusee-secondary header. */
.align 5
_metadata:
@@ -168,12 +168,20 @@ _content_headers:
.asciz "sept_primary"
.align 5
-/* sept_secondary content header */
-.word __sept_secondary_enc_start__
-.word __sept_secondary_enc_size__
+/* sept_secondary 00 content header */
+.word __sept_secondary_00_enc_start__
+.word __sept_secondary_00_enc_size__
.word CONTENT_TYPE_SP2
.word 0xCCCCCCCC
-.asciz "sept_secondary"
+.asciz "sept_secondary_00"
+.align 5
+
+/* sept_secondary 01 content header */
+.word __sept_secondary_01_enc_start__
+.word __sept_secondary_01_enc_size__
+.word CONTENT_TYPE_SP2
+.word 0xCCCCCCCC
+.asciz "sept_secondary_01"
.align 5
/* sm content header */
diff --git a/sept/sept-secondary/KEYS_template.py b/sept/sept-secondary/KEYS_template.py
index 38cdcb0c4..dd3bb7b91 100644
--- a/sept/sept-secondary/KEYS_template.py
+++ b/sept/sept-secondary/KEYS_template.py
@@ -1,7 +1,20 @@
-HOVI_ENC_KEY_PRD = bytearray.fromhex('00000000000000000000000000000000')
-HOVI_ENC_KEY_DEV = bytearray.fromhex('00000000000000000000000000000000')
-HOVI_SIG_KEY_PRD = bytearray.fromhex('00000000000000000000000000000000')
-HOVI_SIG_KEY_DEV = bytearray.fromhex('00000000000000000000000000000000')
-HOVI_KEK_KEY_PRD = bytearray.fromhex('00000000000000000000000000000000')
-HOVI_KEK_KEY_DEV = bytearray.fromhex('00000000000000000000000000000000')
-IV = bytearray.fromhex('00000000000000000000000000000000')
+NUM_KEYS = 2
+
+HOVI_ENC_KEY_PRD = [
+ bytearray.fromhex('00000000000000000000000000000000'),
+ bytearray.fromhex('00000000000000000000000000000000'),
+]
+
+HOVI_SIG_KEY_PRD = [
+ bytearray.fromhex('00000000000000000000000000000000'),
+ bytearray.fromhex('00000000000000000000000000000000'),
+]
+
+IV = [
+ bytearray.fromhex('00000000000000000000000000000000'),
+ bytearray.fromhex('00000000000000000000000000000000'),
+]
+
+assert len(HOVI_ENC_KEY_PRD) == NUM_KEYS
+assert len(HOVI_SIG_KEY_PRD) == NUM_KEYS
+assert len(IV) == NUM_KEYS
\ No newline at end of file
diff --git a/sept/sept-secondary/Makefile b/sept/sept-secondary/Makefile
index d41959363..fbbcac1a3 100644
--- a/sept/sept-secondary/Makefile
+++ b/sept/sept-secondary/Makefile
@@ -77,14 +77,15 @@ export TOPDIR := $(CURDIR)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir)) \
- $(AMS)/exosphere/rebootstub
+ $(AMS)/exosphere/rebootstub \
+ $(TOPDIR)/key_derivation
export DEPSDIR := $(CURDIR)/$(BUILD)
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
-BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) rebootstub.bin
+BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) rebootstub.bin key_derivation.bin
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
@@ -111,33 +112,38 @@ export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
-.PHONY: $(BUILD) clean all check_rebootstub
+.PHONY: $(BUILD) clean all check_rebootstub check_key_derivation
#---------------------------------------------------------------------------------
-all: check_rebootstub $(BUILD)
+all: check_rebootstub check_key_derivation $(BUILD)
check_rebootstub:
@$(MAKE) -C $(AMS)/exosphere/rebootstub all
-$(BUILD):
-ifeq ($(strip $(SEPT_ENC_PATH)),)
+check_key_derivation:
+ @$(MAKE) -C key_derivation
+
+$(BUILD): check_rebootstub check_key_derivation
+ifeq ($(strip $(SEPT_00_ENC_PATH)),)
@[ -d $@ ] || mkdir -p $@
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
else
@touch $(TOPDIR)/$(TARGET).bin
- @cp $(SEPT_ENC_PATH) $(TOPDIR)/$(TARGET).enc
+ @cp $(SEPT_00_ENC_PATH) $(TOPDIR)/$(TARGET)_00.enc
+ @cp $(SEPT_01_ENC_PATH) $(TOPDIR)/$(TARGET)_01.enc
endif
#---------------------------------------------------------------------------------
clean:
@echo clean ...
@$(MAKE) -C $(AMS)/exosphere/rebootstub clean
- @rm -fr $(BUILD) $(TARGET).bin $(TARGET).enc $(TARGET).elf
+ @$(MAKE) -C key_derivation clean
+ @rm -fr $(BUILD) $(TARGET).bin $(TARGET)_*.enc $(TARGET).elf
#---------------------------------------------------------------------------------
else
-.PHONY: all
+.PHONY: all $(OUTPUT).bin
DEPENDS := $(OFILES:.o=.d)
diff --git a/sept/sept-secondary/key_derivation/Makefile b/sept/sept-secondary/key_derivation/Makefile
new file mode 100644
index 000000000..6939c5afc
--- /dev/null
+++ b/sept/sept-secondary/key_derivation/Makefile
@@ -0,0 +1,154 @@
+#---------------------------------------------------------------------------------
+.SUFFIXES:
+#---------------------------------------------------------------------------------
+
+ifeq ($(strip $(DEVKITPRO)),)
+$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=/devkitpro")
+endif
+
+TOPDIR ?= $(CURDIR)
+include $(DEVKITPRO)/devkitA64/base_rules
+
+#---------------------------------------------------------------------------------
+# TARGET is the name of the output
+# BUILD is the directory where object files & intermediate files will be placed
+# SOURCES is a list of directories containing source code
+# DATA is a list of directories containing data files
+# INCLUDES is a list of directories containing header files
+#---------------------------------------------------------------------------------
+TARGET := $(notdir $(CURDIR))
+BUILD := build
+SOURCES := src
+DATA := data
+INCLUDES := include
+
+#---------------------------------------------------------------------------------
+# options for code generation
+#---------------------------------------------------------------------------------
+ARCH := -march=armv8-a -mtune=cortex-a57 -mgeneral-regs-only #<- important
+
+CFLAGS := \
+ -g \
+ -Os \
+ -ffunction-sections \
+ -fdata-sections \
+ -fomit-frame-pointer \
+ -fno-inline \
+ -std=gnu11 \
+ -Werror \
+ -Wall \
+ $(ARCH) $(DEFINES)
+
+CFLAGS += $(INCLUDE)
+
+CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11
+
+ASFLAGS := -g $(ARCH)
+LDFLAGS = -specs=$(TOPDIR)/linker.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
+
+LIBS :=
+
+#---------------------------------------------------------------------------------
+# list of directories containing libraries, this must be the top level containing
+# include and lib
+#---------------------------------------------------------------------------------
+LIBDIRS :=
+
+
+#---------------------------------------------------------------------------------
+# no real need to edit anything past this point unless you need to add additional
+# rules for different file extensions
+#---------------------------------------------------------------------------------
+ifneq ($(BUILD),$(notdir $(CURDIR)))
+#---------------------------------------------------------------------------------
+
+export OUTPUT := $(CURDIR)/$(TARGET)
+export TOPDIR := $(CURDIR)
+
+export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
+ $(foreach dir,$(DATA),$(CURDIR)/$(dir))
+
+export DEPSDIR := $(CURDIR)/$(BUILD)
+
+CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
+CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
+SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
+BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
+
+#---------------------------------------------------------------------------------
+# use CXX for linking C++ projects, CC for standard C
+#---------------------------------------------------------------------------------
+ifeq ($(strip $(CPPFILES)),)
+#---------------------------------------------------------------------------------
+ export LD := $(CC)
+#---------------------------------------------------------------------------------
+else
+#---------------------------------------------------------------------------------
+ export LD := $(CXX)
+#---------------------------------------------------------------------------------
+endif
+#---------------------------------------------------------------------------------
+
+export OFILES_BIN := $(addsuffix .o,$(BINFILES))
+export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
+export OFILES := $(OFILES_BIN) $(OFILES_SRC)
+export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES)))
+
+export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
+ $(foreach dir,$(LIBDIRS),-I$(dir)/include) \
+ -I$(CURDIR)/$(BUILD)
+
+export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
+
+.PHONY: $(BUILD) clean all
+
+#---------------------------------------------------------------------------------
+all: $(BUILD)
+
+$(BUILD):
+ @[ -d $@ ] || mkdir -p $@
+ @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
+
+#---------------------------------------------------------------------------------
+clean:
+ @echo clean ...
+ @rm -fr $(BUILD) $(TARGET).bin $(TARGET).elf
+
+
+#---------------------------------------------------------------------------------
+else
+.PHONY: all
+
+DEPENDS := $(OFILES:.o=.d)
+
+#---------------------------------------------------------------------------------
+# main targets
+#---------------------------------------------------------------------------------
+all : $(OUTPUT).bin
+
+$(OUTPUT).bin : $(OUTPUT).elf
+ $(OBJCOPY) -S -O binary $< $@
+ @echo built ... $(notdir $@)
+
+$(OUTPUT).elf : $(OFILES)
+
+%.elf: $(OFILES)
+ @echo linking $(notdir $@)
+ @$(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@
+ @$(NM) -CSn $@ > $(notdir $*.lst)
+
+$(OFILES_SRC) : $(HFILES_BIN)
+
+#---------------------------------------------------------------------------------
+# you need a rule like this for each extension you use as binary data
+#---------------------------------------------------------------------------------
+%.bin.o : %.bin
+#---------------------------------------------------------------------------------
+ @echo $(notdir $<)
+ @$(bin2o)
+
+-include $(DEPENDS)
+
+#---------------------------------------------------------------------------------------
+endif
+#---------------------------------------------------------------------------------------
diff --git a/sept/sept-secondary/key_derivation/linker.ld b/sept/sept-secondary/key_derivation/linker.ld
new file mode 100644
index 000000000..480bad8d9
--- /dev/null
+++ b/sept/sept-secondary/key_derivation/linker.ld
@@ -0,0 +1,17 @@
+OUTPUT_ARCH(aarch64)
+
+ENTRY(_start)
+SECTIONS
+{
+ . = 0x4003D000;
+
+ __start__ = ABSOLUTE(.);
+
+ .text : ALIGN(4) { *(.text.start) *(.text*); . = ALIGN(4); }
+ .rodata : ALIGN(4) { *(.rodata*); . = ALIGN(4); }
+ .bss : ALIGN(8) { __bss_start__ = .; *(.bss* COMMON); . = ALIGN(8); __bss_end__ = .; }
+
+ . = ALIGN(4);
+
+ __end__ = ABSOLUTE(.);
+}
\ No newline at end of file
diff --git a/sept/sept-secondary/key_derivation/linker.specs b/sept/sept-secondary/key_derivation/linker.specs
new file mode 100644
index 000000000..300990418
--- /dev/null
+++ b/sept/sept-secondary/key_derivation/linker.specs
@@ -0,0 +1,7 @@
+%rename link old_link
+
+*link:
+%(old_link) -T %:getenv(TOPDIR /linker.ld) --nmagic --gc-sections
+
+*startfile:
+crti%O%s crtbegin%O%s
diff --git a/sept/sept-secondary/key_derivation/src/key_derivation.c b/sept/sept-secondary/key_derivation/src/key_derivation.c
new file mode 100644
index 000000000..94194bf4a
--- /dev/null
+++ b/sept/sept-secondary/key_derivation/src/key_derivation.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2018-2019 Atmosphère-NX
+ *
+ * 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 "pmc.h"
+#include "se.h"
+#include "utils.h"
+
+#define AL16 __attribute__((aligned(16)))
+
+#define DERIVATION_ID_MAX 2
+
+static const uint8_t AL16 keyblob_seed_00[0x10] = {
+ 0xDF, 0x20, 0x6F, 0x59, 0x44, 0x54, 0xEF, 0xDC, 0x70, 0x74, 0x48, 0x3B, 0x0D, 0xED, 0x9F, 0xD3
+};
+
+static const uint8_t AL16 masterkey_seed[0x10] = {
+ 0xD8, 0xA2, 0x41, 0x0A, 0xC6, 0xC5, 0x90, 0x01, 0xC6, 0x1D, 0x6A, 0x26, 0x7C, 0x51, 0x3F, 0x3C
+};
+
+static const uint8_t AL16 devicekey_seed[0x10] = {
+ 0x4F, 0x02, 0x5F, 0x0E, 0xB6, 0x6D, 0x11, 0x0E, 0xDC, 0x32, 0x7D, 0x41, 0x86, 0xC2, 0xF4, 0x78
+};
+
+static const uint8_t AL16 devicekey_4x_seed[0x10] = {
+ 0x0C, 0x91, 0x09, 0xDB, 0x93, 0x93, 0x07, 0x81, 0x07, 0x3C, 0xC4, 0x16, 0x22, 0x7C, 0x6C, 0x28
+};
+
+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 zeroes[0x10] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static const uint8_t AL16 master_kek_seeds[DERIVATION_ID_MAX][0x10] = {
+ {0x9A, 0x3E, 0xA9, 0xAB, 0xFD, 0x56, 0x46, 0x1C, 0x9B, 0xF6, 0x48, 0x7F, 0x5C, 0xFA, 0x09, 0x5C},
+ {0xDE, 0xDC, 0xE3, 0x39, 0x30, 0x88, 0x16, 0xF8, 0xAE, 0x97, 0xAD, 0xEC, 0x64, 0x2D, 0x41, 0x41},
+};
+
+static const uint8_t AL16 master_devkey_seeds[DERIVATION_ID_MAX][0x10] = {
+ {0x8F, 0x77, 0x5A, 0x96, 0xB0, 0x94, 0xFD, 0x8D, 0x28, 0xE4, 0x19, 0xC8, 0x16, 0x1C, 0xDB, 0x3D},
+ {0x67, 0x62, 0xD4, 0x8E, 0x55, 0xCF, 0xFF, 0x41, 0x31, 0x15, 0x3B, 0x24, 0x0C, 0x7C, 0x07, 0xAE},
+};
+
+static const uint8_t AL16 master_devkey_vectors[DERIVATION_ID_MAX][0x10] = {
+ {0xD8, 0xD3, 0x67, 0x4F, 0xF3, 0xA2, 0xA4, 0x4E, 0xE4, 0x04, 0x37, 0xC2, 0xD9, 0xCF, 0x41, 0x6F},
+ {0x72, 0xD0, 0xAD, 0xEB, 0xE1, 0xF6, 0x35, 0x90, 0xB4, 0x43, 0xCC, 0x4B, 0xC4, 0xDC, 0x88, 0x0A},
+};
+
+void derive_keys(void) {
+ /* Set mailbox. */
+ volatile uint32_t *mailbox = (volatile uint32_t *)0x4003FF00;
+ const uint32_t derivation_id = *((volatile uint32_t *)0x4003E800);
+
+ if (derivation_id < DERIVATION_ID_MAX) {
+ uint8_t *enc_se_state = (uint8_t *)0x4003E000;
+
+ uint32_t AL16 work_buffer[4];
+
+ /* Derive Keyblob Key 00. */
+ se_aes_ecb_decrypt_block(0xC, work_buffer, 0x10, keyblob_seed_00, 0x10);
+ decrypt_data_into_keyslot(0xF, 0xE, work_buffer, 0x10);
+
+ /* Derive master kek. */
+ decrypt_data_into_keyslot(0xE, 0xD, master_kek_seeds[derivation_id], 0x10);
+
+ /* Clear the copy of the root key inside the SE. */
+ clear_aes_keyslot(0xD);
+
+ /* Derive master key, device master key. */
+ decrypt_data_into_keyslot(0xC, 0xE, masterkey_seed, 0x10);
+ decrypt_data_into_keyslot(0xE, 0xE, masterkey_4x_seed, 0x10);
+ clear_aes_keyslot(0xD);
+
+ /* Derive device keys. */
+ decrypt_data_into_keyslot(0xA, 0xF, devicekey_4x_seed, 0x10);
+ decrypt_data_into_keyslot(0xF, 0xF, devicekey_seed, 0x10);
+ clear_aes_keyslot(0xD);
+
+ /* Derive firmware specific device key. */
+ se_aes_ecb_decrypt_block(0xA, work_buffer, 0x10, master_devkey_seeds[derivation_id], 0x10);
+ decrypt_data_into_keyslot(0xE, 0xE, work_buffer, 0x10);
+ clear_aes_keyslot(0xD);
+
+ /* Test against a vector. */
+ for (size_t i = 0; i < 4; i++) {
+ work_buffer[i] = 0;
+ }
+ if (memcmp(work_buffer, zeroes, 0x10) != 0) {
+ clear_aes_keyslot(0xE);
+ clear_aes_keyslot(0xD);
+ clear_aes_keyslot(0xC);
+ clear_aes_keyslot(0xA);
+ clear_aes_keyslot(0xF);
+ generic_panic();
+ }
+
+ se_aes_ecb_decrypt_block(0xE, work_buffer, 0x10, master_devkey_vectors[derivation_id], 0x10);
+
+ if (memcmp(work_buffer, zeroes, 0x10) == 0) {
+ clear_aes_keyslot(0xE);
+ clear_aes_keyslot(0xD);
+ clear_aes_keyslot(0xC);
+ clear_aes_keyslot(0xA);
+ clear_aes_keyslot(0xF);
+ generic_panic();
+ }
+
+ /* Clear work buffer. */
+ for (size_t i = 0; i < 4; i++) {
+ work_buffer[i] = 0xCCCCCCCC;
+ }
+
+ /* Save context for real. */
+ se_set_in_context_save_mode(true);
+ se_save_context(KEYSLOT_SWITCH_SRKGENKEY, KEYSLOT_SWITCH_RNGKEY, enc_se_state);
+ se_set_in_context_save_mode(false);
+ }
+
+ /* Clear all keyslots. */
+ for (size_t i = 0; i < 0x10; i++) {
+ clear_aes_keyslot(i);
+ }
+
+ *mailbox = 7;
+ while (1) { /* Wait for sept to handle the rest. */ }
+}
diff --git a/sept/sept-secondary/key_derivation/src/key_derivation.h b/sept/sept-secondary/key_derivation/src/key_derivation.h
new file mode 100644
index 000000000..cd6cece8d
--- /dev/null
+++ b/sept/sept-secondary/key_derivation/src/key_derivation.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2018-2019 Atmosphère-NX
+ *
+ * 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_KEYDERIVATION_H
+#define SEPT_KEYDERIVATION_H
+
+#include
+#include
+#include
+
+void derive_keys(void);
+
+#endif
diff --git a/sept/sept-secondary/key_derivation/src/pmc.h b/sept/sept-secondary/key_derivation/src/pmc.h
new file mode 100644
index 000000000..f3a4f9379
--- /dev/null
+++ b/sept/sept-secondary/key_derivation/src/pmc.h
@@ -0,0 +1,626 @@
+/*
+ * Copyright (c) 2018-2019 Atmosphère-NX
+ *
+ * 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 FUSEE_PMC_H
+#define FUSEE_PMC_H
+
+#include
+
+#define PMC_BASE 0x7000E400
+#define MAKE_PMC_REG(n) MAKE_REG32(PMC_BASE + n)
+
+#define PMC_CONTROL_SDMMC1 (1 << 12)
+#define PMC_CONTROL_SDMMC3 (1 << 13)
+#define PMC_CONTROL_SDMMC4 (1 << 14)
+
+#define APBDEV_PMC_CONTROL MAKE_PMC_REG(0x00)
+#define APBDEV_PM_0 MAKE_PMC_REG(0x14)
+#define APBDEV_PMC_DPD_ENABLE_0 MAKE_PMC_REG(0x24)
+#define APBDEV_PMC_PWRGATE_TOGGLE_0 MAKE_PMC_REG(0x30)
+#define APBDEV_PMC_PWRGATE_STATUS_0 MAKE_PMC_REG(0x38)
+#define APBDEV_PMC_NO_IOPOWER_0 MAKE_PMC_REG(0x44)
+#define APBDEV_PMC_SCRATCH0_0 MAKE_PMC_REG(0x50)
+#define APBDEV_PMC_SCRATCH1_0 MAKE_PMC_REG(0x54)
+#define APBDEV_PMC_SCRATCH20_0 MAKE_PMC_REG(0xA0)
+#define APBDEV_PMC_PWR_DET_VAL_0 MAKE_PMC_REG(0xE4)
+#define APBDEV_PMC_DDR_PWR_0 MAKE_PMC_REG(0xE8)
+#define APBDEV_PMC_CRYPTO_OP_0 MAKE_PMC_REG(0xF4)
+#define APBDEV_PMC_WAKE2_STATUS_0 MAKE_PMC_REG(0x168)
+#define APBDEV_PMC_OSC_EDPD_OVER_0 MAKE_PMC_REG(0x1A4)
+#define APBDEV_PMC_RST_STATUS_0 MAKE_PMC_REG(0x1B4)
+#define APBDEV_PMC_IO_DPD_REQ_0 MAKE_PMC_REG(0x1B8)
+#define APBDEV_PMC_IO_DPD2_REQ_0 MAKE_PMC_REG(0x1C0)
+#define APBDEV_PMC_VDDP_SEL_0 MAKE_PMC_REG(0x1CC)
+#define APBDEV_PMC_SCRATCH49_0 MAKE_PMC_REG(0x244)
+#define APBDEV_PMC_TSC_MULT_0 MAKE_PMC_REG(0x2B4)
+#define APBDEV_PMC_REG_SHORT_0 MAKE_PMC_REG(0x2CC)
+#define APBDEV_PMC_WEAK_BIAS_0 MAKE_PMC_REG(0x2C8)
+#define APBDEV_PMC_SECURE_SCRATCH21_0 MAKE_PMC_REG(0x334)
+#define APBDEV_PMC_SECURE_SCRATCH32_0 MAKE_PMC_REG(0x360)
+#define APBDEV_PMC_SECURE_SCRATCH49_0 MAKE_PMC_REG(0x3A4)
+#define APBDEV_PMC_CNTRL2_0 MAKE_PMC_REG(0x440)
+#define APBDEV_PMC_IO_DPD4_REQ_0 MAKE_PMC_REG(0x464)
+#define APBDEV_PMC_UTMIP_PAD_CFG1_0 MAKE_PMC_REG(0x4C4)
+#define APBDEV_PMC_UTMIP_PAD_CFG3_0 MAKE_PMC_REG(0x4CC)
+#define APBDEV_PMC_DDR_CNTRL_0 MAKE_PMC_REG(0x4E4)
+#define APBDEV_PMC_SCRATCH43_0 MAKE_PMC_REG(0x22C)
+#define APBDEV_PMC_SCRATCH188_0 MAKE_PMC_REG(0x810)
+#define APBDEV_PMC_SCRATCH190_0 MAKE_PMC_REG(0x818)
+#define APBDEV_PMC_SCRATCH200_0 MAKE_PMC_REG(0x840)
+
+#define APBDEV_PMC_SCRATCH45_0 MAKE_PMC_REG(0x234)
+#define APBDEV_PMC_SCRATCH46_0 MAKE_PMC_REG(0x238)
+#define APBDEV_PMC_SCRATCH33_0 MAKE_PMC_REG(0x120)
+#define APBDEV_PMC_SCRATCH40_0 MAKE_PMC_REG(0x13C)
+
+typedef struct {
+ uint32_t cntrl;
+ uint32_t sec_disable;
+ uint32_t pmc_swrst;
+ uint32_t wake_mask;
+ uint32_t wake_lvl;
+ uint32_t wake_status;
+ uint32_t sw_wake_status;
+ uint32_t dpd_pads_oride;
+ uint32_t dpd_sample;
+ uint32_t dpd_enable;
+ uint32_t pwrgate_timer_off;
+ uint32_t clamp_status;
+ uint32_t pwrgate_toggle;
+ uint32_t remove_clamping;
+ uint32_t pwrgate_status;
+ uint32_t pwrgood_timer;
+ uint32_t blink_timer;
+ uint32_t no_iopower;
+ uint32_t pwr_det;
+ uint32_t pwr_det_latch;
+ uint32_t scratch0;
+ uint32_t scratch1;
+ uint32_t scratch2;
+ uint32_t scratch3;
+ uint32_t scratch4;
+ uint32_t scratch5;
+ uint32_t scratch6;
+ uint32_t scratch7;
+ uint32_t scratch8;
+ uint32_t scratch9;
+ uint32_t scratch10;
+ uint32_t scratch11;
+ uint32_t scratch12;
+ uint32_t scratch13;
+ uint32_t scratch14;
+ uint32_t scratch15;
+ uint32_t scratch16;
+ uint32_t scratch17;
+ uint32_t scratch18;
+ uint32_t scratch19;
+ uint32_t scratch20;
+ uint32_t scratch21;
+ uint32_t scratch22;
+ uint32_t scratch23;
+ uint32_t secure_scratch0;
+ uint32_t secure_scratch1;
+ uint32_t secure_scratch2;
+ uint32_t secure_scratch3;
+ uint32_t secure_scratch4;
+ uint32_t secure_scratch5;
+ uint32_t cpupwrgood_timer;
+ uint32_t cpupwroff_timer;
+ uint32_t pg_mask;
+ uint32_t pg_mask_1;
+ uint32_t auto_wake_lvl;
+ uint32_t auto_wake_lvl_mask;
+ uint32_t wake_delay;
+ uint32_t pwr_det_val;
+ uint32_t ddr_pwr;
+ uint32_t usb_debounce_del;
+ uint32_t usb_ao;
+ uint32_t crypto_op;
+ uint32_t pllp_wb0_override;
+ uint32_t scratch24;
+ uint32_t scratch25;
+ uint32_t scratch26;
+ uint32_t scratch27;
+ uint32_t scratch28;
+ uint32_t scratch29;
+ uint32_t scratch30;
+ uint32_t scratch31;
+ uint32_t scratch32;
+ uint32_t scratch33;
+ uint32_t scratch34;
+ uint32_t scratch35;
+ uint32_t scratch36;
+ uint32_t scratch37;
+ uint32_t scratch38;
+ uint32_t scratch39;
+ uint32_t scratch40;
+ uint32_t scratch41;
+ uint32_t scratch42;
+ uint32_t bo_mirror0;
+ uint32_t bo_mirror1;
+ uint32_t bo_mirror2;
+ uint32_t sys_33v_en;
+ uint32_t bo_mirror_access;
+ uint32_t gate;
+ uint32_t wake2_mask;
+ uint32_t wake2_lvl;
+ uint32_t wake2_stat;
+ uint32_t sw_wake2_stat;
+ uint32_t auto_wake2_lvl_mask;
+ uint32_t pg_mask2;
+ uint32_t pg_mask_ce1;
+ uint32_t pg_mask_ce2;
+ uint32_t pg_mask_ce3;
+ uint32_t pwrgate_timer_ce0;
+ uint32_t pwrgate_timer_ce1;
+ uint32_t pwrgate_timer_ce2;
+ uint32_t pwrgate_timer_ce3;
+ uint32_t pwrgate_timer_ce4;
+ uint32_t pwrgate_timer_ce5;
+ uint32_t pwrgate_timer_ce6;
+ uint32_t pcx_edpd_cntrl;
+ uint32_t osc_edpd_over;
+ uint32_t clk_out_cntrl;
+ uint32_t sata_pwrgate;
+ uint32_t sensor_ctrl;
+ uint32_t reset_status;
+ uint32_t io_dpd_req;
+ uint32_t io_dpd_stat;
+ uint32_t io_dpd2_req;
+ uint32_t io_dpd2_stat;
+ uint32_t sel_dpd_tim;
+ uint32_t vddp_sel;
+ uint32_t ddr_cfg;
+ uint32_t e_no_vttgen;
+ uint32_t _reserved0;
+ uint32_t pllm_wb0_ovrride_frq;
+ uint32_t test_pwrgate;
+ uint32_t pwrgate_timer_mult;
+ uint32_t dsi_sel_dpd;
+ uint32_t utmip_uhsic_triggers;
+ uint32_t utmip_uhsic_saved_st;
+ uint32_t utmip_pad_cfg;
+ uint32_t utmip_term_pad_cfg;
+ uint32_t utmip_uhsic_sleep_cfg;
+ uint32_t utmip_uhsic_sleepwalk_cfg;
+ uint32_t utmip_sleepwalk_p[3];
+ uint32_t uhsic_sleepwalk_p0;
+ uint32_t utmip_uhsic_status;
+ uint32_t utmip_uhsic_fake;
+ uint32_t bo_mirror3[2];
+ uint32_t secure_scratch6;
+ uint32_t secure_scratch7;
+ uint32_t scratch43;
+ uint32_t scratch44;
+ uint32_t scratch45;
+ uint32_t scratch46;
+ uint32_t scratch47;
+ uint32_t scratch48;
+ uint32_t scratch49;
+ uint32_t scratch50;
+ uint32_t scratch51;
+ uint32_t scratch52;
+ uint32_t scratch53;
+ uint32_t scratch54;
+ uint32_t scratch55;
+ uint32_t scratch0_eco;
+ uint32_t por_dpd_ctrl;
+ uint32_t scratch2_eco;
+ uint32_t utmip_uhsic_line_wakeup;
+ uint32_t utmip_bias_master_cntrl;
+ uint32_t utmip_master_config;
+ uint32_t td_pwrgate_inter_part_timer;
+ uint32_t utmip_uhsic2_triggers;
+ uint32_t utmip_uhsic2_saved_state;
+ uint32_t utmip_uhsic2_sleep_cfg;
+ uint32_t utmip_uhsic2_sleepwalk_cfg;
+ uint32_t uhsic2_sleepwalk_p1;
+ uint32_t utmip_uhsic2_status;
+ uint32_t utmip_uhsic2_fake;
+ uint32_t utmip_uhsic2_line_wakeup;
+ uint32_t utmip_master2_config;
+ uint32_t utmip_uhsic_rpd_cfg;
+ uint32_t pg_mask_ce0;
+ uint32_t pg_mask3[2];
+ uint32_t pllm_wb0_override2;
+ uint32_t tsc_mult;
+ uint32_t cpu_vsense_override;
+ uint32_t glb_amap_cfg;
+ uint32_t sticky_bits;
+ uint32_t sec_disable2;
+ uint32_t weak_bias;
+ uint32_t reg_short;
+ uint32_t pg_mask_andor;
+ uint32_t _reserved1[11];
+ uint32_t secure_scratch8;
+ uint32_t secure_scratch9;
+ uint32_t secure_scratch10;
+ uint32_t secure_scratch11;
+ uint32_t secure_scratch12;
+ uint32_t secure_scratch13;
+ uint32_t secure_scratch14;
+ uint32_t secure_scratch15;
+ uint32_t secure_scratch16;
+ uint32_t secure_scratch17;
+ uint32_t secure_scratch18;
+ uint32_t secure_scratch19;
+ uint32_t secure_scratch20;
+ uint32_t secure_scratch21;
+ uint32_t secure_scratch22;
+ uint32_t secure_scratch23;
+ uint32_t secure_scratch24;
+ uint32_t secure_scratch25;
+ uint32_t secure_scratch26;
+ uint32_t secure_scratch27;
+ uint32_t secure_scratch28;
+ uint32_t secure_scratch29;
+ uint32_t secure_scratch30;
+ uint32_t secure_scratch31;
+ uint32_t secure_scratch32;
+ uint32_t secure_scratch33;
+ uint32_t secure_scratch34;
+ uint32_t secure_scratch35;
+ uint32_t secure_scratch36;
+ uint32_t secure_scratch37;
+ uint32_t secure_scratch38;
+ uint32_t secure_scratch39;
+ uint32_t secure_scratch40;
+ uint32_t secure_scratch41;
+ uint32_t secure_scratch42;
+ uint32_t secure_scratch43;
+ uint32_t secure_scratch44;
+ uint32_t secure_scratch45;
+ uint32_t secure_scratch46;
+ uint32_t secure_scratch47;
+ uint32_t secure_scratch48;
+ uint32_t secure_scratch49;
+ uint32_t secure_scratch50;
+ uint32_t secure_scratch51;
+ uint32_t secure_scratch52;
+ uint32_t secure_scratch53;
+ uint32_t secure_scratch54;
+ uint32_t secure_scratch55;
+ uint32_t secure_scratch56;
+ uint32_t secure_scratch57;
+ uint32_t secure_scratch58;
+ uint32_t secure_scratch59;
+ uint32_t secure_scratch60;
+ uint32_t secure_scratch61;
+ uint32_t secure_scratch62;
+ uint32_t secure_scratch63;
+ uint32_t secure_scratch64;
+ uint32_t secure_scratch65;
+ uint32_t secure_scratch66;
+ uint32_t secure_scratch67;
+ uint32_t secure_scratch68;
+ uint32_t secure_scratch69;
+ uint32_t secure_scratch70;
+ uint32_t secure_scratch71;
+ uint32_t secure_scratch72;
+ uint32_t secure_scratch73;
+ uint32_t secure_scratch74;
+ uint32_t secure_scratch75;
+ uint32_t secure_scratch76;
+ uint32_t secure_scratch77;
+ uint32_t secure_scratch78;
+ uint32_t secure_scratch79;
+ uint32_t _reserved2[8];
+ uint32_t cntrl2;
+ uint32_t _reserved3[2];
+ uint32_t event_counter;
+ uint32_t fuse_control;
+ uint32_t scratch1_eco;
+ uint32_t _reserved4;
+ uint32_t io_dpd3_req;
+ uint32_t io_dpd3_status;
+ uint32_t io_dpd4_req;
+ uint32_t io_dpd4_status;
+ uint32_t _reserved5[30];
+ uint32_t ddr_cntrl;
+ uint32_t _reserved6[70];
+ uint32_t scratch56;
+ uint32_t scratch57;
+ uint32_t scratch58;
+ uint32_t scratch59;
+ uint32_t scratch60;
+ uint32_t scratch61;
+ uint32_t scratch62;
+ uint32_t scratch63;
+ uint32_t scratch64;
+ uint32_t scratch65;
+ uint32_t scratch66;
+ uint32_t scratch67;
+ uint32_t scratch68;
+ uint32_t scratch69;
+ uint32_t scratch70;
+ uint32_t scratch71;
+ uint32_t scratch72;
+ uint32_t scratch73;
+ uint32_t scratch74;
+ uint32_t scratch75;
+ uint32_t scratch76;
+ uint32_t scratch77;
+ uint32_t scratch78;
+ uint32_t scratch79;
+ uint32_t scratch80;
+ uint32_t scratch81;
+ uint32_t scratch82;
+ uint32_t scratch83;
+ uint32_t scratch84;
+ uint32_t scratch85;
+ uint32_t scratch86;
+ uint32_t scratch87;
+ uint32_t scratch88;
+ uint32_t scratch89;
+ uint32_t scratch90;
+ uint32_t scratch91;
+ uint32_t scratch92;
+ uint32_t scratch93;
+ uint32_t scratch94;
+ uint32_t scratch95;
+ uint32_t scratch96;
+ uint32_t scratch97;
+ uint32_t scratch98;
+ uint32_t scratch99;
+ uint32_t scratch100;
+ uint32_t scratch101;
+ uint32_t scratch102;
+ uint32_t scratch103;
+ uint32_t scratch104;
+ uint32_t scratch105;
+ uint32_t scratch106;
+ uint32_t scratch107;
+ uint32_t scratch108;
+ uint32_t scratch109;
+ uint32_t scratch110;
+ uint32_t scratch111;
+ uint32_t scratch112;
+ uint32_t scratch113;
+ uint32_t scratch114;
+ uint32_t scratch115;
+ uint32_t scratch116;
+ uint32_t scratch117;
+ uint32_t scratch118;
+ uint32_t scratch119;
+ uint32_t scratch120;
+ uint32_t scratch121;
+ uint32_t scratch122;
+ uint32_t scratch123;
+ uint32_t scratch124;
+ uint32_t scratch125;
+ uint32_t scratch126;
+ uint32_t scratch127;
+ uint32_t scratch128;
+ uint32_t scratch129;
+ uint32_t scratch130;
+ uint32_t scratch131;
+ uint32_t scratch132;
+ uint32_t scratch133;
+ uint32_t scratch134;
+ uint32_t scratch135;
+ uint32_t scratch136;
+ uint32_t scratch137;
+ uint32_t scratch138;
+ uint32_t scratch139;
+ uint32_t scratch140;
+ uint32_t scratch141;
+ uint32_t scratch142;
+ uint32_t scratch143;
+ uint32_t scratch144;
+ uint32_t scratch145;
+ uint32_t scratch146;
+ uint32_t scratch147;
+ uint32_t scratch148;
+ uint32_t scratch149;
+ uint32_t scratch150;
+ uint32_t scratch151;
+ uint32_t scratch152;
+ uint32_t scratch153;
+ uint32_t scratch154;
+ uint32_t scratch155;
+ uint32_t scratch156;
+ uint32_t scratch157;
+ uint32_t scratch158;
+ uint32_t scratch159;
+ uint32_t scratch160;
+ uint32_t scratch161;
+ uint32_t scratch162;
+ uint32_t scratch163;
+ uint32_t scratch164;
+ uint32_t scratch165;
+ uint32_t scratch166;
+ uint32_t scratch167;
+ uint32_t scratch168;
+ uint32_t scratch169;
+ uint32_t scratch170;
+ uint32_t scratch171;
+ uint32_t scratch172;
+ uint32_t scratch173;
+ uint32_t scratch174;
+ uint32_t scratch175;
+ uint32_t scratch176;
+ uint32_t scratch177;
+ uint32_t scratch178;
+ uint32_t scratch179;
+ uint32_t scratch180;
+ uint32_t scratch181;
+ uint32_t scratch182;
+ uint32_t scratch183;
+ uint32_t scratch184;
+ uint32_t scratch185;
+ uint32_t scratch186;
+ uint32_t scratch187;
+ uint32_t scratch188;
+ uint32_t scratch189;
+ uint32_t scratch190;
+ uint32_t scratch191;
+ uint32_t scratch192;
+ uint32_t scratch193;
+ uint32_t scratch194;
+ uint32_t scratch195;
+ uint32_t scratch196;
+ uint32_t scratch197;
+ uint32_t scratch198;
+ uint32_t scratch199;
+ uint32_t scratch200;
+ uint32_t scratch201;
+ uint32_t scratch202;
+ uint32_t scratch203;
+ uint32_t scratch204;
+ uint32_t scratch205;
+ uint32_t scratch206;
+ uint32_t scratch207;
+ uint32_t scratch208;
+ uint32_t scratch209;
+ uint32_t scratch210;
+ uint32_t scratch211;
+ uint32_t scratch212;
+ uint32_t scratch213;
+ uint32_t scratch214;
+ uint32_t scratch215;
+ uint32_t scratch216;
+ uint32_t scratch217;
+ uint32_t scratch218;
+ uint32_t scratch219;
+ uint32_t scratch220;
+ uint32_t scratch221;
+ uint32_t scratch222;
+ uint32_t scratch223;
+ uint32_t scratch224;
+ uint32_t scratch225;
+ uint32_t scratch226;
+ uint32_t scratch227;
+ uint32_t scratch228;
+ uint32_t scratch229;
+ uint32_t scratch230;
+ uint32_t scratch231;
+ uint32_t scratch232;
+ uint32_t scratch233;
+ uint32_t scratch234;
+ uint32_t scratch235;
+ uint32_t scratch236;
+ uint32_t scratch237;
+ uint32_t scratch238;
+ uint32_t scratch239;
+ uint32_t scratch240;
+ uint32_t scratch241;
+ uint32_t scratch242;
+ uint32_t scratch243;
+ uint32_t scratch244;
+ uint32_t scratch245;
+ uint32_t scratch246;
+ uint32_t scratch247;
+ uint32_t scratch248;
+ uint32_t scratch249;
+ uint32_t scratch250;
+ uint32_t scratch251;
+ uint32_t scratch252;
+ uint32_t scratch253;
+ uint32_t scratch254;
+ uint32_t scratch255;
+ uint32_t scratch256;
+ uint32_t scratch257;
+ uint32_t scratch258;
+ uint32_t scratch259;
+ uint32_t scratch260;
+ uint32_t scratch261;
+ uint32_t scratch262;
+ uint32_t scratch263;
+ uint32_t scratch264;
+ uint32_t scratch265;
+ uint32_t scratch266;
+ uint32_t scratch267;
+ uint32_t scratch268;
+ uint32_t scratch269;
+ uint32_t scratch270;
+ uint32_t scratch271;
+ uint32_t scratch272;
+ uint32_t scratch273;
+ uint32_t scratch274;
+ uint32_t scratch275;
+ uint32_t scratch276;
+ uint32_t scratch277;
+ uint32_t scratch278;
+ uint32_t scratch279;
+ uint32_t scratch280;
+ uint32_t scratch281;
+ uint32_t scratch282;
+ uint32_t scratch283;
+ uint32_t scratch284;
+ uint32_t scratch285;
+ uint32_t scratch286;
+ uint32_t scratch287;
+ uint32_t scratch288;
+ uint32_t scratch289;
+ uint32_t scratch290;
+ uint32_t scratch291;
+ uint32_t scratch292;
+ uint32_t scratch293;
+ uint32_t scratch294;
+ uint32_t scratch295;
+ uint32_t scratch296;
+ uint32_t scratch297;
+ uint32_t scratch298;
+ uint32_t scratch299;
+ uint32_t _reserved7[50];
+ uint32_t secure_scratch80;
+ uint32_t secure_scratch81;
+ uint32_t secure_scratch82;
+ uint32_t secure_scratch83;
+ uint32_t secure_scratch84;
+ uint32_t secure_scratch85;
+ uint32_t secure_scratch86;
+ uint32_t secure_scratch87;
+ uint32_t secure_scratch88;
+ uint32_t secure_scratch89;
+ uint32_t secure_scratch90;
+ uint32_t secure_scratch91;
+ uint32_t secure_scratch92;
+ uint32_t secure_scratch93;
+ uint32_t secure_scratch94;
+ uint32_t secure_scratch95;
+ uint32_t secure_scratch96;
+ uint32_t secure_scratch97;
+ uint32_t secure_scratch98;
+ uint32_t secure_scratch99;
+ uint32_t secure_scratch100;
+ uint32_t secure_scratch101;
+ uint32_t secure_scratch102;
+ uint32_t secure_scratch103;
+ uint32_t secure_scratch104;
+ uint32_t secure_scratch105;
+ uint32_t secure_scratch106;
+ uint32_t secure_scratch107;
+ uint32_t secure_scratch108;
+ uint32_t secure_scratch109;
+ uint32_t secure_scratch110;
+ uint32_t secure_scratch111;
+ uint32_t secure_scratch112;
+ uint32_t secure_scratch113;
+ uint32_t secure_scratch114;
+ uint32_t secure_scratch115;
+ uint32_t secure_scratch116;
+ uint32_t secure_scratch117;
+ uint32_t secure_scratch118;
+ uint32_t secure_scratch119;
+} tegra_pmc_t;
+
+static inline volatile tegra_pmc_t *pmc_get_regs(void)
+{
+ return (volatile tegra_pmc_t *)PMC_BASE;
+}
+
+#endif
diff --git a/sept/sept-secondary/key_derivation/src/se.c b/sept/sept-secondary/key_derivation/src/se.c
new file mode 100644
index 000000000..b32595c99
--- /dev/null
+++ b/sept/sept-secondary/key_derivation/src/se.c
@@ -0,0 +1,757 @@
+/*
+ * Copyright (c) 2018-2019 Atmosphère-NX
+ *
+ * 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 "utils.h"
+#include "se.h"
+
+void trigger_se_blocking_op(unsigned int op, void *dst, size_t dst_size, const void *src, size_t src_size);
+
+/* Globals for driver. */
+static unsigned int g_se_modulus_sizes[KEYSLOT_RSA_MAX];
+static unsigned int g_se_exp_sizes[KEYSLOT_RSA_MAX];
+
+/* Initialize a SE linked list. */
+void NOINLINE ll_init(volatile se_ll_t *ll, void *buffer, size_t size) {
+ ll->num_entries = 0; /* 1 Entry. */
+
+ if (buffer != NULL) {
+ ll->addr_info.address = (uint32_t) get_physical_address(buffer);
+ ll->addr_info.size = (uint32_t) size;
+ } else {
+ ll->addr_info.address = 0;
+ ll->addr_info.size = 0;
+ }
+}
+
+void se_check_error_status_reg(void) {
+ if (se_get_regs()->ERR_STATUS_REG) {
+ generic_panic();
+ }
+}
+
+void se_check_for_error(void) {
+ volatile tegra_se_t *se = se_get_regs();
+ if (se->INT_STATUS_REG & 0x10000 || se->FLAGS_REG & 3 || se->ERR_STATUS_REG) {
+ generic_panic();
+ }
+}
+
+void se_verify_flags_cleared(void) {
+ if (se_get_regs()->FLAGS_REG & 3) {
+ generic_panic();
+ }
+}
+
+/* Set the flags for an AES keyslot. */
+void set_aes_keyslot_flags(unsigned int keyslot, unsigned int flags) {
+ volatile tegra_se_t *se = se_get_regs();
+
+ if (keyslot >= KEYSLOT_AES_MAX) {
+ generic_panic();
+ }
+
+ /* Misc flags. */
+ if (flags & ~0x80) {
+ se->AES_KEYSLOT_FLAGS[keyslot] = ~flags;
+ }
+
+ /* Disable keyslot reads. */
+ if (flags & 0x80) {
+ se->AES_KEY_READ_DISABLE_REG &= ~(1 << keyslot);
+ }
+}
+
+/* Set the flags for an RSA keyslot. */
+void set_rsa_keyslot_flags(unsigned int keyslot, unsigned int flags) {
+ volatile tegra_se_t *se = se_get_regs();
+
+ if (keyslot >= KEYSLOT_RSA_MAX) {
+ generic_panic();
+ }
+
+ /* Misc flags. */
+ if (flags & ~0x80) {
+ /* TODO: Why are flags assigned this way? */
+ se->RSA_KEYSLOT_FLAGS[keyslot] = (((flags >> 4) & 4) | (flags & 3)) ^ 7;
+ }
+
+ /* Disable keyslot reads. */
+ if (flags & 0x80) {
+ se->RSA_KEY_READ_DISABLE_REG &= ~(1 << keyslot);
+ }
+}
+
+void clear_aes_keyslot(unsigned int keyslot) {
+ volatile tegra_se_t *se = se_get_regs();
+
+ if (keyslot >= KEYSLOT_AES_MAX) {
+ generic_panic();
+ }
+
+ /* Zero out the whole keyslot and IV. */
+ for (unsigned int i = 0; i < 0x10; i++) {
+ se->AES_KEYTABLE_ADDR = (keyslot << 4) | i;
+ se->AES_KEYTABLE_DATA = 0;
+ }
+}
+
+void clear_rsa_keyslot(unsigned int keyslot) {
+ volatile tegra_se_t *se = se_get_regs();
+
+ if (keyslot >= KEYSLOT_RSA_MAX) {
+ generic_panic();
+ }
+
+ /* Zero out the whole keyslot. */
+ for (unsigned int i = 0; i < 0x40; i++) {
+ /* Select Keyslot Modulus[i] */
+ se->RSA_KEYTABLE_ADDR = (keyslot << 7) | i | 0x40;
+ se->RSA_KEYTABLE_DATA = 0;
+ }
+ for (unsigned int i = 0; i < 0x40; i++) {
+ /* Select Keyslot Expontent[i] */
+ se->RSA_KEYTABLE_ADDR = (keyslot << 7) | i;
+ se->RSA_KEYTABLE_DATA = 0;
+ }
+}
+
+void set_aes_keyslot(unsigned int keyslot, const void *key, size_t key_size) {
+ volatile tegra_se_t *se = se_get_regs();
+
+ if (keyslot >= KEYSLOT_AES_MAX || key_size > KEYSIZE_AES_MAX) {
+ generic_panic();
+ }
+
+ for (size_t i = 0; i < (key_size >> 2); i++) {
+ se->AES_KEYTABLE_ADDR = (keyslot << 4) | i;
+ se->AES_KEYTABLE_DATA = read32le(key, 4 * i);
+ }
+}
+
+void set_rsa_keyslot(unsigned int keyslot, const void *modulus, size_t modulus_size, const void *exponent, size_t exp_size) {
+ volatile tegra_se_t *se = se_get_regs();
+
+ if (keyslot >= KEYSLOT_RSA_MAX || modulus_size > KEYSIZE_RSA_MAX || exp_size > KEYSIZE_RSA_MAX) {
+ generic_panic();
+ }
+
+ for (size_t i = 0; i < (modulus_size >> 2); i++) {
+ se->RSA_KEYTABLE_ADDR = (keyslot << 7) | 0x40 | i;
+ se->RSA_KEYTABLE_DATA = read32be(modulus, (4 * (modulus_size >> 2)) - (4 * i) - 4);
+ }
+
+ for (size_t i = 0; i < (exp_size >> 2); i++) {
+ se->RSA_KEYTABLE_ADDR = (keyslot << 7) | i;
+ se->RSA_KEYTABLE_DATA = read32be(exponent, (4 * (exp_size >> 2)) - (4 * i) - 4);
+ }
+
+ g_se_modulus_sizes[keyslot] = modulus_size;
+ g_se_exp_sizes[keyslot] = exp_size;
+}
+
+void set_aes_keyslot_iv(unsigned int keyslot, const void *iv, size_t iv_size) {
+ volatile tegra_se_t *se = se_get_regs();
+
+ if (keyslot >= KEYSLOT_AES_MAX || iv_size > 0x10) {
+ generic_panic();
+ }
+
+ for (size_t i = 0; i < (iv_size >> 2); i++) {
+ se->AES_KEYTABLE_ADDR = (keyslot << 4) | 8 | i;
+ se->AES_KEYTABLE_DATA = read32le(iv, 4 * i);
+ }
+}
+
+void clear_aes_keyslot_iv(unsigned int keyslot) {
+ volatile tegra_se_t *se = se_get_regs();
+
+ if (keyslot >= KEYSLOT_AES_MAX) {
+ generic_panic();
+ }
+
+ for (size_t i = 0; i < (0x10 >> 2); i++) {
+ se->AES_KEYTABLE_ADDR = (keyslot << 4) | 8 | i;
+ se->AES_KEYTABLE_DATA = 0;
+ }
+}
+
+void set_se_ctr(const void *ctr) {
+ for (unsigned int i = 0; i < 4; i++) {
+ se_get_regs()->CRYPTO_CTR_REG[i] = read32le(ctr, i * 4);
+ }
+}
+
+void decrypt_data_into_keyslot(unsigned int keyslot_dst, unsigned int keyslot_src, const void *wrapped_key, size_t wrapped_key_size) {
+ volatile tegra_se_t *se = se_get_regs();
+
+ if (keyslot_dst >= KEYSLOT_AES_MAX || keyslot_src >= KEYSLOT_AES_MAX || wrapped_key_size > KEYSIZE_AES_MAX) {
+ generic_panic();
+ }
+
+ /* Write config, validate. */
+ se->CONFIG_REG = (ALG_AES_DEC | DST_KEYTAB);
+ if (se->CONFIG_REG != (ALG_AES_DEC | DST_KEYTAB)) {
+ generic_panic();
+ }
+ se->CRYPTO_REG = keyslot_src << 24;
+ if (se->CRYPTO_REG != (keyslot_src << 24)) {
+ generic_panic();
+ }
+ se->BLOCK_COUNT_REG = 0;
+ if (se->BLOCK_COUNT_REG != 0) {
+ generic_panic();
+ }
+ se->CRYPTO_KEYTABLE_DST_REG = keyslot_dst << 8;
+ if (se->CRYPTO_KEYTABLE_DST_REG != (keyslot_dst << 8)) {
+ generic_panic();
+ }
+
+ /* Clear address context. */
+ se->IN_LL_ADDR_REG = 0;
+ se->OUT_LL_ADDR_REG = 0;
+ if (se->IN_LL_ADDR_REG != 0 || se->OUT_LL_ADDR_REG != 0) {
+ generic_panic();
+ }
+
+ trigger_se_blocking_op(OP_START, NULL, 0, wrapped_key, wrapped_key_size);
+
+ /* Validate address context. */
+ if (se->IN_LL_ADDR_REG == 0 || se->OUT_LL_ADDR_REG == 0) {
+ generic_panic();
+ }
+}
+
+void se_synchronous_exp_mod(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size) {
+ volatile tegra_se_t *se = se_get_regs();
+ uint8_t ALIGN(16) stack_buf[KEYSIZE_RSA_MAX];
+
+ if (keyslot >= KEYSLOT_RSA_MAX || src_size > KEYSIZE_RSA_MAX || dst_size > KEYSIZE_RSA_MAX) {
+ generic_panic();
+ }
+
+ /* Endian swap the input. */
+ for (size_t i = 0; i < src_size; i++) {
+ stack_buf[i] = *((uint8_t *)src + src_size - i - 1);
+ }
+
+ se->CONFIG_REG = (ALG_RSA | DST_RSAREG);
+ se->RSA_CONFIG = keyslot << 24;
+ se->RSA_KEY_SIZE_REG = (g_se_modulus_sizes[keyslot] >> 6) - 1;
+ se->RSA_EXP_SIZE_REG = g_se_exp_sizes[keyslot] >> 2;
+
+ trigger_se_blocking_op(OP_START, NULL, 0, stack_buf, src_size);
+ se_get_exp_mod_output(dst, dst_size);
+}
+
+void se_get_exp_mod_output(void *buf, size_t size) {
+ size_t num_dwords = (size >> 2);
+
+ if (num_dwords < 1) {
+ return;
+ }
+
+ uint32_t *p_out = ((uint32_t *)buf) + num_dwords - 1;
+ uint32_t offset = 0;
+
+ /* Copy endian swapped output. */
+ while (num_dwords) {
+ *p_out = read32be(se_get_regs()->RSA_OUTPUT, offset);
+ offset += 4;
+ p_out--;
+ num_dwords--;
+ }
+}
+
+bool se_rsa2048_pss_verify(const void *signature, size_t signature_size, const void *modulus, size_t modulus_size, const void *data, size_t data_size) {
+ uint8_t message[RSA_2048_BYTES];
+ uint8_t h_buf[0x24];
+
+ /* Hardcode RSA with keyslot 0. */
+ const uint8_t public_exponent[4] = {0x00, 0x01, 0x00, 0x01};
+ set_rsa_keyslot(0, modulus, modulus_size, public_exponent, sizeof(public_exponent));
+ se_synchronous_exp_mod(0, message, sizeof(message), signature, signature_size);
+
+ /* Validate sanity byte. */
+ if (message[RSA_2048_BYTES - 1] != 0xBC) {
+ return false;
+ }
+
+ /* Copy Salt into MGF1 Hash Buffer. */
+ memset(h_buf, 0, sizeof(h_buf));
+ memcpy(h_buf, message + RSA_2048_BYTES - 0x20 - 0x1, 0x20);
+
+ /* Decrypt maskedDB (via inline MGF1). */
+ uint8_t seed = 0;
+ uint8_t mgf1_buf[0x20];
+ for (unsigned int ofs = 0; ofs < RSA_2048_BYTES - 0x20 - 1; ofs += 0x20) {
+ h_buf[sizeof(h_buf) - 1] = seed++;
+ se_calculate_sha256(mgf1_buf, h_buf, sizeof(h_buf));
+ for (unsigned int i = ofs; i < ofs + 0x20 && i < RSA_2048_BYTES - 0x20 - 1; i++) {
+ message[i] ^= mgf1_buf[i - ofs];
+ }
+ }
+
+ /* Constant lmask for rsa-2048-pss. */
+ message[0] &= 0x7F;
+
+ /* Validate DB is of the form 0000...0001. */
+ for (unsigned int i = 0; i < RSA_2048_BYTES - 0x20 - 0x20 - 1 - 1; i++) {
+ if (message[i] != 0) {
+ return false;
+ }
+ }
+ if (message[RSA_2048_BYTES - 0x20 - 0x20 - 1 - 1] != 1) {
+ return false;
+ }
+
+ /* Check hash correctness. */
+ uint8_t validate_buf[8 + 0x20 + 0x20];
+ uint8_t validate_hash[0x20];
+
+ memset(validate_buf, 0, sizeof(validate_buf));
+ se_calculate_sha256(&validate_buf[8], data, data_size);
+ memcpy(&validate_buf[0x28], &message[RSA_2048_BYTES - 0x20 - 0x20 - 1], 0x20);
+ se_calculate_sha256(validate_hash, validate_buf, sizeof(validate_buf));
+ return memcmp(h_buf, validate_hash, 0x20) == 0;
+}
+
+void trigger_se_blocking_op(unsigned int op, void *dst, size_t dst_size, const void *src, size_t src_size) {
+ volatile tegra_se_t *se = se_get_regs();
+ se_ll_t in_ll;
+ se_ll_t out_ll;
+
+ ll_init(&in_ll, (void *)src, src_size);
+ ll_init(&out_ll, dst, dst_size);
+
+ /* Set the LLs. */
+ se->IN_LL_ADDR_REG = (uint32_t) get_physical_address(&in_ll);
+ se->OUT_LL_ADDR_REG = (uint32_t) get_physical_address(&out_ll);
+
+ /* Set registers for operation. */
+ se->ERR_STATUS_REG = se->ERR_STATUS_REG;
+ se->INT_STATUS_REG = se->INT_STATUS_REG;
+
+ if (se->IN_LL_ADDR_REG != (uint32_t) get_physical_address(&in_ll) || se->OUT_LL_ADDR_REG != (uint32_t) get_physical_address(&out_ll) || (se->INT_STATUS_REG & 0x10) || (se->FLAGS_REG & 0x3)) {
+ generic_panic();
+ }
+
+ se->OPERATION_REG = op;
+
+ while (!(se->INT_STATUS_REG & 0x10)) { /* Wait a while */ }
+ se_check_for_error();
+}
+
+/* Secure AES Functionality. */
+void se_perform_aes_block_operation(void *dst, size_t dst_size, const void *src, size_t src_size) {
+ uint8_t block[0x10] = {0};
+
+ if (src_size > sizeof(block) || dst_size > sizeof(block)) {
+ generic_panic();
+ }
+
+ /* Load src data into block. */
+ if (src_size != 0) {
+ memcpy(block, src, src_size);
+ }
+
+ /* Trigger AES operation. */
+ se_get_regs()->BLOCK_COUNT_REG = 0;
+ trigger_se_blocking_op(OP_START, block, sizeof(block), block, sizeof(block));
+
+ /* Copy output data into dst. */
+ if (dst_size != 0) {
+ memcpy(dst, block, dst_size);
+ }
+}
+
+void se_aes_ctr_crypt(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size, const void *ctr, size_t ctr_size) {
+ volatile tegra_se_t *se = se_get_regs();
+
+ if (keyslot >= KEYSLOT_AES_MAX || ctr_size != 0x10) {
+ generic_panic();
+ }
+ unsigned int num_blocks = src_size >> 4;
+
+ /* Unknown what this write does, but official code writes it for CTR mode. */
+ se->SPARE_0 = 1;
+ se->CONFIG_REG = (ALG_AES_ENC | DST_MEMORY);
+ se->CRYPTO_REG = (keyslot << 24) | 0x91E;
+ set_se_ctr(ctr);
+
+ /* Handle any aligned blocks. */
+ size_t aligned_size = (size_t)num_blocks << 4;
+ if (aligned_size) {
+ se->BLOCK_COUNT_REG = num_blocks - 1;
+ trigger_se_blocking_op(OP_START, dst, dst_size, src, aligned_size);
+ }
+
+ /* Handle final, unaligned block. */
+ if (aligned_size < dst_size && aligned_size < src_size) {
+ size_t last_block_size = dst_size - aligned_size;
+ if (src_size < dst_size) {
+ last_block_size = src_size - aligned_size;
+ }
+ se_perform_aes_block_operation(dst + aligned_size, last_block_size, (uint8_t *)src + aligned_size, src_size - aligned_size);
+ }
+}
+
+void se_aes_ecb_encrypt_block(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size, unsigned int config_high) {
+ volatile tegra_se_t *se = se_get_regs();
+
+ if (keyslot >= KEYSLOT_AES_MAX || dst_size != 0x10 || src_size != 0x10) {
+ generic_panic();
+ }
+
+ /* Set configuration high (256-bit vs 128-bit) based on parameter. */
+ se->CONFIG_REG = (ALG_AES_ENC | DST_MEMORY) | (config_high << 16);
+ se->CRYPTO_REG = keyslot << 24 | 0x100;
+ se_perform_aes_block_operation(dst, 0x10, src, 0x10);
+}
+
+void se_aes_128_ecb_encrypt_block(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size) {
+ se_aes_ecb_encrypt_block(keyslot, dst, dst_size, src, src_size, 0);
+}
+
+void se_aes_256_ecb_encrypt_block(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size) {
+ se_aes_ecb_encrypt_block(keyslot, dst, dst_size, src, src_size, 0x202);
+}
+
+void se_aes_ecb_decrypt_block(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size) {
+ volatile tegra_se_t *se = se_get_regs();
+
+ if (keyslot >= KEYSLOT_AES_MAX || dst_size != 0x10 || src_size != 0x10) {
+ generic_panic();
+ }
+
+ se->CONFIG_REG = (ALG_AES_DEC | DST_MEMORY);
+ se->CRYPTO_REG = keyslot << 24;
+ se_perform_aes_block_operation(dst, 0x10, src, 0x10);
+}
+
+void shift_left_xor_rb(uint8_t *key) {
+ uint8_t prev_high_bit = 0;
+ for (unsigned int i = 0; i < 0x10; i++) {
+ uint8_t cur_byte = key[0xF - i];
+ key[0xF - i] = (cur_byte << 1) | (prev_high_bit);
+ prev_high_bit = cur_byte >> 7;
+ }
+ if (prev_high_bit) {
+ key[0xF] ^= 0x87;
+ }
+}
+
+void shift_left_xor_rb_le(uint8_t *key) {
+ uint8_t prev_high_bit = 0;
+ for (unsigned int i = 0; i < 0x10; i++) {
+ uint8_t cur_byte = key[i];
+ key[i] = (cur_byte << 1) | (prev_high_bit);
+ prev_high_bit = cur_byte >> 7;
+ }
+ if (prev_high_bit) {
+ key[0x0] ^= 0x87;
+ }
+}
+
+void se_compute_aes_cmac(unsigned int keyslot, void *cmac, size_t cmac_size, const void *data, size_t data_size, unsigned int config_high) {
+ volatile tegra_se_t *se = se_get_regs();
+
+ if (keyslot >= KEYSLOT_AES_MAX) {
+ generic_panic();
+ }
+
+ /* Generate the derived key, to be XOR'd with final output block. */
+ uint8_t ALIGN(16) derived_key[0x10] = {0};
+ se_aes_ecb_encrypt_block(keyslot, derived_key, sizeof(derived_key), derived_key, sizeof(derived_key), config_high);
+ shift_left_xor_rb(derived_key);
+ if (data_size & 0xF) {
+ shift_left_xor_rb(derived_key);
+ }
+
+ se->CONFIG_REG = (ALG_AES_ENC | DST_HASHREG) | (config_high << 16);
+ se->CRYPTO_REG = (keyslot << 24) | (0x145);
+ clear_aes_keyslot_iv(keyslot);
+
+ unsigned int num_blocks = (data_size + 0xF) >> 4;
+ /* Handle aligned blocks. */
+ if (num_blocks > 1) {
+ se->BLOCK_COUNT_REG = num_blocks - 2;
+ trigger_se_blocking_op(OP_START, NULL, 0, data, data_size);
+ se->CRYPTO_REG |= 0x80;
+ }
+
+ /* Create final block. */
+ uint8_t ALIGN(16) last_block[0x10] = {0};
+ if (data_size & 0xF) {
+ memcpy(last_block, data + (data_size & ~0xF), data_size & 0xF);
+ last_block[data_size & 0xF] = 0x80; /* Last block = data || 100...0 */
+ } else if (data_size >= 0x10) {
+ memcpy(last_block, data + data_size - 0x10, 0x10);
+ }
+
+ for (unsigned int i = 0; i < 0x10; i++) {
+ last_block[i] ^= derived_key[i];
+ }
+
+ /* Perform last operation. */
+ se->BLOCK_COUNT_REG = 0;
+ trigger_se_blocking_op(OP_START, NULL, 0, last_block, sizeof(last_block));
+
+ /* Copy output CMAC. */
+ for (unsigned int i = 0; i < (cmac_size >> 2); i++) {
+ ((uint32_t *)cmac)[i] = read32le(se->HASH_RESULT_REG, i << 2);
+ }
+}
+
+void se_compute_aes_128_cmac(unsigned int keyslot, void *cmac, size_t cmac_size, const void *data, size_t data_size) {
+ se_compute_aes_cmac(keyslot, cmac, cmac_size, data, data_size, 0);
+}
+void se_compute_aes_256_cmac(unsigned int keyslot, void *cmac, size_t cmac_size, const void *data, size_t data_size) {
+ se_compute_aes_cmac(keyslot, cmac, cmac_size, data, data_size, 0x202);
+}
+
+void se_aes_256_cbc_encrypt(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size, const void *iv) {
+ volatile tegra_se_t *se = se_get_regs();
+
+ if (keyslot >= KEYSLOT_AES_MAX || src_size < 0x10) {
+ generic_panic();
+ }
+
+ se->CONFIG_REG = (ALG_AES_ENC | DST_MEMORY) | (0x202 << 16);
+ se->CRYPTO_REG = (keyslot << 24) | 0x144;
+ set_aes_keyslot_iv(keyslot, iv, 0x10);
+ se->BLOCK_COUNT_REG = (src_size >> 4) - 1;
+ trigger_se_blocking_op(OP_START, dst, dst_size, src, src_size);
+}
+
+void se_aes_128_cbc_decrypt(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size) {
+ volatile tegra_se_t *se = se_get_regs();
+
+ if (keyslot >= KEYSLOT_AES_MAX || src_size < 0x10) {
+ generic_panic();
+ }
+
+ se->CONFIG_REG = (ALG_AES_DEC | DST_MEMORY) | (0x000 << 16);
+ se->CRYPTO_REG = (keyslot << 24) | 0x66;
+ clear_aes_keyslot_iv(keyslot);
+ se->BLOCK_COUNT_REG = (src_size >> 4) - 1;
+ trigger_se_blocking_op(OP_START, dst, dst_size, src, src_size);
+}
+
+/* SHA256 Implementation. */
+void se_calculate_sha256(void *dst, const void *src, size_t src_size) {
+ volatile tegra_se_t *se = se_get_regs();
+
+ /* Setup config for SHA256, size = BITS(src_size) */
+ se->CONFIG_REG = (ENCMODE_SHA256 | ALG_SHA | DST_HASHREG);
+ se->SHA_CONFIG_REG = 1;
+ se->SHA_MSG_LENGTH_REG = (uint32_t)(src_size << 3);
+ se->_0x208 = 0;
+ se->_0x20C = 0;
+ se->_0x210 = 0;
+ se->SHA_MSG_LEFT_REG = (uint32_t)(src_size << 3);
+ se->_0x218 = 0;
+ se->_0x21C = 0;
+ se->_0x220 = 0;
+
+ /* Trigger the operation. */
+ trigger_se_blocking_op(OP_START, NULL, 0, src, src_size);
+
+ /* Copy output hash. */
+ for (unsigned int i = 0; i < (0x20 >> 2); i++) {
+ ((uint32_t *)dst)[i] = read32be(se->HASH_RESULT_REG, i << 2);
+ }
+}
+
+/* RNG API */
+void se_initialize_rng(unsigned int keyslot) {
+ volatile tegra_se_t *se = se_get_regs();
+
+ if (keyslot >= KEYSLOT_AES_MAX) {
+ generic_panic();
+ }
+
+ /* To initialize the RNG, we'll perform an RNG operation into an output buffer. */
+ /* This will be discarded, when done. */
+ uint8_t ALIGN(16) output_buf[0x10];
+
+ se->RNG_SRC_CONFIG_REG = 3; /* Entropy enable + Entropy lock enable */
+ se->RNG_RESEED_INTERVAL_REG = 70001;
+ se->CONFIG_REG = (ALG_RNG | DST_MEMORY);
+ se->CRYPTO_REG = (keyslot << 24) | 0x108;
+ se->RNG_CONFIG_REG = 5;
+ se->BLOCK_COUNT_REG = 0;
+ trigger_se_blocking_op(OP_START, output_buf, 0x10, NULL, 0);
+}
+
+void se_generate_random(unsigned int keyslot, void *dst, size_t size) {
+ volatile tegra_se_t *se = se_get_regs();
+
+ if (keyslot >= KEYSLOT_AES_MAX) {
+ generic_panic();
+ }
+
+ uint32_t num_blocks = size >> 4;
+ size_t aligned_size = num_blocks << 4;
+ se->CONFIG_REG = (ALG_RNG | DST_MEMORY);
+ se->CRYPTO_REG = (keyslot << 24) | 0x108;
+ se->RNG_CONFIG_REG = 4;
+
+ if (num_blocks >= 1) {
+ se->BLOCK_COUNT_REG = num_blocks - 1;
+ trigger_se_blocking_op(OP_START, dst, aligned_size, NULL, 0);
+ }
+ if (size > aligned_size) {
+ se_perform_aes_block_operation(dst + aligned_size, size - aligned_size, NULL, 0);
+ }
+}
+
+void se_generate_random_key(unsigned int dst_keyslot, unsigned int rng_keyslot) {
+ volatile tegra_se_t *se = se_get_regs();
+
+ if (dst_keyslot >= KEYSLOT_AES_MAX || rng_keyslot >= KEYSLOT_AES_MAX) {
+ generic_panic();
+ }
+
+ /* Setup Config. */
+ se->CONFIG_REG = (ALG_RNG | DST_KEYTAB);
+ se->CRYPTO_REG = (rng_keyslot << 24) | 0x108;
+ se->RNG_CONFIG_REG = 4;
+ se->BLOCK_COUNT_REG = 0;
+
+ /* Generate low part of key. */
+ se->CRYPTO_KEYTABLE_DST_REG = (dst_keyslot << 8);
+ trigger_se_blocking_op(OP_START, NULL, 0, NULL, 0);
+ /* Generate high part of key. */
+ se->CRYPTO_KEYTABLE_DST_REG = (dst_keyslot << 8) | 1;
+ trigger_se_blocking_op(OP_START, NULL, 0, NULL, 0);
+}
+
+/* SE context save API. */
+void se_set_in_context_save_mode(bool is_context_save_mode) {
+ volatile tegra_se_t *se = se_get_regs();
+
+ uint32_t val = se->_0x0;
+ if (is_context_save_mode) {
+ val |= 0x10000;
+ } else {
+ val &= 0xFFFEFFFF;
+ }
+ se->_0x0 = val;
+ /* Perform a useless read from flags reg. */
+ (void)(se->FLAGS_REG);
+}
+
+void se_generate_srk(unsigned int srkgen_keyslot) {
+ volatile tegra_se_t *se = se_get_regs();
+
+ se->CONFIG_REG = (ALG_RNG | DST_SRK);
+ se->CRYPTO_REG = (srkgen_keyslot << 24) | 0x108;
+ se->RNG_CONFIG_REG = 6;
+ se->BLOCK_COUNT_REG = 0;
+ trigger_se_blocking_op(OP_START, NULL, 0, NULL, 0);
+}
+
+void se_encrypt_with_srk(void *dst, size_t dst_size, const void *src, size_t src_size) {
+ uint8_t output[0x80];
+ uint8_t *aligned_out = (uint8_t *)(((uintptr_t)output + 0x7F) & ~0x3F);
+ if (dst_size > 0x10) {
+ generic_panic();
+ }
+
+ if (dst_size) {
+ trigger_se_blocking_op(OP_CTX_SAVE, aligned_out, dst_size, src, src_size);
+ memcpy(dst, aligned_out, dst_size);
+ } else {
+ trigger_se_blocking_op(OP_CTX_SAVE, aligned_out, 0, src, src_size);
+ }
+}
+
+void se_save_context(unsigned int srkgen_keyslot, unsigned int rng_keyslot, void *dst) {
+ volatile tegra_se_t *se = se_get_regs();
+ uint8_t _work_buf[0x80];
+ uint8_t *work_buf = (uint8_t *)(((uintptr_t)_work_buf + 0x7F) & ~0x3F);
+
+ /* Generate the SRK (context save encryption key). */
+ se_generate_random_key(srkgen_keyslot, rng_keyslot);
+ se_generate_srk(srkgen_keyslot);
+
+ se_generate_random(rng_keyslot, work_buf, 0x10);
+
+ /* Save random initial block. */
+ se->CONFIG_REG = (ALG_AES_ENC | DST_MEMORY);
+ se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_MEM);
+ se->BLOCK_COUNT_REG = 0;
+ se_encrypt_with_srk(dst, 0x10, work_buf, 0x10);
+
+ /* Save Sticky Bits. */
+ for (unsigned int i = 0; i < 0x2; i++) {
+ se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_STICKY_BITS) | (i << CTX_SAVE_STICKY_BIT_INDEX_SHIFT);
+ se->BLOCK_COUNT_REG = 0;
+ se_encrypt_with_srk(dst + 0x10 + (i * 0x10), 0x10, NULL, 0);
+ }
+
+ /* Save AES Key Table. */
+ for (unsigned int i = 0; i < KEYSLOT_AES_MAX; i++) {
+ se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_KEYTABLE_AES) | (i << CTX_SAVE_KEY_INDEX_SHIFT) | (CTX_SAVE_KEY_LOW_BITS);
+ se->BLOCK_COUNT_REG = 0;
+ se_encrypt_with_srk(dst + 0x30 + (i * 0x20), 0x10, NULL, 0);
+ se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_KEYTABLE_AES) | (i << CTX_SAVE_KEY_INDEX_SHIFT) | (CTX_SAVE_KEY_HIGH_BITS);
+ se->BLOCK_COUNT_REG = 0;
+ se_encrypt_with_srk(dst + 0x40 + (i * 0x20), 0x10, NULL, 0);
+ }
+
+ /* Save AES Original IVs. */
+ for (unsigned int i = 0; i < KEYSLOT_AES_MAX; i++) {
+ se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_KEYTABLE_AES) | (i << CTX_SAVE_KEY_INDEX_SHIFT) | (CTX_SAVE_KEY_ORIGINAL_IV);
+ se->BLOCK_COUNT_REG = 0;
+ se_encrypt_with_srk(dst + 0x230 + (i * 0x10), 0x10, NULL, 0);
+ }
+
+ /* Save AES Updated IVs */
+ for (unsigned int i = 0; i < KEYSLOT_AES_MAX; i++) {
+ se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_KEYTABLE_AES) | (i << CTX_SAVE_KEY_INDEX_SHIFT) | (CTX_SAVE_KEY_UPDATED_IV);
+ se->BLOCK_COUNT_REG = 0;
+ se_encrypt_with_srk(dst + 0x330 + (i * 0x10), 0x10, NULL, 0);
+ }
+
+ /* Save RSA Keytable. */
+ uint8_t *rsa_ctx_out = (uint8_t *)dst + 0x430;
+ for (unsigned int rsa_key = 0; rsa_key < KEYSLOT_RSA_MAX; rsa_key++) {
+ for (unsigned int mod_exp = 0; mod_exp < 2; mod_exp++) {
+ for (unsigned int sub_block = 0; sub_block < 0x10; sub_block++) {
+ se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_KEYTABLE_RSA) | ((2 * rsa_key + (1 - mod_exp)) << CTX_SAVE_RSA_KEY_INDEX_SHIFT) | (sub_block << CTX_SAVE_RSA_KEY_BLOCK_INDEX_SHIFT);
+ se->BLOCK_COUNT_REG = 0;
+ se_encrypt_with_srk(rsa_ctx_out, 0x10, NULL, 0);
+ rsa_ctx_out += 0x10;
+ }
+ }
+ }
+
+ /* Save "Known Pattern. " */
+ static const uint8_t context_save_known_pattern[0x10] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
+ se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_MEM);
+ se->BLOCK_COUNT_REG = 0;
+ se_encrypt_with_srk(dst + 0x830, 0x10, context_save_known_pattern, 0x10);
+
+ /* Save SRK into PMC registers. */
+ se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_SRK);
+ se->BLOCK_COUNT_REG = 0;
+ se_encrypt_with_srk(work_buf, 0, NULL, 0);
+ se->CONFIG_REG = 0;
+ se_encrypt_with_srk(work_buf, 0, NULL, 0);
+}
diff --git a/sept/sept-secondary/key_derivation/src/se.h b/sept/sept-secondary/key_derivation/src/se.h
new file mode 100644
index 000000000..98a6a170f
--- /dev/null
+++ b/sept/sept-secondary/key_derivation/src/se.h
@@ -0,0 +1,225 @@
+/*
+ * Copyright (c) 2018-2019 Atmosphère-NX
+ *
+ * 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
+
+#ifndef FUSEE_SE_H
+#define FUSEE_SE_H
+
+#define SE_BASE 0x70012000
+#define MAKE_SE_REG(n) MAKE_REG32(SE_BASE + n)
+
+#define KEYSLOT_SWITCH_LP0TZRAMKEY 0x2
+#define KEYSLOT_SWITCH_SRKGENKEY 0x8
+#define KEYSLOT_SWITCH_PACKAGE2KEY 0x8
+#define KEYSLOT_SWITCH_TEMPKEY 0x9
+#define KEYSLOT_SWITCH_SESSIONKEY 0xA
+#define KEYSLOT_SWITCH_RNGKEY 0xB
+#define KEYSLOT_SWITCH_MASTERKEY 0xC
+#define KEYSLOT_SWITCH_DEVICEKEY 0xD
+
+/* This keyslot was added in 4.0.0. */
+#define KEYSLOT_SWITCH_4XNEWDEVICEKEYGENKEY 0xD
+#define KEYSLOT_SWITCH_4XNEWCONSOLEKEYGENKEY 0xE
+#define KEYSLOT_SWITCH_4XOLDDEVICEKEY 0xF
+
+/* This keyslot was added in 5.0.0. */
+#define KEYSLOT_SWITCH_5XNEWDEVICEKEYGENKEY 0xA
+
+#define KEYSLOT_AES_MAX 0x10
+#define KEYSLOT_RSA_MAX 0x2
+
+#define KEYSIZE_AES_MAX 0x20
+#define KEYSIZE_RSA_MAX 0x100
+
+#define ALG_SHIFT (12)
+#define ALG_DEC_SHIFT (8)
+#define ALG_NOP (0 << ALG_SHIFT)
+#define ALG_AES_ENC (1 << ALG_SHIFT)
+#define ALG_AES_DEC ((1 << ALG_DEC_SHIFT) | ALG_NOP)
+#define ALG_RNG (2 << ALG_SHIFT)
+#define ALG_SHA (3 << ALG_SHIFT)
+#define ALG_RSA (4 << ALG_SHIFT)
+
+#define DST_SHIFT (2)
+#define DST_MEMORY (0 << DST_SHIFT)
+#define DST_HASHREG (1 << DST_SHIFT)
+#define DST_KEYTAB (2 << DST_SHIFT)
+#define DST_SRK (3 << DST_SHIFT)
+#define DST_RSAREG (4 << DST_SHIFT)
+
+#define ENCMODE_SHIFT (24)
+#define DECMODE_SHIFT (16)
+#define ENCMODE_SHA256 (5 << ENCMODE_SHIFT)
+
+#define HASH_DISABLE (0x0)
+#define HASH_ENABLE (0x1)
+
+#define OP_ABORT 0
+#define OP_START 1
+#define OP_RESTART 2
+#define OP_CTX_SAVE 3
+#define OP_RESTART_IN 4
+
+#define CTX_SAVE_SRC_SHIFT 29
+#define CTX_SAVE_SRC_STICKY_BITS (0 << CTX_SAVE_SRC_SHIFT)
+#define CTX_SAVE_SRC_KEYTABLE_AES (2 << CTX_SAVE_SRC_SHIFT)
+#define CTX_SAVE_SRC_KEYTABLE_RSA (1 << CTX_SAVE_SRC_SHIFT)
+#define CTX_SAVE_SRC_MEM (4 << CTX_SAVE_SRC_SHIFT)
+#define CTX_SAVE_SRC_SRK (6 << CTX_SAVE_SRC_SHIFT)
+
+#define CTX_SAVE_KEY_LOW_BITS 0
+#define CTX_SAVE_KEY_HIGH_BITS 1
+#define CTX_SAVE_KEY_ORIGINAL_IV 2
+#define CTX_SAVE_KEY_UPDATED_IV 3
+
+#define CTX_SAVE_STICKY_BIT_INDEX_SHIFT 24
+#define CTX_SAVE_KEY_INDEX_SHIFT 8
+#define CTX_SAVE_RSA_KEY_INDEX_SHIFT 16
+#define CTX_SAVE_RSA_KEY_BLOCK_INDEX_SHIFT 12
+
+#define RSA_2048_BYTES 0x100
+
+typedef struct {
+ uint32_t _0x0;
+ uint32_t _0x4;
+ uint32_t OPERATION_REG;
+ uint32_t INT_ENABLE_REG;
+ uint32_t INT_STATUS_REG;
+ uint32_t CONFIG_REG;
+ uint32_t IN_LL_ADDR_REG;
+ uint32_t _0x1C;
+ uint32_t _0x20;
+ uint32_t OUT_LL_ADDR_REG;
+ uint32_t _0x28;
+ uint32_t _0x2C;
+ uint8_t HASH_RESULT_REG[0x20];
+ uint8_t _0x50[0x20];
+ uint32_t CONTEXT_SAVE_CONFIG_REG;
+ uint8_t _0x74[0x18C];
+ uint32_t SHA_CONFIG_REG;
+ uint32_t SHA_MSG_LENGTH_REG;
+ uint32_t _0x208;
+ uint32_t _0x20C;
+ uint32_t _0x210;
+ uint32_t SHA_MSG_LEFT_REG;
+ uint32_t _0x218;
+ uint32_t _0x21C;
+ uint32_t _0x220;
+ uint32_t _0x224;
+ uint8_t _0x228[0x58];
+ uint32_t AES_KEY_READ_DISABLE_REG;
+ uint32_t AES_KEYSLOT_FLAGS[0x10];
+ uint8_t _0x2C4[0x3C];
+ uint32_t _0x300;
+ uint32_t CRYPTO_REG;
+ uint32_t CRYPTO_CTR_REG[4];
+ uint32_t BLOCK_COUNT_REG;
+ uint32_t AES_KEYTABLE_ADDR;
+ uint32_t AES_KEYTABLE_DATA;
+ uint32_t _0x324;
+ uint32_t _0x328;
+ uint32_t _0x32C;
+ uint32_t CRYPTO_KEYTABLE_DST_REG;
+ uint8_t _0x334[0xC];
+ uint32_t RNG_CONFIG_REG;
+ uint32_t RNG_SRC_CONFIG_REG;
+ uint32_t RNG_RESEED_INTERVAL_REG;
+ uint8_t _0x34C[0xB4];
+ uint32_t RSA_CONFIG;
+ uint32_t RSA_KEY_SIZE_REG;
+ uint32_t RSA_EXP_SIZE_REG;
+ uint32_t RSA_KEY_READ_DISABLE_REG;
+ uint32_t RSA_KEYSLOT_FLAGS[2];
+ uint32_t _0x418;
+ uint32_t _0x41C;
+ uint32_t RSA_KEYTABLE_ADDR;
+ uint32_t RSA_KEYTABLE_DATA;
+ uint8_t RSA_OUTPUT[0x100];
+ uint8_t _0x528[0x2D8];
+ uint32_t FLAGS_REG;
+ uint32_t ERR_STATUS_REG;
+ uint32_t _0x808;
+ uint32_t SPARE_0;
+ uint32_t _0x810;
+ uint32_t _0x814;
+ uint32_t _0x818;
+ uint32_t _0x81C;
+ uint8_t _0x820[0x17E0];
+} tegra_se_t;
+
+typedef struct {
+ uint32_t address;
+ uint32_t size;
+} se_addr_info_t;
+
+typedef struct {
+ uint32_t num_entries; /* Set to total entries - 1 */
+ se_addr_info_t addr_info; /* This should really be an array...but for our use case it works. */
+} se_ll_t;
+
+static inline volatile tegra_se_t *se_get_regs(void) {
+ return (volatile tegra_se_t *)SE_BASE;
+}
+
+void se_check_error_status_reg(void);
+void se_check_for_error(void);
+void se_trigger_interrupt(void);
+
+void se_validate_stored_vector(void);
+void se_generate_stored_vector(void);
+
+void se_verify_flags_cleared(void);
+
+void set_aes_keyslot_flags(unsigned int keyslot, unsigned int flags);
+void set_rsa_keyslot_flags(unsigned int keyslot, unsigned int flags);
+void clear_aes_keyslot(unsigned int keyslot);
+void clear_rsa_keyslot(unsigned int keyslot);
+
+void set_aes_keyslot(unsigned int keyslot, const void *key, size_t key_size);
+void decrypt_data_into_keyslot(unsigned int keyslot_dst, unsigned int keyslot_src, const void *wrapped_key, size_t wrapped_key_size);
+void set_rsa_keyslot(unsigned int keyslot, const void *modulus, size_t modulus_size, const void *exponent, size_t exp_size);
+void set_aes_keyslot_iv(unsigned int keyslot, const void *iv, size_t iv_size);
+void set_se_ctr(const void *ctr);
+
+/* Secure AES API */
+void se_compute_aes_128_cmac(unsigned int keyslot, void *cmac, size_t cmac_size, const void *data, size_t data_size);
+void se_compute_aes_256_cmac(unsigned int keyslot, void *cmac, size_t cmac_size, const void *data, size_t data_size);
+void se_aes_128_ecb_encrypt_block(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size);
+void se_aes_256_ecb_encrypt_block(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size);
+void se_aes_ctr_crypt(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size, const void *ctr, size_t ctr_size);
+void se_aes_ecb_decrypt_block(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size);
+void se_aes_256_cbc_encrypt(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size, const void *iv);
+void se_aes_128_cbc_decrypt(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size);
+
+/* Hash API */
+void se_calculate_sha256(void *dst, const void *src, size_t src_size);
+
+/* RSA API */
+void se_get_exp_mod_output(void *buf, size_t size);
+void se_synchronous_exp_mod(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size);
+bool se_rsa2048_pss_verify(const void *signature, size_t signature_size, const void *modulus, size_t modulus_size, const void *data, size_t data_size);
+
+/* RNG API */
+void se_initialize_rng(unsigned int keyslot);
+void se_generate_random(unsigned int keyslot, void *dst, size_t size);
+
+/* SE context save API. */
+void se_generate_srk(unsigned int srkgen_keyslot);
+void se_set_in_context_save_mode(bool is_context_save_mode);
+void se_generate_random_key(unsigned int dst_keyslot, unsigned int rng_keyslot);
+void se_save_context(unsigned int srk_keyslot, unsigned int rng_keyslot, void *dst);
+
+#endif
diff --git a/sept/sept-secondary/key_derivation/src/start.s b/sept/sept-secondary/key_derivation/src/start.s
new file mode 100644
index 000000000..f41a9493e
--- /dev/null
+++ b/sept/sept-secondary/key_derivation/src/start.s
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2018-2019 Atmosphère-NX
+ *
+ * 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 .
+ */
+
+ /* For some reason GAS doesn't know about it, even with .cpu cortex-a57 */
+#define cpuactlr_el1 s3_1_c15_c2_0
+#define cpuectlr_el1 s3_1_c15_c2_1
+
+.macro RESET_CORE
+ mov x0, #(1 << 63)
+ msr cpuactlr_el1, x0 /* disable regional clock gating */
+ isb
+ mov x0, #3
+ msr rmr_el3, x0
+ isb
+ dsb sy
+ /* Nintendo forgot to copy-paste the branch instruction below. */
+ 1:
+ wfi
+ b 1b
+.endm
+
+.macro ERRATUM_INVALIDATE_BTB_AT_BOOT
+/* Nintendo copy-pasted https://github.com/ARM-software/arm-trusted-firmware/blob/master/plat/nvidia/tegra/common/aarch64/tegra_helpers.S#L312 */
+ /*
+ * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+ /* The following comments are mine. */
+ /* mask all interrupts */
+ msr daifset, 0b1111
+
+ /*
+ Enable invalidates of branch target buffer, then flush
+ the entire instruction cache at the local level, and
+ with the reg change, the branch target buffer, then disable
+ invalidates of the branch target buffer again.
+ */
+ mrs x0, cpuactlr_el1
+ orr x0, x0, #1
+ msr cpuactlr_el1, x0
+
+ dsb sy
+ isb
+ ic iallu
+ dsb sy
+ isb
+
+ mrs x0, cpuactlr_el1
+ bic x0, x0, #1
+ msr cpuactlr_el1, x0
+
+.rept 7
+ nop /* wait long enough for the write to cpuactlr_el1 to have completed */
+.endr
+
+ /* if the OS lock is set, disable it and request a warm reset */
+ mrs x0, oslsr_el1
+ ands x0, x0, #2
+ b.eq 2f
+ mov x0, xzr
+ msr oslar_el1, x0
+
+ RESET_CORE
+
+.rept 65
+ nop /* guard against speculative excecution */
+.endr
+
+ 2:
+ /* set the OS lock */
+ mov x0, #1
+ msr oslar_el1, x0
+.endm
+
+
+.section .text.start
+.align 4
+.global _start
+_start:
+ ERRATUM_INVALIDATE_BTB_AT_BOOT
+ msr spsel, #0
+ ldr x0, =__start__
+ mov sp, x0
+ mov fp, #0x0
+ bl derive_keys
\ No newline at end of file
diff --git a/sept/sept-secondary/key_derivation/src/utils.c b/sept/sept-secondary/key_derivation/src/utils.c
new file mode 100644
index 000000000..b9e7c2551
--- /dev/null
+++ b/sept/sept-secondary/key_derivation/src/utils.c
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2018-2019 Atmosphère-NX
+ *
+ * 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
+#include "utils.h"
+#include "se.h"
+#include
+
+__attribute__ ((noreturn)) void generic_panic(void) {
+ /* Clear keyslots. */
+ clear_aes_keyslot(0xD);
+ clear_aes_keyslot(0xE);
+ for (size_t i = 0; i < 0x10; i++) {
+ clear_aes_keyslot(i);
+ }
+ clear_aes_keyslot(0xD);
+ clear_aes_keyslot(0xE);
+ while(1) { /* ... */ }
+}
diff --git a/sept/sept-secondary/key_derivation/src/utils.h b/sept/sept-secondary/key_derivation/src/utils.h
new file mode 100644
index 000000000..6c8543bf8
--- /dev/null
+++ b/sept/sept-secondary/key_derivation/src/utils.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2018-2019 Atmosphère-NX
+ *
+ * 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 FUSEE_UTILS_H
+#define FUSEE_UTILS_H
+
+#include
+#include
+#include
+#include
+
+#define BIT(n) (1u << (n))
+#define BITL(n) (1ull << (n))
+#define MASK(n) (BIT(n) - 1)
+#define MASKL(n) (BITL(n) - 1)
+#define MASK2(a,b) (MASK(a) & ~MASK(b))
+#define MASK2L(a,b) (MASKL(a) & ~MASKL(b))
+
+#define MAKE_REG32(a) (*(volatile uint32_t *)(a))
+
+#define ALIGN(m) __attribute__((aligned(m)))
+#define PACKED __attribute__((packed))
+
+#define ALINLINE __attribute__((always_inline))
+#define NOINLINE __attribute__((noinline))
+
+#define SET_SYSREG(reg, val) do { temp_reg = (val); __asm__ __volatile__ ("msr " #reg ", %0" :: "r"(temp_reg) : "memory"); } while(false)
+
+static inline uintptr_t get_physical_address(const void *addr) {
+ return (uintptr_t)addr;
+}
+
+static inline uint32_t read32le(const volatile void *dword, size_t offset) {
+ uintptr_t addr = (uintptr_t)dword + offset;
+ volatile uint32_t *target = (uint32_t *)addr;
+ return *target;
+}
+
+static inline uint32_t read32be(const volatile void *dword, size_t offset) {
+ return __builtin_bswap32(read32le(dword, offset));
+}
+
+static inline uint64_t read64le(const volatile void *qword, size_t offset) {
+ uintptr_t addr = (uintptr_t)qword + offset;
+ volatile uint64_t *target = (uint64_t *)addr;
+ return *target;
+}
+
+static inline uint64_t read64be(const volatile void *qword, size_t offset) {
+ return __builtin_bswap64(read64le(qword, offset));
+}
+
+static inline void write32le(volatile void *dword, size_t offset, uint32_t value) {
+ uintptr_t addr = (uintptr_t)dword + offset;
+ volatile uint32_t *target = (uint32_t *)addr;
+ *target = value;
+}
+
+static inline void write32be(volatile void *dword, size_t offset, uint32_t value) {
+ write32le(dword, offset, __builtin_bswap32(value));
+}
+
+static inline void write64le(volatile void *qword, size_t offset, uint64_t value) {
+ uintptr_t addr = (uintptr_t)qword + offset;
+ volatile uint64_t *target = (uint64_t *)addr;
+ *target = value;
+}
+
+static inline void write64be(volatile void *qword, size_t offset, uint64_t value) {
+ write64le(qword, offset, __builtin_bswap64(value));
+}
+
+static inline bool check_32bit_additive_overflow(uint32_t a, uint32_t b) {
+ return __builtin_add_overflow_p(a, b, (uint32_t)0);
+}
+
+static inline bool check_32bit_address_loadable(uintptr_t addr) {
+ /* FWIW the bootROM forbids loading anything between 0x40000000 and 0x40010000, using it for itself... */
+ return (addr >= 0x40010000u && addr < 0x40040000u) || addr >= 0x80000000u;
+}
+
+static inline bool check_32bit_address_range_loadable(uintptr_t addr, size_t size) {
+ return
+ !__builtin_add_overflow_p(addr, size, (uintptr_t)0) && /* the range doesn't overflow */
+ check_32bit_address_loadable(addr) && check_32bit_address_loadable(addr + size) && /* bounds are valid */
+ !(addr >= 0x40010000u && addr < 0x40040000u && addr + size >= 0x40040000u) /* the range doesn't cross MMIO */
+ ;
+}
+
+bool overlaps(uint64_t as, uint64_t ae, uint64_t bs, uint64_t be);
+static inline bool overlaps_a(const void *as, const void *ae, const void *bs, const void *be) {
+ return overlaps((uint64_t)(uintptr_t)as, (uint64_t)(uintptr_t)ae, (uint64_t)(uintptr_t)bs, (uint64_t)(uintptr_t)be);
+}
+
+static inline bool check_32bit_address_range_in_program(uintptr_t addr, size_t size) {
+ extern uint8_t __chainloader_start__[], __chainloader_end__[];
+ extern uint8_t __stack_bottom__[], __stack_top__[];
+ extern uint8_t __start__[], __end__[];
+ uint8_t *start = (uint8_t *)addr, *end = start + size;
+
+ return overlaps_a(start, end, __chainloader_start__, __chainloader_end__) ||
+ overlaps_a(start, end, __stack_bottom__, __stack_top__) ||
+ overlaps_a(start, end, (void *)0xC0000000, (void *)0xC03C0000) || /* framebuffer */
+ overlaps_a(start, end, __start__, __end__);
+}
+
+__attribute__((noreturn)) void generic_panic(void);
+
+#endif
diff --git a/sept/sept-secondary/linker.ld b/sept/sept-secondary/linker.ld
index 27dba8fc7..f6597f78f 100644
--- a/sept/sept-secondary/linker.ld
+++ b/sept/sept-secondary/linker.ld
@@ -20,8 +20,8 @@ MEMORY
SECTIONS
{
PROVIDE(__start__ = 0x40010000);
- PROVIDE(__stack_top__ = 0x40010000);
- PROVIDE(__stack_bottom__ = 0x4000C000);
+ PROVIDE(__stack_top__ = 0x4003C000);
+ PROVIDE(__stack_bottom__ = 0x40038000);
PROVIDE(__heap_start__ = 0);
PROVIDE(__heap_end__ = 0);
diff --git a/sept/sept-secondary/sept_sign.py b/sept/sept-secondary/sept_sign.py
index ba108c1fc..a5ca66a36 100644
--- a/sept/sept-secondary/sept_sign.py
+++ b/sept/sept-secondary/sept_sign.py
@@ -1,5 +1,5 @@
#!/usr/bin/env python
-import sys
+import sys, os
from struct import pack as pk, unpack as up
from Crypto.Cipher import AES
from Crypto.Hash import CMAC
@@ -41,7 +41,7 @@ def get_last_block_for_desired_mac(key, data, desired_mac):
return last_block
-def sign_encrypt_code(code, sig_key, enc_key, iv, desired_mac):
+def sign_encrypt_code(code, sig_key, enc_key, iv, desired_mac, version):
# Pad with 0x20 of zeroes.
code = code + bytearray(0x20)
code_len = len(code)
@@ -49,6 +49,9 @@ def sign_encrypt_code(code, sig_key, enc_key, iv, desired_mac):
code_len &= ~0xFFF
code = code + bytearray(code_len - len(code))
+ # Insert version
+ code = code[:8] + pk('.
+ */
+
+#include
+
+#include "cluster.h"
+#include "flow.h"
+#include "sysreg.h"
+#include "i2c.h"
+#include "car.h"
+#include "mc.h"
+#include "timers.h"
+#include "pmc.h"
+#include "max77620.h"
+
+void _cluster_enable_power()
+{
+ /* Reboot I2C5. */
+ clkrst_reboot(CARDEVICE_I2C5);
+ i2c_init(I2C_5);
+
+ uint8_t val = 0;
+ i2c_query(I2C_5, MAX77620_PWR_I2C_ADDR, MAX77620_REG_AME_GPIO, &val, 1);
+
+ val &= 0xDF;
+ i2c_send(I2C_5, MAX77620_PWR_I2C_ADDR, MAX77620_REG_AME_GPIO, &val, 1);
+ val = 0x09;
+ i2c_send(I2C_5, MAX77620_PWR_I2C_ADDR, MAX77620_REG_GPIO5, &val, 1);
+
+ /* Enable power. */
+ val = 0x20;
+ i2c_send(I2C_5, MAX77621_CPU_I2C_ADDR, 0x02, &val, 1);
+ val = 0x8D;
+ i2c_send(I2C_5, MAX77621_CPU_I2C_ADDR, 0x03, &val, 1);
+ val = 0xB7;
+ i2c_send(I2C_5, MAX77621_CPU_I2C_ADDR, 0x00, &val, 1);
+ val = 0xB7;
+ i2c_send(I2C_5, MAX77621_CPU_I2C_ADDR, 0x01, &val, 1);
+}
+
+int _cluster_pmc_enable_partition(uint32_t part, uint32_t toggle)
+{
+ volatile tegra_pmc_t *pmc = pmc_get_regs();
+
+ /* Check if the partition has already been turned on. */
+ if (pmc->pwrgate_status & part)
+ return 1;
+
+ uint32_t i = 5001;
+ while (pmc->pwrgate_toggle & 0x100)
+ {
+ udelay(1);
+ i--;
+ if (i < 1)
+ return 0;
+ }
+
+ pmc->pwrgate_toggle = (toggle | 0x100);
+
+ i = 5001;
+ while (i > 0)
+ {
+ if (pmc->pwrgate_status & part)
+ break;
+
+ udelay(1);
+ i--;
+ }
+
+ return 1;
+}
+
+void cluster_boot_cpu0(uint32_t entry)
+{
+ volatile tegra_car_t *car = car_get_regs();
+
+ /* Set ACTIVE_CLUSER to FAST. */
+ FLOW_CTLR_BPMP_CLUSTER_CONTROL_0 &= 0xFFFFFFFE;
+
+ _cluster_enable_power();
+
+ if (!(car->pllx_base & 0x40000000))
+ {
+ car->pllx_misc3 &= 0xFFFFFFF7;
+ udelay(2);
+ car->pllx_base = 0x80404E02;
+ car->pllx_base = 0x404E02;
+ car->pllx_misc = ((car->pllx_misc & 0xFFFBFFFF) | 0x40000);
+ car->pllx_base = 0x40404E02;
+ }
+
+ while (!(car->pllx_base & 0x8000000)) {
+ /* Wait. */
+ }
+
+ /* Configure MSELECT source and enable clock. */
+ car->clk_source_mselect = ((car->clk_source_mselect & 0x1FFFFF00) | 6);
+ car->clk_out_enb_v = ((car->clk_out_enb_v & 0xFFFFFFF7) | 8);
+
+ /* Configure initial CPU clock frequency and enable clock. */
+ car->cclk_brst_pol = 0x20008888;
+ car->super_cclk_div = 0x80000000;
+ car->clk_enb_v_set = 1;
+
+ clkrst_reboot(CARDEVICE_CORESIGHT);
+
+ /* CAR2PMC_CPU_ACK_WIDTH should be set to 0. */
+ car->cpu_softrst_ctrl2 &= 0xFFFFF000;
+
+ /* Enable CPU rail. */
+ _cluster_pmc_enable_partition(1, 0);
+
+ /* Enable cluster 0 non-CPU. */
+ _cluster_pmc_enable_partition(0x8000, 15);
+
+ /* Enable CE0. */
+ _cluster_pmc_enable_partition(0x4000, 14);
+
+ /* Request and wait for RAM repair. */
+ FLOW_CTLR_RAM_REPAIR_0 = 1;
+ while (!(FLOW_CTLR_RAM_REPAIR_0 & 2)) {
+ /* Wait. */
+ }
+
+ MAKE_EXCP_VEC_REG(0x100) = 0;
+
+ /* Check for reset vector lock. */
+ if (SB_CSR_0 & 2) {
+ generic_panic();
+ }
+
+ /* Set reset vector. */
+ SB_AA64_RESET_LOW_0 = (entry | 1);
+ SB_AA64_RESET_HIGH_0 = 0;
+
+ /* Non-secure reset vector write disable. */
+ SB_CSR_0 = 2;
+ (void)SB_CSR_0;
+
+ /* Validate reset vector lock + RESET_LOW/HIGH values. */
+ if (!(SB_CSR_0 & 2)) {
+ generic_panic();
+ }
+
+ /* TODO: Should we even bother taking as a parameter? */
+ if (SB_AA64_RESET_LOW_0 != (0x4003D000 | 1) || SB_AA64_RESET_HIGH_0 != 0) {
+ generic_panic();
+ }
+
+ /* Set CPU_STRICT_TZ_APERTURE_CHECK. */
+ /* NOTE: [4.0.0+] This was added, but it breaks Exosphère. */
+ /* MAKE_MC_REG(MC_TZ_SECURITY_CTRL) = 1; */
+
+ /* Clear MSELECT reset. */
+ car->rst_dev_v &= 0xFFFFFFF7;
+
+ /* Clear NONCPU reset. */
+ car->rst_cpug_cmplx_clr = 0x20000000;
+
+ /* Clear CPU{0,1,2,3} POR and CORE, CX0, L2, and DBG reset.*/
+ /* NOTE: [5.0.0+] This was changed so only CPU0 reset is cleared. */
+ /* car->rst_cpug_cmplx_clr = 0x411F000F; */
+ car->rst_cpug_cmplx_clr = 0x41010001;
+}
diff --git a/sept/sept-secondary/src/cluster.h b/sept/sept-secondary/src/cluster.h
new file mode 100644
index 000000000..2f87fbd90
--- /dev/null
+++ b/sept/sept-secondary/src/cluster.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2018 naehrwert
+ * Copyright (c) 2018-2019 Atmosphère-NX
+ *
+ * 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 FUSEE_CLUSTER_H_
+#define FUSEE_CLUSTER_H_
+
+void cluster_boot_cpu0(uint32_t entry);
+
+#endif
diff --git a/sept/sept-secondary/src/key_derivation.c b/sept/sept-secondary/src/key_derivation.c
index ea9c4f714..3b87c5a98 100644
--- a/sept/sept-secondary/src/key_derivation.c
+++ b/sept/sept-secondary/src/key_derivation.c
@@ -17,64 +17,65 @@
#include
#include "key_derivation.h"
#include "se.h"
+#include "cluster.h"
+#include "timers.h"
#include "fuse.h"
#include "utils.h"
-#define AL16 ALIGN(16)
+#define u8 uint8_t
+#define u32 uint32_t
+#include "key_derivation_bin.h"
+#undef u8
+#undef u32
-static const uint8_t AL16 keyblob_seed_00[0x10] = {
- 0xDF, 0x20, 0x6F, 0x59, 0x44, 0x54, 0xEF, 0xDC, 0x70, 0x74, 0x48, 0x3B, 0x0D, 0xED, 0x9F, 0xD3
-};
-static const uint8_t AL16 masterkey_seed[0x10] = {
- 0xD8, 0xA2, 0x41, 0x0A, 0xC6, 0xC5, 0x90, 0x01, 0xC6, 0x1D, 0x6A, 0x26, 0x7C, 0x51, 0x3F, 0x3C
-};
+void derive_keys(uint32_t version) {
+ /* Clear mailbox. */
+ volatile uint32_t *mailbox = (volatile uint32_t *)0x4003FF00;
+ while (*mailbox != 0) {
+ *mailbox = 0;
+ }
-static const uint8_t AL16 devicekey_seed[0x10] = {
- 0x4F, 0x02, 0x5F, 0x0E, 0xB6, 0x6D, 0x11, 0x0E, 0xDC, 0x32, 0x7D, 0x41, 0x86, 0xC2, 0xF4, 0x78
-};
+ /* Set derivation id. */
+ *((volatile uint32_t *)0x4003E800) = version;
-static const uint8_t AL16 devicekey_4x_seed[0x10] = {
- 0x0C, 0x91, 0x09, 0xDB, 0x93, 0x93, 0x07, 0x81, 0x07, 0x3C, 0xC4, 0x16, 0x22, 0x7C, 0x6C, 0x28
-};
+ /* Copy key derivation stub into IRAM high. */
+ for (size_t i = 0; i < key_derivation_bin_size; i += sizeof(uint32_t)) {
+ write32le((void *)0x4003D000, i, read32le(key_derivation_bin, i));
+ }
-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
-};
+ cluster_boot_cpu0(0x4003D000);
-static const uint8_t AL16 new_master_kek_seed_7x[0x10] = {
- 0x9A, 0x3E, 0xA9, 0xAB, 0xFD, 0x56, 0x46, 0x1C, 0x9B, 0xF6, 0x48, 0x7F, 0x5C, 0xFA, 0x09, 0x5C
-};
-
-void derive_7x_keys(const void *tsec_key, void *tsec_root_key) {
- uint8_t AL16 work_buffer[0x10];
-
- /* Set keyslot flags properly in preparation of derivation. */
- set_aes_keyslot_flags(0xE, 0x15);
- set_aes_keyslot_flags(0xD, 0x15);
-
- /* Set the TSEC key. */
- set_aes_keyslot(0xD, tsec_key, 0x10);
-
- /* Derive keyblob key 0. */
- se_aes_ecb_decrypt_block(0xD, work_buffer, 0x10, keyblob_seed_00, 0x10);
- decrypt_data_into_keyslot(0xF, 0xE, work_buffer, 0x10);
-
- /* Clear the SBK. */
- clear_aes_keyslot(0xE);
-
- /* Derive the master kek. */
- set_aes_keyslot(0xC, tsec_root_key, 0x10);
- decrypt_data_into_keyslot(0xC, 0xC, new_master_kek_seed_7x, 0x10);
-
- /* Derive keys for exosphere. */
- decrypt_data_into_keyslot(0xA, 0xF, devicekey_4x_seed, 0x10);
- decrypt_data_into_keyslot(0xF, 0xF, devicekey_seed, 0x10);
- decrypt_data_into_keyslot(0xE, 0xC, masterkey_4x_seed, 0x10);
- decrypt_data_into_keyslot(0xC, 0xC, masterkey_seed, 0x10);
-
- /* Clear master kek from memory. */
- for (size_t i = 0; i < sizeof(work_buffer); i++) {
- work_buffer[i] = 0xCC;
+ while (*mailbox != 7) {
+ /* Wait until keys have been derived. */
}
}
+
+void load_keys(const uint8_t *se_state) {
+ /* Clear keyslots up to 0xA. */
+ for (size_t i = 0; i < 0xA; i++) {
+ clear_aes_keyslot(i);
+ }
+
+ /* Copy device keygen key out of state keyslot 0xA into keyslot 0xA. */
+ set_aes_keyslot(0xA, se_state + 0x30 + (0xA * 0x20), 0x10);
+
+ /* Clear keyslot 0xB. */
+ clear_aes_keyslot(0xB);
+
+ /* Copy master key out of state keyslot 0xC into keyslot 0xC. */
+ set_aes_keyslot(0xC, se_state + 0x30 + (0xC * 0x20), 0x10);
+
+ /* Copy firmware device key out of state keyslot 0xE into keyslot 0xD. */
+ set_aes_keyslot(0xD, se_state + 0x30 + (0xE * 0x20), 0x10);
+
+ /* Clear keyslot 0xE. */
+ clear_aes_keyslot(0xE);
+
+ /* Copy device key out of state keyslot 0xF into keyslot 0xF. */
+ set_aes_keyslot(0xF, se_state + 0x30 + (0xF * 0x20), 0x10);
+
+ /* Set keyslot flags properly in preparation for secmon. */
+ set_aes_keyslot_flags(0xE, 0x15);
+ set_aes_keyslot_flags(0xD, 0x15);
+}
diff --git a/sept/sept-secondary/src/key_derivation.h b/sept/sept-secondary/src/key_derivation.h
index da77a1490..764b69c32 100644
--- a/sept/sept-secondary/src/key_derivation.h
+++ b/sept/sept-secondary/src/key_derivation.h
@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
-
+
#ifndef SEPT_KEYDERIVATION_H
#define SEPT_KEYDERIVATION_H
@@ -21,6 +21,7 @@
#include
#include
-void derive_7x_keys(const void *tsec_key, void *tsec_root_key);
+void derive_keys(uint32_t version);
+void load_keys(const uint8_t *se_state);
#endif
diff --git a/sept/sept-secondary/src/main.c b/sept/sept-secondary/src/main.c
index 2195644f3..bc8f773c7 100644
--- a/sept/sept-secondary/src/main.c
+++ b/sept/sept-secondary/src/main.c
@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
-
+
#include "utils.h"
#include "exception_handlers.h"
#include "panic.h"
@@ -22,6 +22,7 @@
#include "se.h"
#include "pmc.h"
#include "emc.h"
+#include "sysreg.h"
#include "key_derivation.h"
#include "timers.h"
#include "fs_utils.h"
@@ -39,9 +40,6 @@ extern void (*__program_exit_callback)(int rc);
static void *g_framebuffer;
-static uint32_t g_tsec_root_key[0x4] = {0};
-static uint32_t g_tsec_key[0x4] = {0};
-
static bool has_rebooted(void) {
return MAKE_REG32(0x4003FFFC) == 0xFAFAFAFA;
}
@@ -51,27 +49,19 @@ static void set_has_rebooted(bool rebooted) {
}
-static void exfiltrate_keys_and_reboot_if_needed(void) {
+static void exfiltrate_keys_and_reboot_if_needed(uint32_t version) {
volatile tegra_pmc_t *pmc = pmc_get_regs();
uint8_t *enc_se_state = (uint8_t *)0x4003E000;
uint8_t *dec_se_state = (uint8_t *)0x4003F000;
-
+
if (!has_rebooted()) {
/* Prepare for a reboot before doing anything else. */
prepare_for_reboot_to_self();
set_has_rebooted(true);
-
- /* Save the security engine context. */
- se_get_regs()->_0x4 = 0x0;
- se_set_in_context_save_mode(true);
- se_save_context(KEYSLOT_SWITCH_SRKGENKEY, KEYSLOT_SWITCH_RNGKEY, enc_se_state);
- se_set_in_context_save_mode(false);
-
- /* Clear all keyslots. */
- for (size_t k = 0; k < 0x10; k++) {
- clear_aes_keyslot(k);
- }
-
+
+ /* Derive keys. */
+ derive_keys(version);
+
reboot_to_self();
} else {
/* Decrypt the security engine state. */
@@ -82,13 +72,10 @@ static void exfiltrate_keys_and_reboot_if_needed(void) {
context_key[3] = pmc->secure_scratch7;
set_aes_keyslot(0xC, context_key, sizeof(context_key));
se_aes_128_cbc_decrypt(0xC, dec_se_state, 0x840, enc_se_state, 0x840);
-
- /* Copy out tsec key + tsec root key. */
- for (size_t i = 0; i < 0x10; i += 4) {
- g_tsec_key[i/4] = MAKE_REG32((uintptr_t)(dec_se_state) + 0x1B0 + i);
- g_tsec_root_key[i/4] = MAKE_REG32((uintptr_t)(dec_se_state) + 0x1D0 + i);
- }
-
+
+ /* Load keys in from decrypted state. */
+ load_keys(dec_se_state);
+
/* Clear the security engine state. */
for (size_t i = 0; i < 0x840; i += 4) {
MAKE_REG32((uintptr_t)(enc_se_state) + i) = 0xCCCCCCCC;
@@ -101,11 +88,6 @@ static void exfiltrate_keys_and_reboot_if_needed(void) {
pmc->secure_scratch5 = 0xCCCCCCCC;
pmc->secure_scratch6 = 0xCCCCCCCC;
pmc->secure_scratch7 = 0xCCCCCCCC;
-
- /* Clear all keyslots except for SBK/SSK. */
- for (size_t k = 0; k < 0xE; k++) {
- clear_aes_keyslot(k);
- }
}
}
@@ -115,9 +97,6 @@ static void setup_env(void) {
/* Initialize hardware. */
nx_hwinit();
- /* Check for panics. */
- check_and_display_panic();
-
/* Zero-fill the framebuffer and register it as printk provider. */
video_init(g_framebuffer);
@@ -126,7 +105,7 @@ static void setup_env(void) {
/* Set the framebuffer. */
display_init_framebuffer(g_framebuffer);
-
+
/* Draw splash. */
draw_splash((volatile uint32_t *)g_framebuffer);
@@ -136,7 +115,7 @@ static void setup_env(void) {
/* Set up the exception handlers. */
setup_exception_handlers();
-
+
/* Mount the SD card. */
mount_sd();
}
@@ -154,33 +133,29 @@ static void exit_callback(int rc) {
relocate_and_chainload();
}
-int main(void) {
+int sept_main(uint32_t version) {
const char *stage2_path;
stage2_args_t *stage2_args;
uint32_t stage2_version = 0;
ScreenLogLevel log_level = SCREEN_LOG_LEVEL_NONE;
-
+
+ /* Validate that we can safely boot the CCPLEX. */
+ if (SB_CSR_0 & 2) {
+ generic_panic();
+ }
+
/* Extract keys from the security engine, which TSEC FW locked down. */
- exfiltrate_keys_and_reboot_if_needed();
-
+ exfiltrate_keys_and_reboot_if_needed(version);
+
/* Override the global logging level. */
log_set_log_level(log_level);
-
+
/* Initialize the display, console, etc. */
setup_env();
-
- /* Derive keys. */
- derive_7x_keys(g_tsec_key, g_tsec_root_key);
-
- /* Cleanup keys in memory. */
- for (size_t i = 0; i < 0x10; i += 4) {
- g_tsec_root_key[i/4] = 0xCCCCCCCC;
- g_tsec_key[i/4] = 0xCCCCCCCC;
- }
-
+
/* Mark EMC scratch to say that sept has run. */
MAKE_EMC_REG(EMC_SCRATCH0) |= 0x80000000;
-
+
/* Load the loader payload into DRAM. */
load_stage2();
@@ -194,10 +169,10 @@ int main(void) {
stage2_args->display_initialized = false;
strcpy(stage2_args->bct0, "");
g_chainloader_argc = 2;
-
+
/* Wait a while. */
mdelay(1500);
-
+
/* Deinitialize the display, console, etc. */
cleanup_env();
diff --git a/sept/sept-secondary/src/panic.c b/sept/sept-secondary/src/panic.c
index cbd81bfb2..0884463d2 100644
--- a/sept/sept-secondary/src/panic.c
+++ b/sept/sept-secondary/src/panic.c
@@ -13,76 +13,17 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
-
+#include
+#include
#include "panic.h"
#include "di.h"
#include "pmc.h"
+#include "se.h"
#include "fuse.h"
#include "utils.h"
static uint32_t g_panic_code = 0;
-void check_and_display_panic(void) {
- /* We also handle our own panics. */
- /* In the case of our own panics, we assume that the display has already been initialized. */
- bool has_panic = APBDEV_PMC_RST_STATUS_0 != 0 || g_panic_code != 0;
- uint32_t code = g_panic_code == 0 ? APBDEV_PMC_SCRATCH200_0 : g_panic_code;
-
- has_panic = has_panic && !(APBDEV_PMC_RST_STATUS_0 != 1 && code == PANIC_CODE_SAFEMODE);
-
- if (has_panic) {
- uint32_t color;
-
- /* Check for predefined codes: */
- switch (code & MASK(20)) {
- case 0x01: /* Package2 signature verification failed. */
- case 0x02: /* Package2 meta verification failed. */
- case 0x03: /* Package2 version check failed. */
- case 0x04: /* Package2 payload verification failed. */
- color = PANIC_COLOR_KERNEL;
- break;
- case 0x05: /* Unknown SMC. */
- case 0x06: /* Unknown Abort. */
- color = PANIC_COLOR_SECMON_GENERIC;
- break;
- case 0x07: /* Invalid CPU context. */
- case 0x08: /* Invalid SE state. */
- case 0x09: /* CPU is already awake (2.0.0+). */
- color = PANIC_COLOR_SECMON_DEEPSLEEP;
- break;
- case 0x10: /* Unknown exception. */
- color = PANIC_COLOR_SECMON_EXCEPTION;
- break;
- case 0x30: /* General bootloader error. */
- case 0x31: /* Invalid DRAM ID. */
- case 0x32: /* Invalid size. */
- case 0x33: /* Invalid arguement. */
- case 0x34: /* Bad GPT. */
- case 0x35: /* Failed to boot SafeMode. */
- case 0x36: /* Activity monitor fired (4.0.0+). */
- color = PANIC_COLOR_BOOTLOADER_GENERIC;
- break;
- case 0x40: /* Kernel panic. */
- color = PANIC_COLOR_KERNEL;
- break;
- default:
- color = code >> 20;
- color |= color << 4;
- break;
- }
-
- if (g_panic_code == 0) {
- display_init();
- }
-
- display_color_screen(color);
- wait_for_button_and_reboot();
- } else {
- g_panic_code = 0;
- APBDEV_PMC_SCRATCH200_0 = 0;
- }
-}
-
__attribute__ ((noreturn)) void panic(uint32_t code) {
/* Set panic code. */
if (g_panic_code == 0) {
@@ -90,9 +31,13 @@ __attribute__ ((noreturn)) void panic(uint32_t code) {
APBDEV_PMC_SCRATCH200_0 = code;
}
+ /* Clear all keyslots. */
+ for (size_t i = 0; i < 0x10; i++) {
+ clear_aes_keyslot(i);
+ }
+
fuse_disable_programming();
APBDEV_PMC_CRYPTO_OP_0 = 1; /* Disable all SE operations. */
- check_and_display_panic();
while(true);
}
diff --git a/sept/sept-secondary/src/panic.h b/sept/sept-secondary/src/panic.h
index 848a3fd81..e502a8551 100644
--- a/sept/sept-secondary/src/panic.h
+++ b/sept/sept-secondary/src/panic.h
@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
-
+
#ifndef FUSEE_PANIC_H
#define FUSEE_PANIC_H
@@ -28,7 +28,6 @@
#define PANIC_CODE_SAFEMODE 0x00000020
-void check_and_display_panic(void);
__attribute__ ((noreturn)) void panic(uint32_t code);
#endif
diff --git a/sept/sept-secondary/src/start.s b/sept/sept-secondary/src/start.s
index b79cfce26..73cdf5b10 100644
--- a/sept/sept-secondary/src/start.s
+++ b/sept/sept-secondary/src/start.s
@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
-
+
.macro CLEAR_GPR_REG_ITER
mov r\@, #0
.endm
@@ -26,13 +26,18 @@
_start:
/* Switch to system mode, mask all interrupts, clear all flags */
msr cpsr_cxsf, #0xDF
+ b begin_relocation_loop
+ _version:
+ .word 0x00000000 /* Version. */
+ .word 0x00000000 /* Reserved. */
+ begin_relocation_loop:
/* Relocate ourselves if necessary */
ldr r2, =__start__
adr r3, _start
cmp r2, r3
beq _relocation_loop_end
-
+
/* If we are relocating, we are not rebooting to ourselves. Note that. */
ldr r0, =0x4003FFFC
mov r1, #0x0
@@ -50,12 +55,12 @@ _start:
ldr r12, =_second_relocation_start
bx r12
-
+
_second_relocation_start:
ldr r4, =__bss_start__
sub r4, r4, r2
mov r1, #0x0
-
+
_second_relocation_loop:
ldmia r3!, {r5-r12}
stmia r2!, {r5-r12}
@@ -67,7 +72,7 @@ _start:
bx r12
_relocation_loop_end:
-
+
/* Set the stack pointer */
ldr sp, =__stack_top__
mov fp, #0
@@ -78,7 +83,9 @@ _start:
CLEAR_GPR_REG_ITER
.endr
ldr lr, =__program_exit
- b main
+ ldr r0, =_version
+ ldr r0, [r0]
+ b sept_main
/* No need to include this in normal programs: */
.section .chainloader.text.start, "ax", %progbits
diff --git a/sept/sept-secondary/src/utils.c b/sept/sept-secondary/src/utils.c
index fa939c0cb..b3c09d290 100644
--- a/sept/sept-secondary/src/utils.c
+++ b/sept/sept-secondary/src/utils.c
@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
-
+
#include
#include
#include "utils.h"
@@ -66,13 +66,16 @@ __attribute__((noreturn)) void pmc_reboot(uint32_t scratch0) {
}
void prepare_for_reboot_to_self(void) {
+ /* Write warmboot to scratch0. */
+ APBDEV_PMC_SCRATCH0_0 = 0x00000001;
+
/* Patch SDRAM init to perform an SVC immediately after second write */
APBDEV_PMC_SCRATCH45_0 = 0x2E38DFFF;
APBDEV_PMC_SCRATCH46_0 = 0x6001DC28;
/* Set SVC handler to jump to reboot stub in IRAM. */
APBDEV_PMC_SCRATCH33_0 = 0x4003F000;
APBDEV_PMC_SCRATCH40_0 = 0x6000F208;
-
+
/* Copy reboot stub into IRAM high. */
for (size_t i = 0; i < rebootstub_bin_size; i += sizeof(uint32_t)) {
write32le((void *)0x4003F000, i, read32le(rebootstub_bin, i));
@@ -82,7 +85,7 @@ void prepare_for_reboot_to_self(void) {
__attribute__((noreturn)) void reboot_to_self(void) {
/* Prep IRAM for reboot. */
prepare_for_reboot_to_self();
-
+
/* Trigger warm reboot. */
pmc_reboot(1 << 0);
}
diff --git a/stratosphere/libstratosphere b/stratosphere/libstratosphere
index 777984476..7e0ed3b38 160000
--- a/stratosphere/libstratosphere
+++ b/stratosphere/libstratosphere
@@ -1 +1 @@
-Subproject commit 777984476ea7b1da56c9a3fd3f55575a8b899896
+Subproject commit 7e0ed3b38f437791fdd398c7058c376c9d2a6853
diff --git a/stratosphere/loader/source/ldr_npdm.hpp b/stratosphere/loader/source/ldr_npdm.hpp
index b0aae5731..c8c18f76a 100644
--- a/stratosphere/loader/source/ldr_npdm.hpp
+++ b/stratosphere/loader/source/ldr_npdm.hpp
@@ -37,7 +37,7 @@ class NpdmUtils {
u8 default_cpuid;
u32 _0x10;
u32 system_resource_size;
- u32 process_category;
+ u32 version;
u32 main_stack_size;
char title_name[0x50];
u32 aci0_offset;
diff --git a/stratosphere/loader/source/ldr_process_creation.cpp b/stratosphere/loader/source/ldr_process_creation.cpp
index 9a1449d4e..e76cdf20f 100644
--- a/stratosphere/loader/source/ldr_process_creation.cpp
+++ b/stratosphere/loader/source/ldr_process_creation.cpp
@@ -25,6 +25,35 @@
#include "ldr_npdm.hpp"
#include "ldr_nso.hpp"
+static inline bool IsDisallowedVersion810(const u64 title_id, const u32 version) {
+ return version == 0 &&
+ (title_id == TitleId_Settings ||
+ title_id == TitleId_Bus ||
+ title_id == TitleId_Audio ||
+ title_id == TitleId_NvServices ||
+ title_id == TitleId_Ns ||
+ title_id == TitleId_Ssl ||
+ title_id == TitleId_Es ||
+ title_id == TitleId_Creport ||
+ title_id == TitleId_Ro);
+}
+
+Result ProcessCreation::ValidateProcessVersion(u64 title_id, u32 version) {
+ if (GetRuntimeFirmwareVersion() < FirmwareVersion_810) {
+ return ResultSuccess;
+ } else {
+#ifdef LDR_VALIDATE_PROCESS_VERSION
+ if (IsDisallowedVersion810(title_id, version)) {
+ return ResultLoaderInvalidVersion;
+ } else {
+ return ResultSuccess;
+ }
+#else
+ return ResultSuccess;
+#endif
+ }
+}
+
Result ProcessCreation::InitializeProcessInfo(NpdmUtils::NpdmInfo *npdm, Handle reslimit_h, u64 arg_flags, ProcessInfo *out_proc_info) {
/* Initialize a ProcessInfo using an npdm. */
*out_proc_info = {};
@@ -36,8 +65,8 @@ Result ProcessCreation::InitializeProcessInfo(NpdmUtils::NpdmInfo *npdm, Handle
/* Set title id. */
out_proc_info->title_id = npdm->aci0->title_id;
- /* Set process category. */
- out_proc_info->process_category = npdm->header->process_category;
+ /* Set version. */
+ out_proc_info->version = npdm->header->version;
/* Copy reslimit handle raw. */
out_proc_info->reslimit_h = reslimit_h;
@@ -145,6 +174,9 @@ Result ProcessCreation::CreateProcess(Handle *out_process_h, u64 index, char *nc
/* Load the process's NPDM. */
R_TRY(NpdmUtils::LoadNpdmFromCache(target_process->tid_sid.title_id, &npdm_info));
+ /* Validate version. */
+ R_TRY(ValidateProcessVersion(target_process->tid_sid.title_id, npdm_info.header->version));
+
/* Validate the title we're loading is what we expect. */
if (npdm_info.aci0->title_id < npdm_info.acid->title_id_range_min || npdm_info.aci0->title_id > npdm_info.acid->title_id_range_max) {
return ResultLoaderInvalidProgramId;
diff --git a/stratosphere/loader/source/ldr_process_creation.hpp b/stratosphere/loader/source/ldr_process_creation.hpp
index 1914122d1..df975d063 100644
--- a/stratosphere/loader/source/ldr_process_creation.hpp
+++ b/stratosphere/loader/source/ldr_process_creation.hpp
@@ -27,7 +27,7 @@ class ProcessCreation {
public:
struct ProcessInfo {
u8 name[12];
- u32 process_category;
+ u32 version;
u64 title_id;
u64 code_addr;
u32 code_num_pages;
@@ -35,6 +35,7 @@ class ProcessCreation {
Handle reslimit_h;
u32 system_resource_num_pages;
};
+ static Result ValidateProcessVersion(u64 title_id, u32 version);
static Result InitializeProcessInfo(NpdmUtils::NpdmInfo *npdm, Handle reslimit_h, u64 arg_flags, ProcessInfo *out_proc_info);
static Result CreateProcess(Handle *out_process_h, u64 index, char *nca_path, LaunchQueue::LaunchItem *launch_item, u64 arg_flags, Handle reslimit_h);
};
\ No newline at end of file