From 95d38a1a942ff0fc710b8e26272cacc7f6bdd018 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Mon, 8 Jun 2020 03:53:40 -0700 Subject: [PATCH] exo2: suspend fixes (sleep/wake now works on hardware) --- exosphere/lp0fw/src/pmc.h | 6 +++- exosphere/lp0fw/src/se.c | 30 ++++++++++++++----- exosphere/lp0fw/src/se.h | 7 +++-- exosphere/lp0fw/src/secmon.c | 16 +++++++++- exosphere2/program/source/secmon_setup.cpp | 5 +++- .../smc/secmon_smc_power_management.cpp | 13 ++++++-- .../include/exosphere/tegra/tegra_clkrst.hpp | 5 ++++ .../include/exosphere/tegra/tegra_pmc.hpp | 2 ++ libraries/libexosphere/source/log/log_api.cpp | 9 ++++-- .../libexosphere/source/se/se_suspend.cpp | 2 +- 10 files changed, 77 insertions(+), 18 deletions(-) diff --git a/exosphere/lp0fw/src/pmc.h b/exosphere/lp0fw/src/pmc.h index cba043f19..a872c6073 100644 --- a/exosphere/lp0fw/src/pmc.h +++ b/exosphere/lp0fw/src/pmc.h @@ -13,7 +13,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + #ifndef EXOSPHERE_WARMBOOT_BIN_PMC_H #define EXOSPHERE_WARMBOOT_BIN_PMC_H @@ -39,6 +39,10 @@ #define APBDEV_PMC_SEC_DISABLE2_0 MAKE_PMC_REG(0x2C4) #define APBDEV_PMC_WEAK_BIAS_0 MAKE_PMC_REG(0x2C8) #define APBDEV_PMC_SECURE_SCRATCH21_0 MAKE_PMC_REG(0x334) +#define APBDEV_PMC_SECURE_SCRATCH24_0 MAKE_PMC_REG(0x340) +#define APBDEV_PMC_SECURE_SCRATCH25_0 MAKE_PMC_REG(0x344) +#define APBDEV_PMC_SECURE_SCRATCH26_0 MAKE_PMC_REG(0x348) +#define APBDEV_PMC_SECURE_SCRATCH27_0 MAKE_PMC_REG(0x34C) #define APBDEV_PMC_SECURE_SCRATCH32_0 MAKE_PMC_REG(0x360) #define APBDEV_PMC_SECURE_SCRATCH34_0 MAKE_PMC_REG(0x368) #define APBDEV_PMC_SECURE_SCRATCH35_0 MAKE_PMC_REG(0x36C) diff --git a/exosphere/lp0fw/src/se.c b/exosphere/lp0fw/src/se.c index 3a0607f24..2deccbdbc 100644 --- a/exosphere/lp0fw/src/se.c +++ b/exosphere/lp0fw/src/se.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" @@ -56,7 +56,7 @@ void se_verify_flags_cleared(void) { void clear_aes_keyslot(unsigned int keyslot) { volatile tegra_se_t *se = se_get_regs(); - + if (keyslot >= KEYSLOT_AES_MAX) { reboot(); } @@ -70,7 +70,7 @@ void clear_aes_keyslot(unsigned int keyslot) { void clear_rsa_keyslot(unsigned int keyslot) { volatile tegra_se_t *se = se_get_regs(); - + if (keyslot >= KEYSLOT_RSA_MAX) { reboot(); } @@ -90,7 +90,7 @@ void clear_rsa_keyslot(unsigned int keyslot) { void clear_aes_keyslot_iv(unsigned int keyslot) { volatile tegra_se_t *se = se_get_regs(); - + if (keyslot >= KEYSLOT_AES_MAX) { reboot(); } @@ -101,6 +101,20 @@ void clear_aes_keyslot_iv(unsigned int keyslot) { } } +void decrypt_data_into_keyslot_256(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) { + reboot(); + } + + se->SE_CONFIG = (0x202 << 16) | (ALG_AES_DEC | DST_KEYTAB); + se->SE_CRYPTO_CONFIG = keyslot_src << 24; + se->SE_CRYPTO_LAST_BLOCK = 0; + se->SE_CRYPTO_KEYTABLE_DST = keyslot_dst << 8; + + trigger_se_blocking_op(OP_START, NULL, 0, wrapped_key, wrapped_key_size); +} 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(); @@ -148,7 +162,7 @@ void se_perform_aes_block_operation(void *dst, size_t dst_size, const void *src, 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) { reboot(); } @@ -161,7 +175,7 @@ void se_aes_ecb_encrypt_block(unsigned int keyslot, void *dst, size_t dst_size, 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) { reboot(); } @@ -185,7 +199,7 @@ void shift_left_xor_rb(uint8_t *key) { 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) { reboot(); } @@ -239,7 +253,7 @@ void se_compute_aes_256_cmac(unsigned int keyslot, void *cmac, size_t cmac_size, void se_aes_256_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) { reboot(); } diff --git a/exosphere/lp0fw/src/se.h b/exosphere/lp0fw/src/se.h index 8612b169c..5e0083e36 100644 --- a/exosphere/lp0fw/src/se.h +++ b/exosphere/lp0fw/src/se.h @@ -13,14 +13,15 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + #ifndef EXOSPHERE_WARMBOOT_BIN_SE_H #define EXOSPHERE_WARMBOOT_BIN_SE_H #define SE_BASE 0x70012000 #define MAKE_SE_REG(n) MAKE_REG32(SE_BASE + n) -#define KEYSLOT_SWITCH_LP0TZRAMKEY 0x2 +#define KEYSLOT_SWITCH_LP0TZRAMKEK 0x2 +#define KEYSLOT_SWITCH_LP0TZRAMKEY 0x3 #define KEYSLOT_SWITCH_SRKGENKEY 0x8 #define KEYSLOT_SWITCH_PACKAGE2KEY 0x8 #define KEYSLOT_SWITCH_TEMPKEY 0x9 @@ -170,6 +171,8 @@ void clear_aes_keyslot(unsigned int keyslot); void clear_rsa_keyslot(unsigned int keyslot); void clear_aes_keyslot_iv(unsigned int keyslot); +void decrypt_data_into_keyslot_256(unsigned int keyslot_dst, unsigned int keyslot_src, const void *wrapped_key, size_t wrapped_key_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_256_cbc_decrypt(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size); diff --git a/exosphere/lp0fw/src/secmon.c b/exosphere/lp0fw/src/secmon.c index f39c89fa9..01a6ff539 100644 --- a/exosphere/lp0fw/src/secmon.c +++ b/exosphere/lp0fw/src/secmon.c @@ -57,6 +57,20 @@ void secmon_restore_to_tzram(const uint32_t target_firmware) { } void secmon_decrypt_saved_image(void *dst, const void *src, size_t size) { + /* Derive the key used for context save. */ + { + const uint32_t key_source[4] = { APBDEV_PMC_SECURE_SCRATCH24_0, APBDEV_PMC_SECURE_SCRATCH25_0, APBDEV_PMC_SECURE_SCRATCH26_0, APBDEV_PMC_SECURE_SCRATCH27_0 }; + + clear_aes_keyslot(KEYSLOT_SWITCH_LP0TZRAMKEY); + decrypt_data_into_keyslot_256(KEYSLOT_SWITCH_LP0TZRAMKEY, KEYSLOT_SWITCH_LP0TZRAMKEK, key_source, sizeof(key_source)); + + clear_aes_keyslot(KEYSLOT_SWITCH_LP0TZRAMKEK); + APBDEV_PMC_SECURE_SCRATCH24_0 = 0; + APBDEV_PMC_SECURE_SCRATCH25_0 = 0; + APBDEV_PMC_SECURE_SCRATCH26_0 = 0; + APBDEV_PMC_SECURE_SCRATCH27_0 = 0; + } + /* First, AES-256-CBC decrypt the image into TZRAM. */ se_aes_256_cbc_decrypt(KEYSLOT_SWITCH_LP0TZRAMKEY, dst, size, src, size); @@ -85,7 +99,7 @@ void secmon_decrypt_saved_image(void *dst, const void *src, size_t size) { bool secmon_should_clear_aes_keyslot(unsigned int keyslot) { /* We'll just compare keyslot against a hardcoded list of keys. */ static const uint8_t saved_keyslots[6] = { - KEYSLOT_SWITCH_LP0TZRAMKEY, + KEYSLOT_SWITCH_LP0TZRAMKEK, KEYSLOT_SWITCH_SESSIONKEY, KEYSLOT_SWITCH_RNGKEY, KEYSLOT_SWITCH_MASTERKEY, diff --git a/exosphere2/program/source/secmon_setup.cpp b/exosphere2/program/source/secmon_setup.cpp index f81642763..254b8e51f 100644 --- a/exosphere2/program/source/secmon_setup.cpp +++ b/exosphere2/program/source/secmon_setup.cpp @@ -695,7 +695,7 @@ namespace ams::secmon { /* Setup sctlr_el2. */ { - util::BitPack64 sctlr = { hw::SctlrEl2::Res1 }; // 0x30C5083 + util::BitPack64 sctlr = { hw::SctlrEl2::Res1 }; sctlr.Set(0); /* Globally disable the MMU. */ sctlr.Set(0); /* Disable alignment fault checking. */ @@ -1087,6 +1087,9 @@ namespace ams::secmon { /* Perform initial setup. */ Setup1ForWarmboot(); + /* Generate a random srk. */ + se::GenerateSrk(); + /* Setup the Soc security. */ SetupSocSecurity(); diff --git a/exosphere2/program/source/smc/secmon_smc_power_management.cpp b/exosphere2/program/source/smc/secmon_smc_power_management.cpp index bc6c8f580..93f053887 100644 --- a/exosphere2/program/source/smc/secmon_smc_power_management.cpp +++ b/exosphere2/program/source/smc/secmon_smc_power_management.cpp @@ -157,7 +157,7 @@ namespace ams::secmon::smc { AMS_ABORT_UNLESS(reg::HasValue(PMC + APBDEV_PMC_PWRGATE_STATUS, PMC_REG_BITS_VALUE(PWRGATE_STATUS_CE123, 0))); /* Validate that the bpmp is appropriately halted. */ - AMS_ABORT_UNLESS(reg::Read(FLOW_CTLR + FLOW_CTLR_HALT_COP_EVENTS) != reg::Encode(FLOW_REG_BITS_ENUM (HALT_COP_EVENTS_MODE, FLOW_MODE_STOP), + AMS_ABORT_UNLESS(reg::Read(FLOW_CTLR + FLOW_CTLR_HALT_COP_EVENTS) == reg::Encode(FLOW_REG_BITS_ENUM (HALT_COP_EVENTS_MODE, FLOW_MODE_STOP), FLOW_REG_BITS_ENUM_SEL(HALT_COP_EVENTS_JTAG, IsJtagEnabled(), ENABLED, DISABLED))); /* TODO */ @@ -236,7 +236,7 @@ namespace ams::secmon::smc { /* Clear keyslot 3, and then derive the save key. */ se::ClearAesKeySlot(pkg1::AesKeySlot_TzramSaveKey); - se::SetEncryptedAesKey256(pkg1::AesKeySlot_TzramSaveKey, pkg1::AesKeySlot_TzramSaveKek, key_source, sizeof(key_source)); + se::SetEncryptedAesKey256(pkg1::AesKeySlot_TzramSaveKey, pkg1::AesKeySlot_TzramSaveKek, key_source, se::AesBlockSize); /* Declare a temporary block to be used as both iv and mac. */ u32 temp_block[se::AesBlockSize / sizeof(u32)] = {}; @@ -319,6 +319,9 @@ namespace ams::secmon::smc { /* Disable activity monitor bpmp monitoring, so that we don't panic upon bpmp wake. */ actmon::StopMonitoringBpmp(); + /* Set BPMP reset. */ + reg::Write(CLK_RST + CLK_RST_CONTROLLER_RST_DEV_L_SET, CLK_RST_REG_BITS_ENUM(RST_DEV_L_SET_SET_COP_RST, ENABLE)); + /* Load the bpmp firmware. */ void * const sc7fw_load_address = MemoryRegionVirtualIramSc7Firmware.GetPointer(); std::memcpy(sc7fw_load_address, sc7fw_bin, sc7fw_bin_size); @@ -352,6 +355,12 @@ namespace ams::secmon::smc { log::SendText("OYASUMI\n", 8); } + /* If we're on erista, configure the bootrom to allow our custom warmboot firmware. */ + if (GetSocType() == fuse::SocType_Erista) { + reg::Write(PMC + APBDEV_PMC_SCRATCH31, 0x2202E012); + reg::Write(PMC + APBDEV_PMC_SCRATCH32, 0x6001DC28); + } + /* Finalize our powerdown and wait for an interrupt. */ FinalizePowerOff(); } diff --git a/libraries/libexosphere/include/exosphere/tegra/tegra_clkrst.hpp b/libraries/libexosphere/include/exosphere/tegra/tegra_clkrst.hpp index f6a1ae6b8..fc2253c27 100644 --- a/libraries/libexosphere/include/exosphere/tegra/tegra_clkrst.hpp +++ b/libraries/libexosphere/include/exosphere/tegra/tegra_clkrst.hpp @@ -63,6 +63,9 @@ DEFINE_CLK_RST_REG(MISC_CLK_ENB_CFG_ALL_VISIBLE, 28, 1); #define CLK_RST_CONTROLLER_CLK_SOURCE_UARTC (0x1A0) #define CLK_RST_CONTROLLER_CLK_SOURCE_ACTMON (0x3E8) +/* RST_DEV_*_SET */ +#define CLK_RST_CONTROLLER_RST_DEV_L_SET (0x300) + /* RST_DEV_*_CLR */ #define CLK_RST_CONTROLLER_RST_DEV_L_CLR (0x304) @@ -100,4 +103,6 @@ DEFINE_CLK_RST_REG_THREE_BIT_ENUM(CLK_SOURCE_UARTC_UARTC_CLK_SRC, 29, PLLP_OUT0, DEFINE_CLK_RST_REG_THREE_BIT_ENUM(CLK_SOURCE_ACTMON_ACTMON_CLK_SRC, 29, PLLP_OUT0, PLLC2_OUT0, PLLC_OUT0, PLLC4_OUT0, CLK_S, PLLC4_OUT1, CLK_M, PLLC4_OUT2); +DEFINE_CLK_RST_REG_BIT_ENUM(RST_DEV_L_SET_SET_COP_RST, 1, DISABLE, ENABLE); + DEFINE_CLK_RST_REG_BIT_ENUM(RST_DEV_L_CLR_CLR_COP_RST, 1, DISABLE, ENABLE); diff --git a/libraries/libexosphere/include/exosphere/tegra/tegra_pmc.hpp b/libraries/libexosphere/include/exosphere/tegra/tegra_pmc.hpp index 98d3743d8..f64f500f5 100644 --- a/libraries/libexosphere/include/exosphere/tegra/tegra_pmc.hpp +++ b/libraries/libexosphere/include/exosphere/tegra/tegra_pmc.hpp @@ -42,6 +42,8 @@ #define APBDEV_PMC_WAKE_DELAY (0x0E0) #define APBDEV_PMC_PWR_DET_VAL (0x0E4) #define APBDEV_PMC_CRYPTO_OP (0x0F4) +#define APBDEV_PMC_SCRATCH31 (0x118) +#define APBDEV_PMC_SCRATCH32 (0x11C) #define APBDEV_PMC_WAKE2_MASK (0x160) #define APBDEV_PMC_WAKE2_LVL (0x164) #define APBDEV_PMC_WAKE2_STATUS (0x168) diff --git a/libraries/libexosphere/source/log/log_api.cpp b/libraries/libexosphere/source/log/log_api.cpp index 2ea3c5c70..ad1d89ea2 100644 --- a/libraries/libexosphere/source/log/log_api.cpp +++ b/libraries/libexosphere/source/log/log_api.cpp @@ -21,6 +21,7 @@ namespace ams::log { constexpr inline uart::Port UartLogPort = uart::Port_ReservedDebug; constinit bool g_initialized_uart = false; + constinit bool g_logging_enabled = false; constexpr inline u32 UartPortFlags = [] { if constexpr (UartLogPort == uart::Port_ReservedDebug) { @@ -75,14 +76,18 @@ namespace ams::log { g_initialized_uart = false; } + void SetDebugLogEnabled(bool en) { + g_logging_enabled = en; + } + void SendText(const void *text, size_t size) { - if (g_initialized_uart) { + if (g_initialized_uart && g_logging_enabled) { uart::SendText(UartLogPort, text, size); } } void Flush() { - if (g_initialized_uart) { + if (g_initialized_uart && g_logging_enabled) { uart::WaitFlush(UartLogPort); } } diff --git a/libraries/libexosphere/source/se/se_suspend.cpp b/libraries/libexosphere/source/se/se_suspend.cpp index 98d49c958..883ae3cbc 100644 --- a/libraries/libexosphere/source/se/se_suspend.cpp +++ b/libraries/libexosphere/source/se/se_suspend.cpp @@ -44,7 +44,7 @@ namespace ams::se { } /* Execute the operation. */ - ExecuteOperation(SE, SE_OPERATION_OP_CTX_SAVE, dst, dst_size, src, src_size); + ExecuteOperation(SE, SE_OPERATION_OP_CTX_SAVE, temp, dst_size, src, src_size); /* Copy output from the operation, if any. */ if (dst_size > 0) {