mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2024-12-18 08:22:04 +00:00
Flesh out more of the SE driver
This commit is contained in:
parent
f77cae48d0
commit
83fd2c43a3
3 changed files with 117 additions and 3 deletions
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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. */
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue