diff --git a/exosphere/src/masterkey.c b/exosphere/src/masterkey.c
index b894a7721..d1ef71c71 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
@@ -83,7 +83,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 +91,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. */
@@ -135,23 +135,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/package2.c b/exosphere/src/package2.c
index 66d8828fe..4ee7f23bf 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();
@@ -198,7 +157,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 +246,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? */
@@ -500,16 +459,16 @@ static void copy_warmboot_bin_to_dram() {
}
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 +503,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:
@@ -585,7 +544,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 +556,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 +579,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 +589,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 +600,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 +608,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 +619,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/sept/sept-secondary/Makefile b/sept/sept-secondary/Makefile
index d41959363..03a8a5f8c 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,15 +112,18 @@ 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):
+check_key_derivation:
+ @$(MAKE) -C key_derivation
+
+$(BUILD): check_rebootstub check_key_derivation
ifeq ($(strip $(SEPT_ENC_PATH)),)
@[ -d $@ ] || mkdir -p $@
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
@@ -132,6 +136,7 @@ endif
clean:
@echo clean ...
@$(MAKE) -C $(AMS)/exosphere/rebootstub clean
+ @$(MAKE) -C key_derivation clean
@rm -fr $(BUILD) $(TARGET).bin $(TARGET).enc $(TARGET).elf
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..65eb9290b
--- /dev/null
+++ b/sept/sept-secondary/key_derivation/src/key_derivation.c
@@ -0,0 +1,149 @@
+/*
+ * 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"
+
+#define AL16 __attribute__((aligned(16)))
+
+#define DERIVATION_ID_MAX 1
+
+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 master_kek_seeds[DERIVATION_ID_MAX][0x10] = {
+ {0x9A, 0x3E, 0xA9, 0xAB, 0xFD, 0x56, 0x46, 0x1C, 0x9B, 0xF6, 0x48, 0x7F, 0x5C, 0xFA, 0x09, 0x5C},
+};
+
+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},
+};
+
+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 *partial_se_state = (uint8_t *)0x4000FFC0;
+ uint8_t *enc_se_state = (uint8_t *)0x4003E000;
+
+ volatile tegra_pmc_t *pmc = pmc_get_regs();
+ uint32_t AL16 work_buffer[4];
+
+ /* Save a partial context, only the keyslots we want. */
+ /* We can't avoid touching memory, but save to a location that the bootrom will overwrite during init. */
+ se_set_in_context_save_mode(true);
+ se_save_partial_context(KEYSLOT_SWITCH_SRKGENKEY, KEYSLOT_SWITCH_RNGKEY, partial_se_state);
+ se_set_in_context_save_mode(false);
+
+ /* Clear the copy of the root key still inside the SE. */
+ clear_aes_keyslot(0xD);
+
+ /* Copy SRK into keyslot 0xE, clear it. */
+ {
+ work_buffer[0] = pmc->secure_scratch4;
+ pmc->secure_scratch4 = 0xCCCCCCCC;
+ work_buffer[1] = pmc->secure_scratch5;
+ pmc->secure_scratch5 = 0xCCCCCCCC;
+ work_buffer[2] = pmc->secure_scratch6;
+ pmc->secure_scratch6 = 0xCCCCCCCC;
+ work_buffer[3] = pmc->secure_scratch7;
+ pmc->secure_scratch7 = 0xCCCCCCCC;
+ set_aes_keyslot(0xE, work_buffer, 0x10);
+ for (size_t i = 0; i < 4; i++) {
+ work_buffer[i] = 0xCCCCCCCC;
+ }
+ }
+
+ /* Decrypt SE state. */
+ se_aes_128_cbc_decrypt(0xE, partial_se_state, 0x40, partial_se_state, 0x40);
+
+ /* Clear keyslots to wipe IVs. */
+ clear_aes_keyslot(0xE);
+ clear_aes_keyslot(0xF);
+
+ /* Mov root key into keyslot 0xE. Clear first to wipe from IV. */
+ set_aes_keyslot(0xE, partial_se_state + 0x30, 0x10);
+ for (size_t i = 0; i < 4; i++) {
+ *((volatile uint32_t *)(partial_se_state + 0x30)) = 0xCCCCCCCC;
+ }
+
+ /* Derive master kek. */
+ decrypt_data_into_keyslot(0xE, 0xE, master_kek_seeds[0], 0x10);
+
+ /* 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);
+
+ /* Derive Keyblob Key 00. */
+ set_aes_keyslot(0xF, partial_se_state + 0x20, 0x10);
+ se_aes_ecb_decrypt_block(0xF, work_buffer, 0x10, keyblob_seed_00, 0x10);
+ set_aes_keyslot(0xF, partial_se_state + 0x10, 0x10);
+ decrypt_data_into_keyslot(0xF, 0xF, work_buffer, 0x10);
+
+ /* Clear TSEC key + SBK. */
+ for (size_t i = 0; i < 8; i++) {
+ *((volatile uint32_t *)(partial_se_state + 0x10)) = 0xCCCCCCCC;
+ }
+
+ /* Derive device keys. */
+ decrypt_data_into_keyslot(0xA, 0xF, devicekey_4x_seed, 0x10);
+ decrypt_data_into_keyslot(0xF, 0xF, devicekey_seed, 0x10);
+
+ /* Derive firmware specific device key. */
+ se_aes_ecb_decrypt_block(0xA, work_buffer, 0x10, master_devkey_seeds[0], 0x10);
+ decrypt_data_into_keyslot(0xE, 0xE, work_buffer, 0x10);
+
+ /* 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);
+ }
+
+ *(volatile uint32_t *)(0x4003FFC0) = 0xCACACACA;
+
+ *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..e7db66ab0
--- /dev/null
+++ b/sept/sept-secondary/key_derivation/src/se.c
@@ -0,0 +1,763 @@
+/*
+ * 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();
+ }
+
+ se->CONFIG_REG = (ALG_AES_DEC | DST_KEYTAB);
+ se->CRYPTO_REG = keyslot_src << 24;
+ se->BLOCK_COUNT_REG = 0;
+ se->CRYPTO_KEYTABLE_DST_REG = keyslot_dst << 8;
+
+ trigger_se_blocking_op(OP_START, NULL, 0, wrapped_key, wrapped_key_size);
+}
+
+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;
+ 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);
+}
+
+void se_save_partial_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 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 + 0x00, 0x10, context_save_known_pattern, 0x10);
+
+ /* Save specific keyslots 0xC, 0xD, 0xE. */
+ se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_KEYTABLE_AES) | (0xE << CTX_SAVE_KEY_INDEX_SHIFT) | (CTX_SAVE_KEY_LOW_BITS);
+ se->BLOCK_COUNT_REG = 0;
+ se_encrypt_with_srk(dst + 0x10, 0x10, NULL, 0);
+ se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_KEYTABLE_AES) | (0xC << CTX_SAVE_KEY_INDEX_SHIFT) | (CTX_SAVE_KEY_LOW_BITS);
+ se->BLOCK_COUNT_REG = 0;
+ se_encrypt_with_srk(dst + 0x20, 0x10, NULL, 0);
+ se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_KEYTABLE_AES) | (0xD << CTX_SAVE_KEY_INDEX_SHIFT) | (CTX_SAVE_KEY_LOW_BITS);
+ se->BLOCK_COUNT_REG = 0;
+ se_encrypt_with_srk(dst + 0x30, 0x10, NULL, 0);
+
+ /* 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..d3b3c7ca1
--- /dev/null
+++ b/sept/sept-secondary/key_derivation/src/se.h
@@ -0,0 +1,227 @@
+/*
+ * 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);
+
+void se_save_partial_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..cc6cec4b7
--- /dev/null
+++ b/sept/sept-secondary/key_derivation/src/utils.c
@@ -0,0 +1,24 @@
+/*
+ * 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
+
+__attribute__ ((noreturn)) void generic_panic(void) {
+ 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/src/cluster.c b/sept/sept-secondary/src/cluster.c
new file mode 100644
index 000000000..cb29ec76b
--- /dev/null
+++ b/sept/sept-secondary/src/cluster.c
@@ -0,0 +1,163 @@
+/*
+ * 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 .
+ */
+
+#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;
+
+ /* 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;
+
+ /* 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..39f16cf28 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(void) {
+ /* 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) = 0x0;
-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
-};
+ while (*mailbox != 7) {
+ /* Wait until keys have been derived. */
+ }
+}
-void derive_7x_keys(const void *tsec_key, void *tsec_root_key) {
- uint8_t AL16 work_buffer[0x10];
+void load_keys(const uint8_t *se_state) {
+ /* Clear keyslot 0xA. */
+ for (size_t i = 0; i < 0xA; i++) {
+ clear_aes_keyslot(0xA);
+ }
+
+ /* 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 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;
- }
}
diff --git a/sept/sept-secondary/src/key_derivation.h b/sept/sept-secondary/src/key_derivation.h
index da77a1490..621d9dce5 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(void);
+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..50c4f7285 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"
@@ -39,9 +39,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;
}
@@ -55,23 +52,15 @@ static void exfiltrate_keys_and_reboot_if_needed(void) {
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();
+
reboot_to_self();
} else {
/* Decrypt the security engine state. */
@@ -82,13 +71,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 +87,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);
- }
}
}
@@ -126,7 +107,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 +117,7 @@ static void setup_env(void) {
/* Set up the exception handlers. */
setup_exception_handlers();
-
+
/* Mount the SD card. */
mount_sd();
}
@@ -159,28 +140,19 @@ int main(void) {
stage2_args_t *stage2_args;
uint32_t stage2_version = 0;
ScreenLogLevel log_level = SCREEN_LOG_LEVEL_NONE;
-
+
/* Extract keys from the security engine, which TSEC FW locked down. */
exfiltrate_keys_and_reboot_if_needed();
-
+
/* 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 +166,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/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);
}