mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2024-12-18 00:12:03 +00:00
fusee: Move nxboot hand-off to IRAM.
fusee/exosphere: Minor cleanup.
This commit is contained in:
parent
d61ec20679
commit
39d812f434
19 changed files with 370 additions and 290 deletions
|
@ -18,7 +18,6 @@
|
|||
|
||||
#include "utils.h"
|
||||
#include "memory_map.h"
|
||||
|
||||
#include "bootup.h"
|
||||
#include "cpu_context.h"
|
||||
#include "package2.h"
|
||||
|
@ -38,7 +37,6 @@
|
|||
extern void *__start_cold_addr;
|
||||
extern size_t __bin_size;
|
||||
|
||||
|
||||
static const uint8_t new_device_key_sources[MASTERKEY_NUM_NEW_DEVICE_KEYS][0x10] = {
|
||||
{0x8B, 0x4E, 0x1C, 0x22, 0x42, 0x07, 0xC8, 0x73, 0x56, 0x94, 0x08, 0x8B, 0xCC, 0x47, 0x0F, 0x5D}, /* 4.x New Device Key Source. */
|
||||
{0x6C, 0xEF, 0xC6, 0x27, 0x8B, 0xEC, 0x8A, 0x91, 0x99, 0xAB, 0x24, 0xAC, 0x4F, 0x1C, 0x8F, 0x1C}, /* 5.x New Device Key Source. */
|
||||
|
@ -85,15 +83,15 @@ static void setup_se(void) {
|
|||
intr_initialize_gic_nonsecure();
|
||||
|
||||
/* Perform some sanity initialization. */
|
||||
volatile security_engine_t *p_security_engine = get_security_engine();
|
||||
p_security_engine->_0x0 &= 0xFFFEFFFF; /* Clear bit 16. */
|
||||
(void)(SECURITY_ENGINE->FLAGS_REG);
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
se->_0x0 &= 0xFFFEFFFF; /* Clear bit 16. */
|
||||
(void)(se->FLAGS_REG);
|
||||
__dsb_sy();
|
||||
|
||||
p_security_engine->_0x4 = 0;
|
||||
p_security_engine->AES_KEY_READ_DISABLE_REG = 0;
|
||||
p_security_engine->RSA_KEY_READ_DISABLE_REG = 0;
|
||||
p_security_engine->_0x0 &= 0xFFFFFFFB;
|
||||
se->_0x4 = 0;
|
||||
se->AES_KEY_READ_DISABLE_REG = 0;
|
||||
se->RSA_KEY_READ_DISABLE_REG = 0;
|
||||
se->_0x0 &= 0xFFFFFFFB;
|
||||
|
||||
/* Currently unknown what each flag does. */
|
||||
for (unsigned int i = 0; i < KEYSLOT_AES_MAX; i++) {
|
||||
|
@ -139,8 +137,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) {
|
||||
|
@ -169,7 +166,6 @@ static void package2_crypt_ctr(unsigned int master_key_rev, void *dst, size_t ds
|
|||
se_aes_ctr_crypt(KEYSLOT_SWITCH_PACKAGE2KEY, dst, dst_size, src, src_size, ctr, ctr_size);
|
||||
}
|
||||
|
||||
|
||||
static void verify_header_signature(package2_header_t *header) {
|
||||
const uint8_t *modulus;
|
||||
|
||||
|
@ -506,7 +502,8 @@ void load_package2(coldboot_crt0_reloc_list_t *reloc_list) {
|
|||
randomcache_init();
|
||||
|
||||
/* 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);
|
||||
/* 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 = 1;
|
||||
|
||||
|
|
|
@ -36,9 +36,8 @@ static unsigned int g_se_exp_sizes[KEYSLOT_RSA_MAX];
|
|||
static bool g_se_generated_vector = false;
|
||||
static uint8_t g_se_stored_test_vector[0x10];
|
||||
|
||||
|
||||
/* Initialize a SE linked list. */
|
||||
void ll_init(se_ll_t *ll, void *buffer, size_t size) {
|
||||
void ll_init(volatile se_ll_t *ll, void *buffer, size_t size) {
|
||||
ll->num_entries = 0; /* 1 Entry. */
|
||||
|
||||
if (buffer != NULL) {
|
||||
|
@ -62,7 +61,7 @@ void set_security_engine_callback(unsigned int (*callback)(void)) {
|
|||
|
||||
/* Fires on Security Engine operation completion. */
|
||||
void se_operation_completed(void) {
|
||||
SECURITY_ENGINE->INT_ENABLE_REG = 0;
|
||||
se_get_regs()->INT_ENABLE_REG = 0;
|
||||
if (g_se_callback != NULL) {
|
||||
g_se_callback();
|
||||
g_se_callback = NULL;
|
||||
|
@ -70,13 +69,14 @@ void se_operation_completed(void) {
|
|||
}
|
||||
|
||||
void se_check_error_status_reg(void) {
|
||||
if (SECURITY_ENGINE->ERR_STATUS_REG) {
|
||||
if (se_get_regs()->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) {
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
if (se->INT_STATUS_REG & 0x10000 || se->FLAGS_REG & 3 || se->ERR_STATUS_REG) {
|
||||
generic_panic();
|
||||
}
|
||||
}
|
||||
|
@ -86,12 +86,11 @@ void se_trigger_interrupt(void) {
|
|||
}
|
||||
|
||||
void se_verify_flags_cleared(void) {
|
||||
if (SECURITY_ENGINE->FLAGS_REG & 3) {
|
||||
if (se_get_regs()->FLAGS_REG & 3) {
|
||||
generic_panic();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void se_generate_test_vector(void *vector) {
|
||||
/* TODO: Implement real test vector generation. */
|
||||
memset(vector, 0, 0x10);
|
||||
|
@ -122,23 +121,27 @@ void se_generate_stored_vector(void) {
|
|||
|
||||
/* 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) {
|
||||
SECURITY_ENGINE->AES_KEYSLOT_FLAGS[keyslot] = ~flags;
|
||||
se->AES_KEYSLOT_FLAGS[keyslot] = ~flags;
|
||||
}
|
||||
|
||||
/* Disable keyslot reads. */
|
||||
if (flags & 0x80) {
|
||||
SECURITY_ENGINE->AES_KEY_READ_DISABLE_REG &= ~(1 << keyslot);
|
||||
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();
|
||||
}
|
||||
|
@ -146,28 +149,32 @@ void set_rsa_keyslot_flags(unsigned int keyslot, unsigned int flags) {
|
|||
/* Misc flags. */
|
||||
if (flags & ~0x80) {
|
||||
/* TODO: Why are flags assigned this way? */
|
||||
SECURITY_ENGINE->RSA_KEYSLOT_FLAGS[keyslot] = (((flags >> 4) & 4) | (flags & 3)) ^ 7;
|
||||
se->RSA_KEYSLOT_FLAGS[keyslot] = (((flags >> 4) & 4) | (flags & 3)) ^ 7;
|
||||
}
|
||||
|
||||
/* Disable keyslot reads. */
|
||||
if (flags & 0x80) {
|
||||
SECURITY_ENGINE->RSA_KEY_READ_DISABLE_REG &= ~(1 << keyslot);
|
||||
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++) {
|
||||
SECURITY_ENGINE->AES_KEYTABLE_ADDR = (keyslot << 4) | i;
|
||||
SECURITY_ENGINE->AES_KEYTABLE_DATA = 0;
|
||||
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();
|
||||
}
|
||||
|
@ -175,40 +182,44 @@ void clear_rsa_keyslot(unsigned int keyslot) {
|
|||
/* Zero out the whole keyslot. */
|
||||
for (unsigned int i = 0; i < 0x40; i++) {
|
||||
/* Select Keyslot Modulus[i] */
|
||||
SECURITY_ENGINE->RSA_KEYTABLE_ADDR = (keyslot << 7) | i | 0x40;
|
||||
SECURITY_ENGINE->RSA_KEYTABLE_DATA = 0;
|
||||
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] */
|
||||
SECURITY_ENGINE->RSA_KEYTABLE_ADDR = (keyslot << 7) | i;
|
||||
SECURITY_ENGINE->RSA_KEYTABLE_DATA = 0;
|
||||
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++) {
|
||||
SECURITY_ENGINE->AES_KEYTABLE_ADDR = (keyslot << 4) | i;
|
||||
SECURITY_ENGINE->AES_KEYTABLE_DATA = read32le(key, 4 * 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++) {
|
||||
SECURITY_ENGINE->RSA_KEYTABLE_ADDR = (keyslot << 7) | 0x40 | i;
|
||||
SECURITY_ENGINE->RSA_KEYTABLE_DATA = read32be(modulus, (4 * (modulus_size >> 2)) - (4 * i) - 4);
|
||||
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++) {
|
||||
SECURITY_ENGINE->RSA_KEYTABLE_ADDR = (keyslot << 7) | i;
|
||||
SECURITY_ENGINE->RSA_KEYTABLE_DATA = read32be(exponent, (4 * (exp_size >> 2)) - (4 * i) - 4);
|
||||
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;
|
||||
|
@ -216,48 +227,56 @@ void set_rsa_keyslot(unsigned int keyslot, const void *modulus, size_t modulus_
|
|||
}
|
||||
|
||||
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++) {
|
||||
SECURITY_ENGINE->AES_KEYTABLE_ADDR = (keyslot << 4) | 8 | i;
|
||||
SECURITY_ENGINE->AES_KEYTABLE_DATA = read32le(iv, 4 * 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++) {
|
||||
SECURITY_ENGINE->AES_KEYTABLE_ADDR = (keyslot << 4) | 8 | i;
|
||||
SECURITY_ENGINE->AES_KEYTABLE_DATA = 0;
|
||||
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++) {
|
||||
SECURITY_ENGINE->CRYPTO_CTR_REG[i] = read32le(ctr, i * 4);
|
||||
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 >= KEYSIZE_AES_MAX || wrapped_key_size > KEYSIZE_AES_MAX) {
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
SECURITY_ENGINE->CONFIG_REG = (ALG_AES_DEC | DST_KEYTAB);
|
||||
SECURITY_ENGINE->CRYPTO_REG = keyslot_src << 24;
|
||||
SECURITY_ENGINE->BLOCK_COUNT_REG = 0;
|
||||
SECURITY_ENGINE->CRYPTO_KEYTABLE_DST_REG = keyslot_dst << 8;
|
||||
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;
|
||||
|
||||
flush_dcache_range(wrapped_key, (const uint8_t *)wrapped_key + wrapped_key_size);
|
||||
trigger_se_blocking_op(OP_START, NULL, 0, wrapped_key, wrapped_key_size);
|
||||
}
|
||||
|
||||
void se_aes_crypt_insecure_internal(unsigned int keyslot, uint32_t out_ll_paddr, uint32_t in_ll_paddr, size_t size, unsigned int crypt_config, bool encrypt, unsigned int (*callback)(void)) {
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
|
||||
if (keyslot >= KEYSLOT_AES_MAX) {
|
||||
generic_panic();
|
||||
}
|
||||
|
@ -268,34 +287,34 @@ void se_aes_crypt_insecure_internal(unsigned int keyslot, uint32_t out_ll_paddr,
|
|||
|
||||
/* Setup Config register. */
|
||||
if (encrypt) {
|
||||
SECURITY_ENGINE->CONFIG_REG = (ALG_AES_ENC | DST_MEMORY);
|
||||
se->CONFIG_REG = (ALG_AES_ENC | DST_MEMORY);
|
||||
} else {
|
||||
SECURITY_ENGINE->CONFIG_REG = (ALG_AES_DEC | DST_MEMORY);
|
||||
se->CONFIG_REG = (ALG_AES_DEC | DST_MEMORY);
|
||||
}
|
||||
|
||||
/* Setup Crypto register. */
|
||||
SECURITY_ENGINE->CRYPTO_REG = crypt_config | (keyslot << 24) | (encrypt << 8);
|
||||
se->CRYPTO_REG = crypt_config | (keyslot << 24) | (encrypt << 8);
|
||||
|
||||
/* Mark this encryption as insecure -- this makes the SE not a secure busmaster. */
|
||||
SECURITY_ENGINE->CRYPTO_REG |= 0x80000000;
|
||||
se->CRYPTO_REG |= 0x80000000;
|
||||
|
||||
/* Appropriate number of blocks. */
|
||||
SECURITY_ENGINE->BLOCK_COUNT_REG = (size >> 4) - 1;
|
||||
se->BLOCK_COUNT_REG = (size >> 4) - 1;
|
||||
|
||||
/* Set the callback, for after the async operation. */
|
||||
set_security_engine_callback(callback);
|
||||
|
||||
/* Enable SE Interrupt firing for async op. */
|
||||
SECURITY_ENGINE->INT_ENABLE_REG = 0x10;
|
||||
se->INT_ENABLE_REG = 0x10;
|
||||
|
||||
/* Setup Input/Output lists */
|
||||
SECURITY_ENGINE->IN_LL_ADDR_REG = in_ll_paddr;
|
||||
SECURITY_ENGINE->OUT_LL_ADDR_REG = out_ll_paddr;
|
||||
se->IN_LL_ADDR_REG = in_ll_paddr;
|
||||
se->OUT_LL_ADDR_REG = out_ll_paddr;
|
||||
|
||||
/* Set registers for operation. */
|
||||
SECURITY_ENGINE->ERR_STATUS_REG = SECURITY_ENGINE->ERR_STATUS_REG;
|
||||
SECURITY_ENGINE->INT_STATUS_REG = SECURITY_ENGINE->INT_STATUS_REG;
|
||||
SECURITY_ENGINE->OPERATION_REG = 1;
|
||||
se->ERR_STATUS_REG = se->ERR_STATUS_REG;
|
||||
se->INT_STATUS_REG = se->INT_STATUS_REG;
|
||||
se->OPERATION_REG = 1;
|
||||
|
||||
/* Ensure writes go through. */
|
||||
__dsb_ish();
|
||||
|
@ -303,7 +322,7 @@ void se_aes_crypt_insecure_internal(unsigned int keyslot, uint32_t out_ll_paddr,
|
|||
|
||||
void se_aes_ctr_crypt_insecure(unsigned int keyslot, uint32_t out_ll_paddr, uint32_t in_ll_paddr, size_t size, const void *ctr, unsigned int (*callback)(void)) {
|
||||
/* Unknown what this write does, but official code writes it for CTR mode. */
|
||||
SECURITY_ENGINE->_0x80C = 1;
|
||||
se_get_regs()->SPARE_0 = 1;
|
||||
set_se_ctr(ctr);
|
||||
se_aes_crypt_insecure_internal(keyslot, out_ll_paddr, in_ll_paddr, size, 0x81E, true, callback);
|
||||
}
|
||||
|
@ -318,8 +337,8 @@ void se_aes_cbc_decrypt_insecure(unsigned int keyslot, uint32_t out_ll_paddr, ui
|
|||
se_aes_crypt_insecure_internal(keyslot, out_ll_paddr, in_ll_paddr, size, 0x66, false, callback);
|
||||
}
|
||||
|
||||
|
||||
void se_exp_mod(unsigned int keyslot, void *buf, size_t size, unsigned int (*callback)(void)) {
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
uint8_t stack_buf[KEYSIZE_RSA_MAX];
|
||||
|
||||
if (keyslot >= KEYSLOT_RSA_MAX || size > KEYSIZE_RSA_MAX) {
|
||||
|
@ -331,24 +350,24 @@ void se_exp_mod(unsigned int keyslot, void *buf, size_t size, unsigned int (*cal
|
|||
stack_buf[i] = *((uint8_t *)buf + size - i - 1);
|
||||
}
|
||||
|
||||
|
||||
SECURITY_ENGINE->CONFIG_REG = (ALG_RSA | DST_RSAREG);
|
||||
SECURITY_ENGINE->RSA_CONFIG = keyslot << 24;
|
||||
SECURITY_ENGINE->RSA_KEY_SIZE_REG = (g_se_modulus_sizes[keyslot] >> 6) - 1;
|
||||
SECURITY_ENGINE->RSA_EXP_SIZE_REG = g_se_exp_sizes[keyslot] >> 2;
|
||||
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;
|
||||
|
||||
set_security_engine_callback(callback);
|
||||
|
||||
/* Enable SE Interrupt firing for async op. */
|
||||
SECURITY_ENGINE->INT_ENABLE_REG = 0x10;
|
||||
se->INT_ENABLE_REG = 0x10;
|
||||
|
||||
flush_dcache_range(stack_buf, stack_buf + KEYSIZE_RSA_MAX);
|
||||
trigger_se_rsa_op(stack_buf, size);
|
||||
|
||||
while (!(SECURITY_ENGINE->INT_STATUS_REG & 2)) { /* Wait a while */ }
|
||||
while (!(se->INT_STATUS_REG & 2)) { /* Wait a while */ }
|
||||
}
|
||||
|
||||
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 stack_buf[KEYSIZE_RSA_MAX];
|
||||
|
||||
if (keyslot >= KEYSLOT_RSA_MAX || src_size > KEYSIZE_RSA_MAX || dst_size > KEYSIZE_RSA_MAX) {
|
||||
|
@ -360,11 +379,10 @@ void se_synchronous_exp_mod(unsigned int keyslot, void *dst, size_t dst_size, co
|
|||
stack_buf[i] = *((uint8_t *)src + src_size - i - 1);
|
||||
}
|
||||
|
||||
SECURITY_ENGINE->CONFIG_REG = (ALG_RSA | DST_RSAREG);
|
||||
SECURITY_ENGINE->RSA_CONFIG = keyslot << 24;
|
||||
SECURITY_ENGINE->RSA_KEY_SIZE_REG = (g_se_modulus_sizes[keyslot] >> 6) - 1;
|
||||
SECURITY_ENGINE->RSA_EXP_SIZE_REG = g_se_exp_sizes[keyslot] >> 2;
|
||||
|
||||
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;
|
||||
|
||||
flush_dcache_range(stack_buf, stack_buf + KEYSIZE_RSA_MAX);
|
||||
trigger_se_blocking_op(OP_START, NULL, 0, stack_buf, src_size);
|
||||
|
@ -382,7 +400,7 @@ void se_get_exp_mod_output(void *buf, size_t size) {
|
|||
|
||||
/* Copy endian swapped output. */
|
||||
while (num_dwords) {
|
||||
*p_out = read32be(SECURITY_ENGINE->RSA_OUTPUT, offset);
|
||||
*p_out = read32be(se_get_regs()->RSA_OUTPUT, offset);
|
||||
offset += 4;
|
||||
p_out--;
|
||||
num_dwords--;
|
||||
|
@ -447,22 +465,25 @@ bool se_rsa2048_pss_verify(const void *signature, size_t signature_size, const v
|
|||
|
||||
|
||||
void trigger_se_rsa_op(void *buf, size_t size) {
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
se_ll_t in_ll;
|
||||
|
||||
ll_init(&in_ll, (void *)buf, size);
|
||||
|
||||
/* Set the input LL. */
|
||||
SECURITY_ENGINE->IN_LL_ADDR_REG = (uint32_t) get_physical_address(&in_ll);
|
||||
se->IN_LL_ADDR_REG = (uint32_t) get_physical_address(&in_ll);
|
||||
|
||||
/* Set registers for operation. */
|
||||
SECURITY_ENGINE->ERR_STATUS_REG = SECURITY_ENGINE->ERR_STATUS_REG;
|
||||
SECURITY_ENGINE->INT_STATUS_REG = SECURITY_ENGINE->INT_STATUS_REG;
|
||||
SECURITY_ENGINE->OPERATION_REG = 1;
|
||||
se->ERR_STATUS_REG = se->ERR_STATUS_REG;
|
||||
se->INT_STATUS_REG = se->INT_STATUS_REG;
|
||||
se->OPERATION_REG = 1;
|
||||
|
||||
/* Ensure writes go through. */
|
||||
__dsb_ish();
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
|
@ -472,20 +493,19 @@ void trigger_se_blocking_op(unsigned int op, void *dst, size_t dst_size, const v
|
|||
__dsb_sy();
|
||||
|
||||
/* Set the LLs. */
|
||||
SECURITY_ENGINE->IN_LL_ADDR_REG = (uint32_t) get_physical_address(&in_ll);
|
||||
SECURITY_ENGINE->OUT_LL_ADDR_REG = (uint32_t) get_physical_address(&out_ll);
|
||||
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. */
|
||||
SECURITY_ENGINE->ERR_STATUS_REG = SECURITY_ENGINE->ERR_STATUS_REG;
|
||||
SECURITY_ENGINE->INT_STATUS_REG = SECURITY_ENGINE->INT_STATUS_REG;
|
||||
SECURITY_ENGINE->OPERATION_REG = op;
|
||||
se->ERR_STATUS_REG = se->ERR_STATUS_REG;
|
||||
se->INT_STATUS_REG = se->INT_STATUS_REG;
|
||||
se->OPERATION_REG = op;
|
||||
|
||||
while (!(SECURITY_ENGINE->INT_STATUS_REG & 0x10)) { /* Wait a while */ }
|
||||
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};
|
||||
|
@ -501,7 +521,7 @@ void se_perform_aes_block_operation(void *dst, size_t dst_size, const void *src,
|
|||
flush_dcache_range(block, block + sizeof(block));
|
||||
|
||||
/* Trigger AES operation. */
|
||||
SECURITY_ENGINE->BLOCK_COUNT_REG = 0;
|
||||
se_get_regs()->BLOCK_COUNT_REG = 0;
|
||||
trigger_se_blocking_op(OP_START, block, sizeof(block), block, sizeof(block));
|
||||
|
||||
/* Copy output data into dst. */
|
||||
|
@ -512,6 +532,8 @@ void se_perform_aes_block_operation(void *dst, size_t dst_size, const void *src,
|
|||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
@ -526,15 +548,15 @@ void se_aes_ctr_crypt(unsigned int keyslot, void *dst, size_t dst_size, const vo
|
|||
unsigned int num_blocks = src_size >> 4;
|
||||
|
||||
/* Unknown what this write does, but official code writes it for CTR mode. */
|
||||
SECURITY_ENGINE->_0x80C = 1;
|
||||
SECURITY_ENGINE->CONFIG_REG = (ALG_AES_ENC | DST_MEMORY);
|
||||
SECURITY_ENGINE->CRYPTO_REG = (keyslot << 24) | 0x91E;
|
||||
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) {
|
||||
SECURITY_ENGINE->BLOCK_COUNT_REG = num_blocks - 1;
|
||||
se->BLOCK_COUNT_REG = num_blocks - 1;
|
||||
trigger_se_blocking_op(OP_START, dst, dst_size, src, aligned_size);
|
||||
}
|
||||
|
||||
|
@ -553,13 +575,15 @@ void se_aes_ctr_crypt(unsigned int keyslot, void *dst, size_t dst_size, const vo
|
|||
}
|
||||
|
||||
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. */
|
||||
SECURITY_ENGINE->CONFIG_REG = (ALG_AES_ENC | DST_MEMORY) | (config_high << 16);
|
||||
SECURITY_ENGINE->CRYPTO_REG = keyslot << 24 | 0x100;
|
||||
se->CONFIG_REG = (ALG_AES_ENC | DST_MEMORY) | (config_high << 16);
|
||||
se->CRYPTO_REG = keyslot << 24 | 0x100;
|
||||
flush_dcache_range((uint8_t *)src, (uint8_t *)src + 0x10);
|
||||
se_perform_aes_block_operation(dst, 0x10, src, 0x10);
|
||||
flush_dcache_range((uint8_t *)dst, (uint8_t *)dst + 0x10);
|
||||
|
@ -576,12 +600,14 @@ void se_aes_256_ecb_encrypt_block(unsigned int keyslot, void *dst, size_t dst_si
|
|||
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
SECURITY_ENGINE->CONFIG_REG = (ALG_AES_DEC | DST_MEMORY);
|
||||
SECURITY_ENGINE->CRYPTO_REG = keyslot << 24;
|
||||
se->CONFIG_REG = (ALG_AES_DEC | DST_MEMORY);
|
||||
se->CRYPTO_REG = keyslot << 24;
|
||||
flush_dcache_range((uint8_t *)src, (uint8_t *)src + 0x10);
|
||||
se_perform_aes_block_operation(dst, 0x10, src, 0x10);
|
||||
flush_dcache_range((uint8_t *)dst, (uint8_t *)dst + 0x10);
|
||||
|
@ -600,6 +626,8 @@ 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) {
|
||||
generic_panic();
|
||||
}
|
||||
|
@ -616,17 +644,16 @@ void se_compute_aes_cmac(unsigned int keyslot, void *cmac, size_t cmac_size, con
|
|||
shift_left_xor_rb(derived_key);
|
||||
}
|
||||
|
||||
SECURITY_ENGINE->CONFIG_REG = (ALG_AES_ENC | DST_HASHREG) | (config_high << 16);
|
||||
SECURITY_ENGINE->CRYPTO_REG = (keyslot << 24) | (0x145);
|
||||
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) {
|
||||
SECURITY_ENGINE->BLOCK_COUNT_REG = num_blocks - 2;
|
||||
se->BLOCK_COUNT_REG = num_blocks - 2;
|
||||
trigger_se_blocking_op(OP_START, NULL, 0, data, data_size);
|
||||
SECURITY_ENGINE->CRYPTO_REG |= 0x80;
|
||||
se->CRYPTO_REG |= 0x80;
|
||||
}
|
||||
|
||||
/* Create final block. */
|
||||
|
@ -643,13 +670,13 @@ void se_compute_aes_cmac(unsigned int keyslot, void *cmac, size_t cmac_size, con
|
|||
}
|
||||
|
||||
/* Perform last operation. */
|
||||
SECURITY_ENGINE->BLOCK_COUNT_REG = 0;
|
||||
se->BLOCK_COUNT_REG = 0;
|
||||
flush_dcache_range(last_block, last_block + sizeof(last_block));
|
||||
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(SECURITY_ENGINE->HASH_RESULT_REG, i << 2);
|
||||
((uint32_t *)cmac)[i] = read32le(se->HASH_RESULT_REG, i << 2);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -661,42 +688,48 @@ void se_compute_aes_256_cmac(unsigned int keyslot, void *cmac, size_t cmac_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) {
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
|
||||
if (keyslot >= KEYSLOT_AES_MAX || src_size < 0x10) {
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
SECURITY_ENGINE->CONFIG_REG = (ALG_AES_ENC | DST_MEMORY) | (0x202 << 16);
|
||||
SECURITY_ENGINE->CRYPTO_REG = (keyslot << 24) | 0x144;
|
||||
se->CONFIG_REG = (ALG_AES_ENC | DST_MEMORY) | (0x202 << 16);
|
||||
se->CRYPTO_REG = (keyslot << 24) | 0x144;
|
||||
set_aes_keyslot_iv(keyslot, iv, 0x10);
|
||||
SECURITY_ENGINE->BLOCK_COUNT_REG = (src_size >> 4) - 1;
|
||||
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) */
|
||||
SECURITY_ENGINE->CONFIG_REG = (ENCMODE_SHA256 | ALG_SHA | DST_HASHREG);
|
||||
SECURITY_ENGINE->SHA_CONFIG_REG = 1;
|
||||
SECURITY_ENGINE->SHA_MSG_LENGTH_REG = (uint32_t)(src_size << 3);
|
||||
SECURITY_ENGINE->_0x208 = 0;
|
||||
SECURITY_ENGINE->_0x20C = 0;
|
||||
SECURITY_ENGINE->_0x210 = 0;
|
||||
SECURITY_ENGINE->SHA_MSG_LEFT_REG = (uint32_t)(src_size << 3);
|
||||
SECURITY_ENGINE->_0x218 = 0;
|
||||
SECURITY_ENGINE->_0x21C = 0;
|
||||
SECURITY_ENGINE->_0x220 = 0;
|
||||
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(SECURITY_ENGINE->HASH_RESULT_REG, i << 2);
|
||||
((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();
|
||||
}
|
||||
|
@ -705,74 +738,80 @@ void se_initialize_rng(unsigned int keyslot) {
|
|||
/* This will be discarded, when done. */
|
||||
uint8_t output_buf[0x10];
|
||||
|
||||
SECURITY_ENGINE->RNG_SRC_CONFIG_REG = 3; /* Entropy enable + Entropy lock enable */
|
||||
SECURITY_ENGINE->RNG_RESEED_INTERVAL_REG = 70001;
|
||||
SECURITY_ENGINE->CONFIG_REG = (ALG_RNG | DST_MEMORY);
|
||||
SECURITY_ENGINE->CRYPTO_REG = (keyslot << 24) | 0x108;
|
||||
SECURITY_ENGINE->RNG_CONFIG_REG = 5;
|
||||
SECURITY_ENGINE->BLOCK_COUNT_REG = 0;
|
||||
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;
|
||||
SECURITY_ENGINE->CONFIG_REG = (ALG_RNG | DST_MEMORY);
|
||||
SECURITY_ENGINE->CRYPTO_REG = (keyslot << 24) | 0x108;
|
||||
SECURITY_ENGINE->RNG_CONFIG_REG = 4;
|
||||
se->CONFIG_REG = (ALG_RNG | DST_MEMORY);
|
||||
se->CRYPTO_REG = (keyslot << 24) | 0x108;
|
||||
se->RNG_CONFIG_REG = 4;
|
||||
|
||||
if (num_blocks >= 1) {
|
||||
SECURITY_ENGINE->BLOCK_COUNT_REG = 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* SE context save API. */
|
||||
void se_set_in_context_save_mode(bool is_context_save_mode) {
|
||||
uint32_t val = SECURITY_ENGINE->_0x0;
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
|
||||
uint32_t val = se->_0x0;
|
||||
if (is_context_save_mode) {
|
||||
val |= 0x10000;
|
||||
} else {
|
||||
val &= 0xFFFEFFFF;
|
||||
}
|
||||
SECURITY_ENGINE->_0x0 = val;
|
||||
se->_0x0 = val;
|
||||
/* Perform a useless read from flags reg. */
|
||||
(void)(SECURITY_ENGINE->FLAGS_REG);
|
||||
(void)(se->FLAGS_REG);
|
||||
}
|
||||
|
||||
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. */
|
||||
SECURITY_ENGINE->CONFIG_REG = (ALG_RNG | DST_KEYTAB);
|
||||
SECURITY_ENGINE->CRYPTO_REG = (rng_keyslot << 24) | 0x108;
|
||||
SECURITY_ENGINE->RNG_CONFIG_REG = 4;
|
||||
SECURITY_ENGINE->BLOCK_COUNT_REG = 0;
|
||||
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. */
|
||||
SECURITY_ENGINE->CRYPTO_KEYTABLE_DST_REG = (dst_keyslot << 8);
|
||||
se->CRYPTO_KEYTABLE_DST_REG = (dst_keyslot << 8);
|
||||
trigger_se_blocking_op(OP_START, NULL, 0, NULL, 0);
|
||||
/* Generate high part of key. */
|
||||
SECURITY_ENGINE->CRYPTO_KEYTABLE_DST_REG = (dst_keyslot << 8) | 1;
|
||||
se->CRYPTO_KEYTABLE_DST_REG = (dst_keyslot << 8) | 1;
|
||||
trigger_se_blocking_op(OP_START, NULL, 0, NULL, 0);
|
||||
}
|
||||
|
||||
void se_generate_srk(unsigned int srkgen_keyslot) {
|
||||
SECURITY_ENGINE->CONFIG_REG = (ALG_RNG | DST_SRK);
|
||||
SECURITY_ENGINE->CRYPTO_REG = (srkgen_keyslot << 24) | 0x108;
|
||||
SECURITY_ENGINE->RNG_CONFIG_REG = 6;
|
||||
SECURITY_ENGINE->BLOCK_COUNT_REG = 0;
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -796,6 +835,7 @@ void se_encrypt_with_srk(void *dst, size_t dst_size, const void *src, size_t src
|
|||
}
|
||||
|
||||
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);
|
||||
|
||||
|
@ -808,39 +848,39 @@ void se_save_context(unsigned int srkgen_keyslot, unsigned int rng_keyslot, void
|
|||
flush_dcache_range(work_buf, work_buf + 0x10);
|
||||
|
||||
/* Save random initial block. */
|
||||
SECURITY_ENGINE->CONFIG_REG = (ALG_AES_ENC | DST_MEMORY);
|
||||
SECURITY_ENGINE->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_MEM);
|
||||
SECURITY_ENGINE->BLOCK_COUNT_REG = 0;
|
||||
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++) {
|
||||
SECURITY_ENGINE->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_STICKY_BITS) | (i << CTX_SAVE_STICKY_BIT_INDEX_SHIFT);
|
||||
SECURITY_ENGINE->BLOCK_COUNT_REG = 0;
|
||||
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++) {
|
||||
SECURITY_ENGINE->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_KEYTABLE_AES) | (i << CTX_SAVE_KEY_INDEX_SHIFT) | (CTX_SAVE_KEY_LOW_BITS);
|
||||
SECURITY_ENGINE->BLOCK_COUNT_REG = 0;
|
||||
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);
|
||||
SECURITY_ENGINE->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_KEYTABLE_AES) | (i << CTX_SAVE_KEY_INDEX_SHIFT) | (CTX_SAVE_KEY_HIGH_BITS);
|
||||
SECURITY_ENGINE->BLOCK_COUNT_REG = 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++) {
|
||||
SECURITY_ENGINE->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_KEYTABLE_AES) | (i << CTX_SAVE_KEY_INDEX_SHIFT) | (CTX_SAVE_KEY_ORIGINAL_IV);
|
||||
SECURITY_ENGINE->BLOCK_COUNT_REG = 0;
|
||||
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++) {
|
||||
SECURITY_ENGINE->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_KEYTABLE_AES) | (i << CTX_SAVE_KEY_INDEX_SHIFT) | (CTX_SAVE_KEY_UPDATED_IV);
|
||||
SECURITY_ENGINE->BLOCK_COUNT_REG = 0;
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -849,8 +889,8 @@ void se_save_context(unsigned int srkgen_keyslot, unsigned int rng_keyslot, void
|
|||
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++) {
|
||||
SECURITY_ENGINE->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);
|
||||
SECURITY_ENGINE->BLOCK_COUNT_REG = 0;
|
||||
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;
|
||||
}
|
||||
|
@ -859,14 +899,14 @@ void se_save_context(unsigned int srkgen_keyslot, unsigned int rng_keyslot, void
|
|||
|
||||
/* 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};
|
||||
SECURITY_ENGINE->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_MEM);
|
||||
SECURITY_ENGINE->BLOCK_COUNT_REG = 0;
|
||||
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. */
|
||||
SECURITY_ENGINE->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_SRK);
|
||||
SECURITY_ENGINE->BLOCK_COUNT_REG = 0;
|
||||
se->CONTEXT_SAVE_CONFIG_REG = (CTX_SAVE_SRC_SRK);
|
||||
se->BLOCK_COUNT_REG = 0;
|
||||
se_encrypt_with_srk(work_buf, 0, NULL, 0);
|
||||
SECURITY_ENGINE->CONFIG_REG = 0;
|
||||
se->CONFIG_REG = 0;
|
||||
se_encrypt_with_srk(work_buf, 0, NULL, 0);
|
||||
}
|
||||
|
|
|
@ -97,7 +97,7 @@
|
|||
|
||||
#define RSA_2048_BYTES 0x100
|
||||
|
||||
typedef struct security_engine {
|
||||
typedef struct {
|
||||
uint32_t _0x0;
|
||||
uint32_t _0x4;
|
||||
uint32_t OPERATION_REG;
|
||||
|
@ -157,15 +157,13 @@ typedef struct security_engine {
|
|||
uint32_t FLAGS_REG;
|
||||
uint32_t ERR_STATUS_REG;
|
||||
uint32_t _0x808;
|
||||
uint32_t _0x80C;
|
||||
uint32_t SPARE_0;
|
||||
uint32_t _0x810;
|
||||
uint32_t _0x814;
|
||||
uint32_t _0x818;
|
||||
uint32_t _0x81C;
|
||||
uint8_t _0x820[0x17E0];
|
||||
} security_engine_t;
|
||||
|
||||
static_assert(sizeof(security_engine_t) == 0x2000, "Mis-defined Security Engine Registers!");
|
||||
} tegra_se_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t address;
|
||||
|
@ -177,15 +175,10 @@ typedef struct {
|
|||
se_addr_info_t addr_info; /* This should really be an array...but for our use case it works. */
|
||||
} se_ll_t;
|
||||
|
||||
|
||||
/* WIP, API subject to change. */
|
||||
|
||||
static inline volatile security_engine_t *get_security_engine(void) {
|
||||
return (volatile security_engine_t *)(MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_SE));
|
||||
static inline volatile tegra_se_t *se_get_regs(void) {
|
||||
return (volatile tegra_se_t *)(MMIO_GET_DEVICE_ADDRESS(MMIO_DEVID_SE));
|
||||
}
|
||||
|
||||
#define SECURITY_ENGINE (get_security_engine())
|
||||
|
||||
/* This function MUST be registered to fire on the appropriate interrupt. */
|
||||
void se_operation_completed(void);
|
||||
|
||||
|
@ -209,7 +202,6 @@ void set_rsa_keyslot(unsigned int keyslot, const void *modulus, size_t modulus_s
|
|||
void set_aes_keyslot_iv(unsigned int keyslot, const void *iv, size_t iv_size);
|
||||
void set_se_ctr(const void *ctr);
|
||||
|
||||
|
||||
/* Insecure AES API */
|
||||
void se_aes_ctr_crypt_insecure(unsigned int keyslot, uint32_t out_ll_paddr, uint32_t in_ll_paddr, size_t size, const void *ctr, unsigned int (*callback)(void));
|
||||
void se_aes_cbc_encrypt_insecure(unsigned int keyslot, uint32_t out_ll_paddr, uint32_t in_ll_paddr, size_t size, const void *iv, unsigned int (*callback)(void));
|
||||
|
|
|
@ -175,8 +175,7 @@ bool i2c_write(volatile tegra_i2c_t *regs, uint8_t device, void *src, size_t src
|
|||
i2c_load_config(regs);
|
||||
|
||||
/* Config |= SEND; */
|
||||
regs->I2C_I2C_CNFG_0 |= 0x200;
|
||||
|
||||
regs->I2C_I2C_CNFG_0 = ((regs->I2C_I2C_CNFG_0 & 0xFFFFFDFF) | 0x200);
|
||||
|
||||
while (regs->I2C_I2C_STATUS_0 & 0x100) {
|
||||
/* Wait until not busy. */
|
||||
|
@ -203,8 +202,7 @@ bool i2c_read(volatile tegra_i2c_t *regs, uint8_t device, void *dst, size_t dst_
|
|||
i2c_load_config(regs);
|
||||
|
||||
/* Config |= SEND; */
|
||||
regs->I2C_I2C_CNFG_0 |= 0x200;
|
||||
|
||||
regs->I2C_I2C_CNFG_0 = ((regs->I2C_I2C_CNFG_0 & 0xFFFFFDFF) | 0x200);
|
||||
|
||||
while (regs->I2C_I2C_STATUS_0 & 0x100) {
|
||||
/* Wait until not busy. */
|
||||
|
|
|
@ -21,8 +21,8 @@
|
|||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#define I2C234_BASE 0x7000C000
|
||||
#define I2C56_BASE 0x7000D000
|
||||
#define I2C1234_BASE 0x7000C000
|
||||
#define I2C56_BASE 0x7000D000
|
||||
|
||||
#define I2C_1 0
|
||||
#define I2C_2 1
|
||||
|
@ -82,10 +82,10 @@ typedef struct {
|
|||
uint32_t I2C_I2C_HS_INTERFACE_TIMING_1_0;
|
||||
} tegra_i2c_t;
|
||||
|
||||
#define I2C1_REGS ((volatile tegra_i2c_t *)(I2C234_BASE + 0x000))
|
||||
#define I2C2_REGS ((volatile tegra_i2c_t *)(I2C234_BASE + 0x400))
|
||||
#define I2C3_REGS ((volatile tegra_i2c_t *)(I2C234_BASE + 0x500))
|
||||
#define I2C4_REGS ((volatile tegra_i2c_t *)(I2C234_BASE + 0x700))
|
||||
#define I2C1_REGS ((volatile tegra_i2c_t *)(I2C1234_BASE + 0x000))
|
||||
#define I2C2_REGS ((volatile tegra_i2c_t *)(I2C1234_BASE + 0x400))
|
||||
#define I2C3_REGS ((volatile tegra_i2c_t *)(I2C1234_BASE + 0x500))
|
||||
#define I2C4_REGS ((volatile tegra_i2c_t *)(I2C1234_BASE + 0x700))
|
||||
#define I2C5_REGS ((volatile tegra_i2c_t *)(I2C56_BASE + 0x000))
|
||||
#define I2C6_REGS ((volatile tegra_i2c_t *)(I2C56_BASE + 0x100))
|
||||
|
||||
|
|
|
@ -39,8 +39,7 @@ void NOINLINE ll_init(volatile se_ll_t *ll, void *buffer, size_t size) {
|
|||
}
|
||||
|
||||
void se_check_error_status_reg(void) {
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
if (se->ERR_STATUS_REG) {
|
||||
if (se_get_regs()->ERR_STATUS_REG) {
|
||||
generic_panic();
|
||||
}
|
||||
}
|
||||
|
@ -53,8 +52,7 @@ void se_check_for_error(void) {
|
|||
}
|
||||
|
||||
void se_verify_flags_cleared(void) {
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
if (se->FLAGS_REG & 3) {
|
||||
if (se_get_regs()->FLAGS_REG & 3) {
|
||||
generic_panic();
|
||||
}
|
||||
}
|
||||
|
@ -193,9 +191,8 @@ void clear_aes_keyslot_iv(unsigned int keyslot) {
|
|||
}
|
||||
|
||||
void set_se_ctr(const void *ctr) {
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
for (unsigned int i = 0; i < 4; i++) {
|
||||
se->CRYPTO_CTR_REG[i] = read32le(ctr, i * 4);
|
||||
se_get_regs()->CRYPTO_CTR_REG[i] = read32le(ctr, i * 4);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -237,7 +234,6 @@ void se_synchronous_exp_mod(unsigned int keyslot, void *dst, size_t dst_size, co
|
|||
}
|
||||
|
||||
void se_get_exp_mod_output(void *buf, size_t size) {
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
size_t num_dwords = (size >> 2);
|
||||
|
||||
if (num_dwords < 1) {
|
||||
|
@ -249,7 +245,7 @@ void se_get_exp_mod_output(void *buf, size_t size) {
|
|||
|
||||
/* Copy endian swapped output. */
|
||||
while (num_dwords) {
|
||||
*p_out = read32be(se->RSA_OUTPUT, offset);
|
||||
*p_out = read32be(se_get_regs()->RSA_OUTPUT, offset);
|
||||
offset += 4;
|
||||
p_out--;
|
||||
num_dwords--;
|
||||
|
@ -330,10 +326,8 @@ void trigger_se_blocking_op(unsigned int op, void *dst, size_t dst_size, const v
|
|||
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) {
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
uint8_t block[0x10] = {0};
|
||||
|
||||
if (src_size > sizeof(block) || dst_size > sizeof(block)) {
|
||||
|
@ -346,7 +340,7 @@ void se_perform_aes_block_operation(void *dst, size_t dst_size, const void *src,
|
|||
}
|
||||
|
||||
/* Trigger AES operation. */
|
||||
se->BLOCK_COUNT_REG = 0;
|
||||
se_get_regs()->BLOCK_COUNT_REG = 0;
|
||||
trigger_se_blocking_op(OP_START, block, sizeof(block), block, sizeof(block));
|
||||
|
||||
/* Copy output data into dst. */
|
||||
|
@ -407,7 +401,6 @@ void se_aes_256_ecb_encrypt_block(unsigned int keyslot, void *dst, size_t dst_si
|
|||
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();
|
||||
|
||||
|
@ -535,7 +528,6 @@ void se_compute_aes_cmac(unsigned int keyslot, void *cmac, size_t cmac_size, con
|
|||
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) {
|
||||
|
|
|
@ -34,6 +34,9 @@
|
|||
#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
|
||||
|
||||
|
@ -88,7 +91,7 @@
|
|||
|
||||
#define RSA_2048_BYTES 0x100
|
||||
|
||||
typedef struct security_engine {
|
||||
typedef struct {
|
||||
uint32_t _0x0;
|
||||
uint32_t _0x4;
|
||||
uint32_t OPERATION_REG;
|
||||
|
@ -170,8 +173,6 @@ static inline volatile tegra_se_t *se_get_regs(void) {
|
|||
return (volatile tegra_se_t *)SE_BASE;
|
||||
}
|
||||
|
||||
/* This function MUST be registered to fire on the appropriate interrupt. */
|
||||
|
||||
void se_check_error_status_reg(void);
|
||||
void se_check_for_error(void);
|
||||
void se_trigger_interrupt(void);
|
||||
|
|
|
@ -6,6 +6,7 @@ PHDRS
|
|||
{
|
||||
crt0 PT_LOAD;
|
||||
chainloader PT_LOAD;
|
||||
nxboot PT_LOAD;
|
||||
main PT_LOAD;
|
||||
}
|
||||
|
||||
|
@ -13,16 +14,17 @@ PHDRS
|
|||
MEMORY
|
||||
{
|
||||
main : ORIGIN = 0xF0000000, LENGTH = 0x10000000
|
||||
high_iram : ORIGIN = 0x40010000, LENGTH = 0x20000
|
||||
low_iram : ORIGIN = 0x40003000, LENGTH = 0x8000
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
PROVIDE(__start__ = 0xF0000000);
|
||||
PROVIDE(__stack_top__ = 0x40010000);
|
||||
PROVIDE(__stack_bottom__ = 0x4000C000);
|
||||
PROVIDE(__heap_start__ = 0xE0000000);
|
||||
PROVIDE(__heap_end__ = 0xF0000000);
|
||||
PROVIDE(__stack_top__ = 0x90020000);
|
||||
PROVIDE(__stack_bottom__ = 0x90010000);
|
||||
PROVIDE(__heap_start__ = 0x90020000);
|
||||
PROVIDE(__heap_end__ = 0xA0020000);
|
||||
|
||||
. = __start__;
|
||||
|
||||
|
@ -53,6 +55,27 @@ SECTIONS
|
|||
. = ALIGN(32);
|
||||
PROVIDE (__chainloader_end__ = ABSOLUTE(.));
|
||||
} >low_iram :NONE
|
||||
|
||||
.nxboot_loadable :
|
||||
{
|
||||
. = ALIGN(32);
|
||||
PROVIDE (__nxboot_start__ = ABSOLUTE(.));
|
||||
PROVIDE (__nxboot_lma__ = LOADADDR(.nxboot_loadable));
|
||||
KEEP(*(.nxboot.text.start))
|
||||
nxboot_iram.o(.text*)
|
||||
nxboot_iram.o(.rodata*)
|
||||
nxboot_iram.o(.data*)
|
||||
. = ALIGN(32);
|
||||
} >high_iram AT>main :nxboot
|
||||
|
||||
.nxboot_bss (NOLOAD) :
|
||||
{
|
||||
. = ALIGN(32);
|
||||
PROVIDE (__nxboot_bss_start__ = ABSOLUTE(.));
|
||||
nxboot_iram.o(.bss* COMMON)
|
||||
. = ALIGN(32);
|
||||
PROVIDE (__nxboot_end__ = ABSOLUTE(.));
|
||||
} >high_iram :NONE
|
||||
|
||||
.text :
|
||||
{
|
||||
|
|
|
@ -175,8 +175,7 @@ bool i2c_write(volatile tegra_i2c_t *regs, uint8_t device, void *src, size_t src
|
|||
i2c_load_config(regs);
|
||||
|
||||
/* Config |= SEND; */
|
||||
regs->I2C_I2C_CNFG_0 |= 0x200;
|
||||
|
||||
regs->I2C_I2C_CNFG_0 = ((regs->I2C_I2C_CNFG_0 & 0xFFFFFDFF) | 0x200);
|
||||
|
||||
while (regs->I2C_I2C_STATUS_0 & 0x100) {
|
||||
/* Wait until not busy. */
|
||||
|
@ -203,8 +202,7 @@ bool i2c_read(volatile tegra_i2c_t *regs, uint8_t device, void *dst, size_t dst_
|
|||
i2c_load_config(regs);
|
||||
|
||||
/* Config |= SEND; */
|
||||
regs->I2C_I2C_CNFG_0 |= 0x200;
|
||||
|
||||
regs->I2C_I2C_CNFG_0 = ((regs->I2C_I2C_CNFG_0 & 0xFFFFFDFF) | 0x200);
|
||||
|
||||
while (regs->I2C_I2C_STATUS_0 & 0x100) {
|
||||
/* Wait until not busy. */
|
||||
|
|
|
@ -21,8 +21,8 @@
|
|||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#define I2C234_BASE 0x7000C000
|
||||
#define I2C56_BASE 0x7000D000
|
||||
#define I2C1234_BASE 0x7000C000
|
||||
#define I2C56_BASE 0x7000D000
|
||||
|
||||
#define I2C_1 0
|
||||
#define I2C_2 1
|
||||
|
@ -82,10 +82,10 @@ typedef struct {
|
|||
uint32_t I2C_I2C_HS_INTERFACE_TIMING_1_0;
|
||||
} tegra_i2c_t;
|
||||
|
||||
#define I2C1_REGS ((volatile tegra_i2c_t *)(I2C234_BASE + 0x000))
|
||||
#define I2C2_REGS ((volatile tegra_i2c_t *)(I2C234_BASE + 0x400))
|
||||
#define I2C3_REGS ((volatile tegra_i2c_t *)(I2C234_BASE + 0x500))
|
||||
#define I2C4_REGS ((volatile tegra_i2c_t *)(I2C234_BASE + 0x700))
|
||||
#define I2C1_REGS ((volatile tegra_i2c_t *)(I2C1234_BASE + 0x000))
|
||||
#define I2C2_REGS ((volatile tegra_i2c_t *)(I2C1234_BASE + 0x400))
|
||||
#define I2C3_REGS ((volatile tegra_i2c_t *)(I2C1234_BASE + 0x500))
|
||||
#define I2C4_REGS ((volatile tegra_i2c_t *)(I2C1234_BASE + 0x700))
|
||||
#define I2C5_REGS ((volatile tegra_i2c_t *)(I2C56_BASE + 0x000))
|
||||
#define I2C6_REGS ((volatile tegra_i2c_t *)(I2C56_BASE + 0x100))
|
||||
|
||||
|
|
|
@ -51,8 +51,11 @@ static void __program_init_newlib_hooks(void) {
|
|||
static void __program_move_additional_sections(void) {
|
||||
#if defined(FUSEE_STAGE1_SRC) || defined(FUSEE_STAGE2_SRC)
|
||||
extern uint8_t __chainloader_lma__[], __chainloader_start__[], __chainloader_bss_start__[], __chainloader_end__[];
|
||||
extern uint8_t __nxboot_lma__[], __nxboot_start__[], __nxboot_bss_start__[], __nxboot_end__[];
|
||||
memcpy(__chainloader_start__, __chainloader_lma__, __chainloader_bss_start__ - __chainloader_start__);
|
||||
memset(__chainloader_bss_start__, 0, __chainloader_end__ - __chainloader_bss_start__);
|
||||
memcpy(__nxboot_start__, __nxboot_lma__, __nxboot_bss_start__ - __nxboot_start__);
|
||||
memset(__nxboot_bss_start__, 0, __nxboot_end__ - __nxboot_bss_start__);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -102,7 +102,8 @@ int main(int argc, void **argv) {
|
|||
g_do_nxboot = loader_ctx->chainload_entrypoint == 0;
|
||||
if (g_do_nxboot) {
|
||||
printf("Now performing nxboot.\n");
|
||||
nxboot_main();
|
||||
uint32_t boot_memaddr = nxboot_main();
|
||||
nxboot_finish(boot_memaddr);
|
||||
} else {
|
||||
/* TODO: What else do we want to do in terms of argc/argv? */
|
||||
const char *path = get_loader_ctx()->file_paths_to_load[get_loader_ctx()->file_id_of_entrypoint];
|
||||
|
|
|
@ -185,9 +185,8 @@ static void nxboot_move_bootconfig() {
|
|||
|
||||
/* This is the main function responsible for booting Horizon. */
|
||||
static nx_keyblob_t __attribute__((aligned(16))) g_keyblobs[32];
|
||||
void nxboot_main(void) {
|
||||
uint32_t nxboot_main(void) {
|
||||
volatile tegra_pmc_t *pmc = pmc_get_regs();
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
loader_ctx_t *loader_ctx = get_loader_ctx();
|
||||
package2_header_t *package2;
|
||||
size_t package2_size;
|
||||
|
@ -397,43 +396,6 @@ void nxboot_main(void) {
|
|||
}
|
||||
free(package2);
|
||||
|
||||
/* Clear used keyslots. */
|
||||
clear_aes_keyslot(KEYSLOT_SWITCH_PACKAGE2KEY);
|
||||
clear_aes_keyslot(KEYSLOT_SWITCH_RNGKEY);
|
||||
|
||||
/* Lock keyslots. */
|
||||
set_aes_keyslot_flags(KEYSLOT_SWITCH_MASTERKEY, 0xFF);
|
||||
if (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware < EXOSPHERE_TARGET_FIRMWARE_400) {
|
||||
set_aes_keyslot_flags(KEYSLOT_SWITCH_DEVICEKEY, 0xFF);
|
||||
} else {
|
||||
set_aes_keyslot_flags(KEYSLOT_SWITCH_4XOLDDEVICEKEY, 0xFF);
|
||||
}
|
||||
|
||||
/* Finalize the GPU UCODE carveout. */
|
||||
mc_config_carveout_finalize();
|
||||
|
||||
/* Lock AES keyslots. */
|
||||
for (uint32_t i = 0; i < 16; i++)
|
||||
set_aes_keyslot_flags(i, 0x15);
|
||||
|
||||
/* Lock RSA keyslots. */
|
||||
for (uint32_t i = 0; i < 2; i++)
|
||||
set_rsa_keyslot_flags(i, 1);
|
||||
|
||||
/* Lock the Security Engine. */
|
||||
se->_0x4 = 0;
|
||||
se->AES_KEY_READ_DISABLE_REG = 0;
|
||||
se->RSA_KEY_READ_DISABLE_REG = 0;
|
||||
se->_0x0 &= 0xFFFFFFFB;
|
||||
|
||||
/* Boot up Exosphère. */
|
||||
MAILBOX_NX_BOOTLOADER_IS_SECMON_AWAKE = 0;
|
||||
if (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware < EXOSPHERE_TARGET_FIRMWARE_400) {
|
||||
MAILBOX_NX_BOOTLOADER_SETUP_STATE = NX_BOOTLOADER_STATE_LOADED_PACKAGE2;
|
||||
} else {
|
||||
MAILBOX_NX_BOOTLOADER_SETUP_STATE = NX_BOOTLOADER_STATE_DRAM_INITIALIZED_4X;
|
||||
}
|
||||
|
||||
printf("[NXBOOT]: Powering on the CCPLEX...\n");
|
||||
|
||||
/* Display splash screen. */
|
||||
|
@ -442,26 +404,6 @@ void nxboot_main(void) {
|
|||
/* Unmount everything. */
|
||||
nxfs_unmount_all();
|
||||
|
||||
/* Terminate the display. */
|
||||
display_end();
|
||||
|
||||
/* Boot CPU0. */
|
||||
cluster_boot_cpu0((uint32_t)exosphere_memaddr);
|
||||
|
||||
/* Wait for Exosphère to wake up. */
|
||||
while (MAILBOX_NX_BOOTLOADER_IS_SECMON_AWAKE == 0) {
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
/* Signal Exosphère. */
|
||||
if (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware < EXOSPHERE_TARGET_FIRMWARE_400) {
|
||||
MAILBOX_NX_BOOTLOADER_SETUP_STATE = NX_BOOTLOADER_STATE_FINISHED;
|
||||
} else {
|
||||
MAILBOX_NX_BOOTLOADER_SETUP_STATE = NX_BOOTLOADER_STATE_FINISHED_4X;
|
||||
}
|
||||
|
||||
/* Halt ourselves in waitevent state. */
|
||||
while (1) {
|
||||
FLOW_CTLR_HALT_COP_EVENTS_0 = 0x50000000;
|
||||
}
|
||||
/* Return the memory address for booting CPU0. */
|
||||
return (uint32_t)exosphere_memaddr;
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@ typedef struct {
|
|||
uint32_t boot_reason_state;
|
||||
} boot_reason_t;
|
||||
|
||||
void nxboot_main(void);
|
||||
uint32_t nxboot_main(void);
|
||||
void nxboot_finish(uint32_t boot_memaddr);
|
||||
|
||||
#endif
|
||||
|
|
90
fusee/fusee-secondary/src/nxboot_iram.c
Normal file
90
fusee/fusee-secondary/src/nxboot_iram.c
Normal file
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* Copyright (c) 2018 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "cluster.h"
|
||||
#include "di.h"
|
||||
#include "exocfg.h"
|
||||
#include "flow.h"
|
||||
#include "mc.h"
|
||||
#include "nxboot.h"
|
||||
#include "se.h"
|
||||
#include "timers.h"
|
||||
|
||||
void nxboot_finish(uint32_t boot_memaddr) {
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
|
||||
/* Clear used keyslots. */
|
||||
clear_aes_keyslot(KEYSLOT_SWITCH_PACKAGE2KEY);
|
||||
clear_aes_keyslot(KEYSLOT_SWITCH_RNGKEY);
|
||||
|
||||
/* Lock keyslots. */
|
||||
set_aes_keyslot_flags(KEYSLOT_SWITCH_MASTERKEY, 0xFF);
|
||||
if (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware < EXOSPHERE_TARGET_FIRMWARE_400) {
|
||||
set_aes_keyslot_flags(KEYSLOT_SWITCH_DEVICEKEY, 0xFF);
|
||||
} else {
|
||||
set_aes_keyslot_flags(KEYSLOT_SWITCH_4XOLDDEVICEKEY, 0xFF);
|
||||
}
|
||||
|
||||
/* Finalize the GPU UCODE carveout. */
|
||||
mc_config_carveout_finalize();
|
||||
|
||||
/* Lock AES keyslots. */
|
||||
for (uint32_t i = 0; i < 16; i++)
|
||||
set_aes_keyslot_flags(i, 0x15);
|
||||
|
||||
/* Lock RSA keyslots. */
|
||||
for (uint32_t i = 0; i < 2; i++)
|
||||
set_rsa_keyslot_flags(i, 1);
|
||||
|
||||
/* Lock the Security Engine. */
|
||||
se->_0x4 = 0;
|
||||
se->AES_KEY_READ_DISABLE_REG = 0;
|
||||
se->RSA_KEY_READ_DISABLE_REG = 0;
|
||||
se->_0x0 &= 0xFFFFFFFB;
|
||||
|
||||
/* Boot up Exosphère. */
|
||||
MAILBOX_NX_BOOTLOADER_IS_SECMON_AWAKE = 0;
|
||||
if (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware < EXOSPHERE_TARGET_FIRMWARE_400) {
|
||||
MAILBOX_NX_BOOTLOADER_SETUP_STATE = NX_BOOTLOADER_STATE_LOADED_PACKAGE2;
|
||||
} else {
|
||||
MAILBOX_NX_BOOTLOADER_SETUP_STATE = NX_BOOTLOADER_STATE_DRAM_INITIALIZED_4X;
|
||||
}
|
||||
|
||||
/* Terminate the display. */
|
||||
display_end();
|
||||
|
||||
/* Boot CPU0. */
|
||||
cluster_boot_cpu0(boot_memaddr);
|
||||
|
||||
/* Wait for Exosphère to wake up. */
|
||||
while (MAILBOX_NX_BOOTLOADER_IS_SECMON_AWAKE == 0) {
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
/* Signal Exosphère. */
|
||||
if (MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware < EXOSPHERE_TARGET_FIRMWARE_400) {
|
||||
MAILBOX_NX_BOOTLOADER_SETUP_STATE = NX_BOOTLOADER_STATE_FINISHED;
|
||||
} else {
|
||||
MAILBOX_NX_BOOTLOADER_SETUP_STATE = NX_BOOTLOADER_STATE_FINISHED_4X;
|
||||
}
|
||||
|
||||
/* Halt ourselves in waitevent state. */
|
||||
while (1) {
|
||||
FLOW_CTLR_HALT_COP_EVENTS_0 = 0x50000000;
|
||||
}
|
||||
}
|
|
@ -39,8 +39,7 @@ void NOINLINE ll_init(volatile se_ll_t *ll, void *buffer, size_t size) {
|
|||
}
|
||||
|
||||
void se_check_error_status_reg(void) {
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
if (se->ERR_STATUS_REG) {
|
||||
if (se_get_regs()->ERR_STATUS_REG) {
|
||||
generic_panic();
|
||||
}
|
||||
}
|
||||
|
@ -53,8 +52,7 @@ void se_check_for_error(void) {
|
|||
}
|
||||
|
||||
void se_verify_flags_cleared(void) {
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
if (se->FLAGS_REG & 3) {
|
||||
if (se_get_regs()->FLAGS_REG & 3) {
|
||||
generic_panic();
|
||||
}
|
||||
}
|
||||
|
@ -193,9 +191,8 @@ void clear_aes_keyslot_iv(unsigned int keyslot) {
|
|||
}
|
||||
|
||||
void set_se_ctr(const void *ctr) {
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
for (unsigned int i = 0; i < 4; i++) {
|
||||
se->CRYPTO_CTR_REG[i] = read32le(ctr, i * 4);
|
||||
se_get_regs()->CRYPTO_CTR_REG[i] = read32le(ctr, i * 4);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -237,7 +234,6 @@ void se_synchronous_exp_mod(unsigned int keyslot, void *dst, size_t dst_size, co
|
|||
}
|
||||
|
||||
void se_get_exp_mod_output(void *buf, size_t size) {
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
size_t num_dwords = (size >> 2);
|
||||
|
||||
if (num_dwords < 1) {
|
||||
|
@ -249,7 +245,7 @@ void se_get_exp_mod_output(void *buf, size_t size) {
|
|||
|
||||
/* Copy endian swapped output. */
|
||||
while (num_dwords) {
|
||||
*p_out = read32be(se->RSA_OUTPUT, offset);
|
||||
*p_out = read32be(se_get_regs()->RSA_OUTPUT, offset);
|
||||
offset += 4;
|
||||
p_out--;
|
||||
num_dwords--;
|
||||
|
@ -330,10 +326,8 @@ void trigger_se_blocking_op(unsigned int op, void *dst, size_t dst_size, const v
|
|||
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) {
|
||||
volatile tegra_se_t *se = se_get_regs();
|
||||
uint8_t block[0x10] = {0};
|
||||
|
||||
if (src_size > sizeof(block) || dst_size > sizeof(block)) {
|
||||
|
@ -346,7 +340,7 @@ void se_perform_aes_block_operation(void *dst, size_t dst_size, const void *src,
|
|||
}
|
||||
|
||||
/* Trigger AES operation. */
|
||||
se->BLOCK_COUNT_REG = 0;
|
||||
se_get_regs()->BLOCK_COUNT_REG = 0;
|
||||
trigger_se_blocking_op(OP_START, block, sizeof(block), block, sizeof(block));
|
||||
|
||||
/* Copy output data into dst. */
|
||||
|
@ -407,7 +401,6 @@ void se_aes_256_ecb_encrypt_block(unsigned int keyslot, void *dst, size_t dst_si
|
|||
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();
|
||||
|
||||
|
@ -535,7 +528,6 @@ void se_compute_aes_cmac(unsigned int keyslot, void *cmac, size_t cmac_size, con
|
|||
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) {
|
||||
|
|
|
@ -34,6 +34,9 @@
|
|||
#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
|
||||
|
||||
|
@ -88,7 +91,7 @@
|
|||
|
||||
#define RSA_2048_BYTES 0x100
|
||||
|
||||
typedef struct security_engine {
|
||||
typedef struct {
|
||||
uint32_t _0x0;
|
||||
uint32_t _0x4;
|
||||
uint32_t OPERATION_REG;
|
||||
|
@ -170,8 +173,6 @@ static inline volatile tegra_se_t *se_get_regs(void) {
|
|||
return (volatile tegra_se_t *)SE_BASE;
|
||||
}
|
||||
|
||||
/* This function MUST be registered to fire on the appropriate interrupt. */
|
||||
|
||||
void se_check_error_status_reg(void);
|
||||
void se_check_for_error(void);
|
||||
void se_trigger_interrupt(void);
|
||||
|
|
|
@ -31,5 +31,5 @@ void display_splash_screen_bmp(const char *custom_splash_path) {
|
|||
/* TODO: Display the splash screen. It should be a pointer to a BMP, at this point. */
|
||||
|
||||
/* Display the splash screen for three seconds. */
|
||||
/* udelay(3000000); */
|
||||
udelay(3000000);
|
||||
}
|
||||
|
|
|
@ -70,3 +70,12 @@ _start:
|
|||
relocate_and_chainload:
|
||||
ldr sp, =__stack_top__
|
||||
b relocate_and_chainload_main
|
||||
|
||||
.section .nxboot.text.start, "ax", %progbits
|
||||
.arm
|
||||
.align 5
|
||||
.global nxboot
|
||||
.type nxboot, %function
|
||||
nxboot:
|
||||
ldr sp, =__stack_top__
|
||||
b nxboot_finish
|
Loading…
Reference in a new issue