Flesh out more of the SE driver

This commit is contained in:
Michael Scire 2018-02-19 01:27:50 -08:00
parent f77cae48d0
commit 83fd2c43a3
3 changed files with 117 additions and 3 deletions

View file

@ -1,9 +1,12 @@
#include <stdint.h>
#include <stddef.h>
#include "utils.h" #include "utils.h"
#include "cache.h" #include "cache.h"
#include "se.h" #include "se.h"
void trigger_se_rsa_op(void *buf, size_t size); 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. */ /* Globals for driver. */
volatile security_engine_t *g_security_engine; 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_modulus_sizes[KEYSLOT_RSA_MAX];
unsigned int g_se_exp_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. */ /* Set the global security engine pointer. */
void set_security_engine_address(security_engine_t *security_engine) { void set_security_engine_address(security_engine_t *security_engine) {
g_security_engine = security_engine; g_security_engine = security_engine;
@ -31,6 +49,18 @@ void set_security_engine_callback(unsigned int (*callback)(void)) {
g_se_callback = callback; 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. */ /* Set the flags for an AES keyslot. */
void set_aes_keyslot_flags(unsigned int keyslot, unsigned int flags) { void set_aes_keyslot_flags(unsigned int keyslot, unsigned int flags) {
if (g_security_engine == NULL || keyslot >= KEYSLOT_AES_MAX) { 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 */ } 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();
}
}

View file

@ -75,8 +75,8 @@ typedef struct security_engine {
unsigned int _0x41C; unsigned int _0x41C;
unsigned int RSA_KEYTABLE_ADDR; unsigned int RSA_KEYTABLE_ADDR;
unsigned int RSA_KEYTABLE_DATA; unsigned int RSA_KEYTABLE_DATA;
unsigned int RSA_OUTPUT; unsigned char RSA_OUTPUT[0x100];
unsigned char _0x42C[0x3D4]; unsigned char _0x528[0x2D8];
unsigned int FLAGS_REG; unsigned int FLAGS_REG;
unsigned int ERR_STATUS_REG; unsigned int ERR_STATUS_REG;
unsigned int _0x808; unsigned int _0x808;
@ -88,16 +88,30 @@ typedef struct security_engine {
unsigned char _0x820[0x17E0]; unsigned char _0x820[0x17E0];
} security_engine_t; } 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. */ /* TODO: Define constants for the C driver. */
/* WIP, API subject to change. */ /* 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); void set_security_engine_address(security_engine_t *security_engine);
security_engine_t *get_security_engine_address(void); 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_aes_keyslot_flags(unsigned int keyslot, unsigned int flags);
void set_rsa_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); 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 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_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_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); 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. */ /* TODO: SE context save API, consider extending AES API for secure world vs non-secure world operations. */

View file

@ -6,6 +6,8 @@
void panic(void); void panic(void);
uint32_t get_physical_address(void *vaddr);
static inline uint32_t read32le(const void *dword, size_t offset) { static inline uint32_t read32le(const void *dword, size_t offset) {
return *(uint32_t *)((uintptr_t)dword + offset); return *(uint32_t *)((uintptr_t)dword + offset);
} }