From 83fd2c43a366356a4394c3e1dcf3d5d32ca1515c Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Mon, 19 Feb 2018 01:27:50 -0800 Subject: [PATCH] Flesh out more of the SE driver --- exosphere/se.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++- exosphere/se.h | 22 ++++++++++- exosphere/utils.h | 2 + 3 files changed, 117 insertions(+), 3 deletions(-) diff --git a/exosphere/se.c b/exosphere/se.c index d80bf9158..6129a7b55 100644 --- a/exosphere/se.c +++ b/exosphere/se.c @@ -1,9 +1,12 @@ +#include +#include + #include "utils.h" #include "cache.h" #include "se.h" void trigger_se_rsa_op(void *buf, size_t size); -void trigger_se_aes_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); /* Globals for driver. */ volatile security_engine_t *g_security_engine; @@ -13,6 +16,21 @@ unsigned int (*g_se_callback)(void); unsigned int g_se_modulus_sizes[KEYSLOT_RSA_MAX]; unsigned int g_se_exp_sizes[KEYSLOT_RSA_MAX]; +/* Initialize a SE linked list. */ +void ll_init(se_ll_t *ll, void *buffer, size_t size) { + ll->num_entries = 0; /* 1 Entry. */ + + if (buffer != NULL) { + ll->addr_info.address = get_physical_address(buffer); + ll->addr_info.size = (uint32_t) size; + } else { + ll->addr_info.address = 0; + ll->addr_info.size = 0; + } + + flush_dcache_range((uint8_t *)ll, (uint8_t *)ll + sizeof(*ll)); +} + /* Set the global security engine pointer. */ void set_security_engine_address(security_engine_t *security_engine) { g_security_engine = security_engine; @@ -31,6 +49,18 @@ void set_security_engine_callback(unsigned int (*callback)(void)) { g_se_callback = callback; } +/* Fires on Security Engine operation completion. */ +void se_operation_completed(void) { + if (g_security_engine == NULL) { + panic(); + } + g_security_engine->INT_ENABLE_REG = 0; + if (g_se_callback != NULL) { + g_se_callback(); + g_se_callback = NULL; + } +} + /* Set the flags for an AES keyslot. */ void set_aes_keyslot_flags(unsigned int keyslot, unsigned int flags) { if (g_security_engine == NULL || keyslot >= KEYSLOT_AES_MAX) { @@ -190,3 +220,67 @@ void se_exp_mod(unsigned int keyslot, void *buf, size_t size, unsigned int (*cal while (!(g_security_engine->INT_STATUS_REG & 2)) { /* Wait a while */ } } + +void se_get_exp_mod_output(void *buf, size_t size) { + size_t num_dwords = (size >> 2); + if (num_dwords < 1) { + return; + } + + uint32_t *p_out = ((uint32_t *)buf) + num_dwords - 1; + uint32_t out_ofs = 0; + + /* Copy endian swapped output. */ + while (num_dwords) { + *p_out = read32be(g_security_engine->RSA_OUTPUT, offset); + offset += 4; + p_out--; + num_dwords--; + } +} + +void trigger_se_rsa_op(void *buf, size_t size) { + se_ll_t in_ll; + ll_init(&in_ll, buf, size); + + /* Set the input LL. */ + g_security_engine->IN_LL_ADDR_REG = get_physical_address(&in_ll); + + /* Set registers for operation. */ + g_security_engine->ERR_STATUS_REG = g_security_engine->ERR_STATUS_REG; + g_security_engine->INT_STATUS_REG = g_security_engine->INT_STATUS_REG; + g_security_engine->OPERATION_REG = 1; + + /* Ensure writes go through. */ + __asm__ __volatile__ ("dsb ish" : : : "memory"); +} + +void trigger_se_blocking_op(unsigned int op, void *dst, size_t dst_size, const void *src, size_t src_size) { + se_ll_t in_ll; + se_ll_t out_ll; + + ll_init(&in_ll, src, src_size); + ll_init(&out_ll, dst, dst_size); + + /* Set the LLs. */ + g_security_engine->IN_LL_ADDR_REG = get_physical_address(&in_ll); + g_security_enging->OUT_LL_ADDR_REG = get_physical_address(&out_ll); + + /* Set registers for operation. */ + g_security_engine->ERR_STATUS_REG = g_security_engine->ERR_STATUS_REG; + g_security_engine->INT_STATUS_REG = g_security_engine->INT_STATUS_REG; + g_security_engine->OPERATION_REG = op; + + while (!(g_security_engine->INT_STATUS_REG & 0x10)) { /* Wait a while */ } + se_check_for_error(); +} + +void se_check_for_error(void) { + if (g_security_engine == NULL) { + panic(); + } + + if (g_security_engine->INT_STATUS_REG & 0x10000 || g_security_engine->FLAGS_REG & 3 || g_security_engine->ERR_STATUS_REG) { + panic(); + } +} diff --git a/exosphere/se.h b/exosphere/se.h index 856f5b85b..16b90ed5f 100644 --- a/exosphere/se.h +++ b/exosphere/se.h @@ -75,8 +75,8 @@ typedef struct security_engine { unsigned int _0x41C; unsigned int RSA_KEYTABLE_ADDR; unsigned int RSA_KEYTABLE_DATA; - unsigned int RSA_OUTPUT; - unsigned char _0x42C[0x3D4]; + unsigned char RSA_OUTPUT[0x100]; + unsigned char _0x528[0x2D8]; unsigned int FLAGS_REG; unsigned int ERR_STATUS_REG; unsigned int _0x808; @@ -88,16 +88,30 @@ typedef struct security_engine { unsigned char _0x820[0x17E0]; } security_engine_t; +typedef struct { + uint32_t address; + uint32_t size; +} se_addr_info_t; + +typedef struct { + uint32_t num_entries; /* Set to total entries - 1 */ + se_addr_info_t addr_info; /* This should really be an array...but for our use case it works. */ +} se_ll_t; + /* TODO: Define constants for the C driver. */ /* WIP, API subject to change. */ +/* This function MUST be registered to fire on the appropriate interrupt. */ +void se_operation_completed(void); void set_security_engine_address(security_engine_t *security_engine); security_engine_t *get_security_engine_address(void); +void se_check_for_error(void); + void set_aes_keyslot_flags(unsigned int keyslot, unsigned int flags); void set_rsa_keyslot_flags(unsigned int keyslot, unsigned int flags); void clear_aes_keyslot(unsigned int keyslot); @@ -110,8 +124,12 @@ void set_aes_keyslot_iv(unsigned int keyslot, const void *iv, size_t iv_size); void set_se_ctr(const void *ctr); void se_crypt_aes(unsigned int keyslot, void *dst, size_t dst_size, const void *src, size_t src_size, unsigned int config, unsigned int mode, unsigned int (*callback)(void)); + + void se_exp_mod(unsigned int keyslot, void *buf, size_t size, unsigned int (*callback)(void)); +void se_get_exp_mod_output(void *buf, size_t size); + void se_generate_random(unsigned int keyslot, void *dst, size_t size); /* TODO: SE context save API, consider extending AES API for secure world vs non-secure world operations. */ diff --git a/exosphere/utils.h b/exosphere/utils.h index 2b5784cff..f37819d32 100644 --- a/exosphere/utils.h +++ b/exosphere/utils.h @@ -6,6 +6,8 @@ void panic(void); +uint32_t get_physical_address(void *vaddr); + static inline uint32_t read32le(const void *dword, size_t offset) { return *(uint32_t *)((uintptr_t)dword + offset); }