diff --git a/exosphere/src/interrupt.c b/exosphere/src/interrupt.c index ff5af5ebe..7f79b20f0 100644 --- a/exosphere/src/interrupt.c +++ b/exosphere/src/interrupt.c @@ -11,8 +11,7 @@ static struct { } g_registered_interrupts[MAX_REGISTERED_INTERRUPTS] = { {0, NULL}, {0, NULL}, {0, NULL}, {0, NULL} }; static unsigned int get_interrupt_id(void) { - return 0; - /* TODO */ + return GICC_IAR; } /* Initializes the GIC. TODO: This must be called during wakeup. */ diff --git a/exosphere/src/lp0.c b/exosphere/src/lp0.c index 83690ee22..f3e1d2198 100644 --- a/exosphere/src/lp0.c +++ b/exosphere/src/lp0.c @@ -22,8 +22,55 @@ extern const uint32_t bpmpfw_bin_size; /* Save security engine, and go to sleep. */ void save_se_and_power_down_cpu(void) { + uint32_t tzram_cmac[0x4] = {0}; + + uint8_t *tzram_encryption_src = (uint8_t *)(LP0_ENTRY_GET_RAM_SEGMENT_ADDRESS(LP0_ENTRY_RAM_SEGMENT_ID_ENCRYPTED_TZRAM)); + uint8_t *tzram_encryption_dst = (uint8_t *)(LP0_ENTRY_GET_RAM_SEGMENT_ADDRESS(LP0_ENTRY_RAM_SEGMENT_ID_CURRENT_TZRAM)); + uint8_t *tzram_store_address = (uint8_t *)(WARMBOOT_GET_RAM_SEGMENT_ADDRESS(WARMBOOT_RAM_SEGMENT_ID_TZRAM)); clear_priv_smc_in_progress(); - /* TODO. */ + + /* Flush cache. */ + flush_dcache_all(); + + /* Encrypt and save TZRAM into DRAM using a random aes-256 key. */ + se_generate_random_key(KEYSLOT_SWITCH_LP0TZRAMKEY, KEYSLOT_SWITCH_RNGKEY); + + flush_dcache_range(tzram_encryption_dst, tzram_encryption_dst + LP0_TZRAM_SAVE_SIZE); + flush_dcache_range(tzram_encryption_src, tzram_encryption_src + LP0_TZRAM_SAVE_SIZE); + + /* Use the all-zero cmac buffer as an IV. */ + se_aes_256_cbc_encrypt(KEYSLOT_SWITCH_LP0TZRAMKEY, tzram_encryption_dst, LP0_TZRAM_SAVE_SIZE, tzram_encryption_src, LP0_TZRAM_SAVE_SIZE, tzram_cmac); + flush_dcache_range(tzram_encryption_dst, tzram_encryption_dst + LP0_TZRAM_SAVE_SIZE); + + /* Copy encrypted TZRAM from IRAM to DRAM. */ + memcpy(tzram_store_address, tzram_encryption_dst, LP0_TZRAM_SAVE_SIZE); + flush_dcache_range(tzram_store_address, tzram_store_address + LP0_TZRAM_SAVE_SIZE); + + /* Compute CMAC. */ + se_compute_aes_256_cmac(KEYSLOT_SWITCH_LP0TZRAMKEY, tzram_cmac, sizeof(tzram_cmac), tzram_encryption_dst, LP0_TZRAM_SAVE_SIZE); + + /* Write CMAC, lock registers. */ + APBDEV_PMC_SECURE_SCRATCH112_0 = tzram_cmac[0]; + APBDEV_PMC_SECURE_SCRATCH113_0 = tzram_cmac[1]; + APBDEV_PMC_SECURE_SCRATCH114_0 = tzram_cmac[2]; + APBDEV_PMC_SECURE_SCRATCH115_0 = tzram_cmac[3]; + APBDEV_PMC_SEC_DISABLE8_0 = 0x550000; + + /* Save security engine state. */ + uint8_t *se_state_dst = (uint8_t *)(WARMBOOT_GET_RAM_SEGMENT_ADDRESS(WARMBOOT_RAM_SEGMENT_ID_SE_STATE)); + se_check_error_status_reg(); + se_set_in_context_save_mode(true); + se_save_context(KEYSLOT_SWITCH_SRKKEY, KEYSLOT_SWITCH_RNGKEY, se_state_dst); + flush_dcache_range(se_state_dst, se_state_dst + 0x840); + APBDEV_PMC_SCRATCH43_0 = (uint32_t)(WARMBOOT_GET_RAM_SEGMENT_PA(WARMBOOT_RAM_SEGMENT_ID_SE_STATE)); + se_set_in_context_save_mode(false); + se_check_error_status_reg(); + + if (!configitem_is_retail()) { + /* TODO: uart_log("OYASUMI"); */ + } + + finalize_powerdown(); } uint32_t cpu_suspend(uint64_t power_state, uint64_t entrypoint, uint64_t argument) { diff --git a/exosphere/src/lp0.h b/exosphere/src/lp0.h index dd5e06468..5b44c804e 100644 --- a/exosphere/src/lp0.h +++ b/exosphere/src/lp0.h @@ -5,6 +5,8 @@ /* Exosphere Deep Sleep Entry implementation. */ +#define LP0_TZRAM_SAVE_SIZE 0xE000 + uint32_t cpu_suspend(uint64_t power_state, uint64_t entrypoint, uint64_t argument); #endif \ No newline at end of file diff --git a/exosphere/src/memory_map.h b/exosphere/src/memory_map.h index 45d1c27e4..edf26c8c4 100644 --- a/exosphere/src/memory_map.h +++ b/exosphere/src/memory_map.h @@ -81,7 +81,7 @@ #define MMIO_DEVID_EXCEPTION_VECTORS 17 #define MMIO_DEVID_MAX 18 -#define LP0_ENTRY_RAM_SEGMENT_ID_DECRYPTED_TZRAM 0 +#define LP0_ENTRY_RAM_SEGMENT_ID_ENCRYPTED_TZRAM 0 #define LP0_ENTRY_RAM_SEGMENT_ID_LP0_ENTRY_CODE 1 #define LP0_ENTRY_RAM_SEGMENT_ID_CURRENT_TZRAM 2 #define LP0_ENTRY_RAM_SEGMENT_ID_MAX 3 diff --git a/exosphere/src/pmc.h b/exosphere/src/pmc.h index 946447647..6c1d78399 100644 --- a/exosphere/src/pmc.h +++ b/exosphere/src/pmc.h @@ -23,4 +23,12 @@ static inline uintptr_t get_pmc_base(void) { #define APBDEV_PMC_WAKE2_STATUS_0 (*((volatile uint32_t *)(PMC_BASE + 0x168))) #define APBDEV_PMC_CNTRL2_0 (*((volatile uint32_t *)(PMC_BASE + 0x440))) +#define APBDEV_PMC_SCRATCH43_0 (*((volatile uint32_t *)(PMC_BASE + 0x22C))) +#define APBDEV_PMC_SEC_DISABLE8_0 (*((volatile uint32_t *)(PMC_BASE + 0x5C0))) +#define APBDEV_PMC_SECURE_SCRATCH112_0 (*((volatile uint32_t *)(PMC_BASE + 0xB18))) +#define APBDEV_PMC_SECURE_SCRATCH113_0 (*((volatile uint32_t *)(PMC_BASE + 0xB1C))) +#define APBDEV_PMC_SECURE_SCRATCH114_0 (*((volatile uint32_t *)(PMC_BASE + 0xB20))) +#define APBDEV_PMC_SECURE_SCRATCH115_0 (*((volatile uint32_t *)(PMC_BASE + 0xB24))) + + #endif diff --git a/exosphere/src/se.c b/exosphere/src/se.c index c0587b384..e9dc879b0 100644 --- a/exosphere/src/se.c +++ b/exosphere/src/se.c @@ -49,6 +49,11 @@ void se_operation_completed(void) { } } +void se_check_error_status_reg(void) { + if (SECURITY_ENGINE->ERR_STATUS_REG) { + generic_panic(); + } +} void se_check_for_error(void) { if (SECURITY_ENGINE->INT_STATUS_REG & 0x10000 || SECURITY_ENGINE->FLAGS_REG & 3 || SECURITY_ENGINE->ERR_STATUS_REG) { @@ -528,6 +533,10 @@ void se_compute_aes_256_cmac(unsigned int keyslot, void *cmac, size_t cmac_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) { + /* TODO */ +} + /* SHA256 Implementation. */ void se_calculate_sha256(void *dst, const void *src, size_t src_size) { /* Setup config for SHA256, size = BITS(src_size) */ @@ -590,3 +599,17 @@ void se_generate_random(unsigned int keyslot, void *dst, size_t size) { } } + + +/* SE context save API. */ +void se_set_in_context_save_mode(bool is_context_save_mode) { + /* TODO */ +} + +void se_generate_random_key(unsigned int dst_keyslot, unsigned int rng_keyslot) { + /* TODO */ +} + +void se_save_context(unsigned int srk_keyslot, unsigned int rng_keyslot, void *dst) { + /* TODO */ +} diff --git a/exosphere/src/se.h b/exosphere/src/se.h index 5a2db189e..22def5126 100644 --- a/exosphere/src/se.h +++ b/exosphere/src/se.h @@ -1,6 +1,7 @@ #ifndef EXOSPHERE_SE_H #define EXOSPHERE_SE_H +#include #include #include @@ -8,6 +9,8 @@ /* Exosphere driver for the Tegra X1 security engine. */ +#define KEYSLOT_SWITCH_LP0TZRAMKEY 0x2 +#define KEYSLOT_SWITCH_SRKKEY 0x8 #define KEYSLOT_SWITCH_PACKAGE2KEY 0x8 #define KEYSLOT_SWITCH_TEMPKEY 0x9 #define KEYSLOT_SWITCH_SESSIONKEY 0xA @@ -146,6 +149,7 @@ static inline volatile security_engine_t *get_security_engine(void) { /* This function MUST be registered to fire on the appropriate interrupt. */ void se_operation_completed(void); +void se_check_error_status_reg(void); void se_check_for_error(void); void se_trigger_interrupt(void); void se_clear_interrupts(void); /* TODO */ @@ -176,6 +180,7 @@ void se_aes_128_ecb_encrypt_block(unsigned int keyslot, void *dst, size_t dst_si 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); /* Hash API */ void se_calculate_sha256(void *dst, const void *src, size_t src_size); @@ -189,6 +194,9 @@ void se_synchronous_exp_mod(unsigned int keyslot, void *dst, size_t dst_size, co void se_initialize_rng(unsigned int keyslot); void se_generate_random(unsigned int keyslot, void *dst, size_t size); -/* TODO: SE context save API. */ +/* SE context save API. */ +void se_set_in_context_save_mode(bool is_context_save_mode); +void se_generate_random_key(unsigned int dst_keyslot, unsigned int rng_keyslot); +void se_save_context(unsigned int srk_keyslot, unsigned int rng_keyslot, void *dst); #endif /* EXOSPHERE_SE_H */