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 "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();
}
}