exo2: suspend fixes (sleep/wake now works on hardware)

This commit is contained in:
Michael Scire 2020-06-08 03:53:40 -07:00 committed by SciresM
parent 2fb363dcf0
commit 95d38a1a94
10 changed files with 77 additions and 18 deletions

View file

@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef EXOSPHERE_WARMBOOT_BIN_PMC_H #ifndef EXOSPHERE_WARMBOOT_BIN_PMC_H
#define 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_SEC_DISABLE2_0 MAKE_PMC_REG(0x2C4)
#define APBDEV_PMC_WEAK_BIAS_0 MAKE_PMC_REG(0x2C8) #define APBDEV_PMC_WEAK_BIAS_0 MAKE_PMC_REG(0x2C8)
#define APBDEV_PMC_SECURE_SCRATCH21_0 MAKE_PMC_REG(0x334) #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_SCRATCH32_0 MAKE_PMC_REG(0x360)
#define APBDEV_PMC_SECURE_SCRATCH34_0 MAKE_PMC_REG(0x368) #define APBDEV_PMC_SECURE_SCRATCH34_0 MAKE_PMC_REG(0x368)
#define APBDEV_PMC_SECURE_SCRATCH35_0 MAKE_PMC_REG(0x36C) #define APBDEV_PMC_SECURE_SCRATCH35_0 MAKE_PMC_REG(0x36C)

View file

@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include <string.h> #include <string.h>
#include "utils.h" #include "utils.h"
@ -56,7 +56,7 @@ void se_verify_flags_cleared(void) {
void clear_aes_keyslot(unsigned int keyslot) { void clear_aes_keyslot(unsigned int keyslot) {
volatile tegra_se_t *se = se_get_regs(); volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_AES_MAX) { if (keyslot >= KEYSLOT_AES_MAX) {
reboot(); reboot();
} }
@ -70,7 +70,7 @@ void clear_aes_keyslot(unsigned int keyslot) {
void clear_rsa_keyslot(unsigned int keyslot) { void clear_rsa_keyslot(unsigned int keyslot) {
volatile tegra_se_t *se = se_get_regs(); volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_RSA_MAX) { if (keyslot >= KEYSLOT_RSA_MAX) {
reboot(); reboot();
} }
@ -90,7 +90,7 @@ void clear_rsa_keyslot(unsigned int keyslot) {
void clear_aes_keyslot_iv(unsigned int keyslot) { void clear_aes_keyslot_iv(unsigned int keyslot) {
volatile tegra_se_t *se = se_get_regs(); volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_AES_MAX) { if (keyslot >= KEYSLOT_AES_MAX) {
reboot(); 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) { 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(); 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) { 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(); volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_AES_MAX || dst_size != 0x10 || src_size != 0x10) { if (keyslot >= KEYSLOT_AES_MAX || dst_size != 0x10 || src_size != 0x10) {
reboot(); 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) { 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(); volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_AES_MAX || dst_size != 0x10 || src_size != 0x10) { if (keyslot >= KEYSLOT_AES_MAX || dst_size != 0x10 || src_size != 0x10) {
reboot(); 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) { 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(); volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_AES_MAX) { if (keyslot >= KEYSLOT_AES_MAX) {
reboot(); 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) { 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(); volatile tegra_se_t *se = se_get_regs();
if (keyslot >= KEYSLOT_AES_MAX || src_size < 0x10) { if (keyslot >= KEYSLOT_AES_MAX || src_size < 0x10) {
reboot(); reboot();
} }

View file

@ -13,14 +13,15 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef EXOSPHERE_WARMBOOT_BIN_SE_H #ifndef EXOSPHERE_WARMBOOT_BIN_SE_H
#define EXOSPHERE_WARMBOOT_BIN_SE_H #define EXOSPHERE_WARMBOOT_BIN_SE_H
#define SE_BASE 0x70012000 #define SE_BASE 0x70012000
#define MAKE_SE_REG(n) MAKE_REG32(SE_BASE + n) #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_SRKGENKEY 0x8
#define KEYSLOT_SWITCH_PACKAGE2KEY 0x8 #define KEYSLOT_SWITCH_PACKAGE2KEY 0x8
#define KEYSLOT_SWITCH_TEMPKEY 0x9 #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_rsa_keyslot(unsigned int keyslot);
void clear_aes_keyslot_iv(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_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); void se_aes_256_cbc_decrypt(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size);

View file

@ -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) { 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. */ /* First, AES-256-CBC decrypt the image into TZRAM. */
se_aes_256_cbc_decrypt(KEYSLOT_SWITCH_LP0TZRAMKEY, dst, size, src, size); 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) { bool secmon_should_clear_aes_keyslot(unsigned int keyslot) {
/* We'll just compare keyslot against a hardcoded list of keys. */ /* We'll just compare keyslot against a hardcoded list of keys. */
static const uint8_t saved_keyslots[6] = { static const uint8_t saved_keyslots[6] = {
KEYSLOT_SWITCH_LP0TZRAMKEY, KEYSLOT_SWITCH_LP0TZRAMKEK,
KEYSLOT_SWITCH_SESSIONKEY, KEYSLOT_SWITCH_SESSIONKEY,
KEYSLOT_SWITCH_RNGKEY, KEYSLOT_SWITCH_RNGKEY,
KEYSLOT_SWITCH_MASTERKEY, KEYSLOT_SWITCH_MASTERKEY,

View file

@ -695,7 +695,7 @@ namespace ams::secmon {
/* Setup sctlr_el2. */ /* Setup sctlr_el2. */
{ {
util::BitPack64 sctlr = { hw::SctlrEl2::Res1 }; // 0x30C5083 util::BitPack64 sctlr = { hw::SctlrEl2::Res1 };
sctlr.Set<hw::SctlrEl2::M>(0); /* Globally disable the MMU. */ sctlr.Set<hw::SctlrEl2::M>(0); /* Globally disable the MMU. */
sctlr.Set<hw::SctlrEl2::A>(0); /* Disable alignment fault checking. */ sctlr.Set<hw::SctlrEl2::A>(0); /* Disable alignment fault checking. */
@ -1087,6 +1087,9 @@ namespace ams::secmon {
/* Perform initial setup. */ /* Perform initial setup. */
Setup1ForWarmboot(); Setup1ForWarmboot();
/* Generate a random srk. */
se::GenerateSrk();
/* Setup the Soc security. */ /* Setup the Soc security. */
SetupSocSecurity(); SetupSocSecurity();

View file

@ -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))); 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. */ /* 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))); FLOW_REG_BITS_ENUM_SEL(HALT_COP_EVENTS_JTAG, IsJtagEnabled(), ENABLED, DISABLED)));
/* TODO */ /* TODO */
@ -236,7 +236,7 @@ namespace ams::secmon::smc {
/* Clear keyslot 3, and then derive the save key. */ /* Clear keyslot 3, and then derive the save key. */
se::ClearAesKeySlot(pkg1::AesKeySlot_TzramSaveKey); 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. */ /* Declare a temporary block to be used as both iv and mac. */
u32 temp_block[se::AesBlockSize / sizeof(u32)] = {}; 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. */ /* Disable activity monitor bpmp monitoring, so that we don't panic upon bpmp wake. */
actmon::StopMonitoringBpmp(); 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. */ /* Load the bpmp firmware. */
void * const sc7fw_load_address = MemoryRegionVirtualIramSc7Firmware.GetPointer<void>(); void * const sc7fw_load_address = MemoryRegionVirtualIramSc7Firmware.GetPointer<void>();
std::memcpy(sc7fw_load_address, sc7fw_bin, sc7fw_bin_size); std::memcpy(sc7fw_load_address, sc7fw_bin, sc7fw_bin_size);
@ -352,6 +355,12 @@ namespace ams::secmon::smc {
log::SendText("OYASUMI\n", 8); 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. */ /* Finalize our powerdown and wait for an interrupt. */
FinalizePowerOff(); FinalizePowerOff();
} }

View file

@ -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_UARTC (0x1A0)
#define CLK_RST_CONTROLLER_CLK_SOURCE_ACTMON (0x3E8) #define CLK_RST_CONTROLLER_CLK_SOURCE_ACTMON (0x3E8)
/* RST_DEV_*_SET */
#define CLK_RST_CONTROLLER_RST_DEV_L_SET (0x300)
/* RST_DEV_*_CLR */ /* RST_DEV_*_CLR */
#define CLK_RST_CONTROLLER_RST_DEV_L_CLR (0x304) #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_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); DEFINE_CLK_RST_REG_BIT_ENUM(RST_DEV_L_CLR_CLR_COP_RST, 1, DISABLE, ENABLE);

View file

@ -42,6 +42,8 @@
#define APBDEV_PMC_WAKE_DELAY (0x0E0) #define APBDEV_PMC_WAKE_DELAY (0x0E0)
#define APBDEV_PMC_PWR_DET_VAL (0x0E4) #define APBDEV_PMC_PWR_DET_VAL (0x0E4)
#define APBDEV_PMC_CRYPTO_OP (0x0F4) #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_MASK (0x160)
#define APBDEV_PMC_WAKE2_LVL (0x164) #define APBDEV_PMC_WAKE2_LVL (0x164)
#define APBDEV_PMC_WAKE2_STATUS (0x168) #define APBDEV_PMC_WAKE2_STATUS (0x168)

View file

@ -21,6 +21,7 @@ namespace ams::log {
constexpr inline uart::Port UartLogPort = uart::Port_ReservedDebug; constexpr inline uart::Port UartLogPort = uart::Port_ReservedDebug;
constinit bool g_initialized_uart = false; constinit bool g_initialized_uart = false;
constinit bool g_logging_enabled = false;
constexpr inline u32 UartPortFlags = [] { constexpr inline u32 UartPortFlags = [] {
if constexpr (UartLogPort == uart::Port_ReservedDebug) { if constexpr (UartLogPort == uart::Port_ReservedDebug) {
@ -75,14 +76,18 @@ namespace ams::log {
g_initialized_uart = false; g_initialized_uart = false;
} }
void SetDebugLogEnabled(bool en) {
g_logging_enabled = en;
}
void SendText(const void *text, size_t size) { void SendText(const void *text, size_t size) {
if (g_initialized_uart) { if (g_initialized_uart && g_logging_enabled) {
uart::SendText(UartLogPort, text, size); uart::SendText(UartLogPort, text, size);
} }
} }
void Flush() { void Flush() {
if (g_initialized_uart) { if (g_initialized_uart && g_logging_enabled) {
uart::WaitFlush(UartLogPort); uart::WaitFlush(UartLogPort);
} }
} }

View file

@ -44,7 +44,7 @@ namespace ams::se {
} }
/* Execute the operation. */ /* 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. */ /* Copy output from the operation, if any. */
if (dst_size > 0) { if (dst_size > 0) {