/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */ /* * drivers/securestorage/securestorage.c * * Copyright (C) 2020 Amlogic, Inc. All rights reserved. * */ #include #include #include #include #include #include static uint64_t storage_share_in_base; static uint64_t storage_share_out_base; static uint64_t storage_share_block_base; static uint64_t storage_share_block_size; static int32_t storage_init_status; static uint64_t bl31_storage_ops(uint64_t function_id) { struct arm_smccc_res res; arm_smccc_smc(function_id, 0, 0, 0, 0, 0, 0, 0, &res); return res.a0; } uint64_t bl31_storage_ops2(uint64_t function_id, uint64_t arg1) { struct arm_smccc_res res; arm_smccc_smc(function_id, arg1, 0, 0, 0, 0, 0, 0, &res); return res.a0; } uint64_t bl31_storage_ops3(uint64_t function_id, uint64_t arg1, uint32_t arg2) { struct arm_smccc_res res; arm_smccc_smc(function_id, arg1, arg2, 0, 0, 0, 0, 0, &res); return res.a0; } static uint64_t bl31_storage_write(uint8_t *keyname, uint8_t *keybuf, uint32_t keylen, uint32_t keyattr) { uint32_t *input = (uint32_t *)storage_share_in_base; uint8_t *data; uint32_t namelen; namelen = strlen((const char *)keyname); *input++ = namelen; *input++ = keylen; *input++ = keyattr; data = (uint8_t *)input; memcpy(data, keyname, namelen); data += namelen; memcpy(data, keybuf, keylen); return bl31_storage_ops(SECURITY_KEY_WRITE); } static uint64_t bl31_storage_read(uint8_t *keyname, uint8_t *keybuf, uint32_t keylen, uint32_t *readlen) { uint32_t *input = (uint32_t *)storage_share_in_base; uint32_t *output = (uint32_t *)storage_share_out_base; uint32_t namelen; uint8_t *name, *buf; uint64_t ret; namelen = strlen((const char *)keyname); *input++ = namelen; *input++ = keylen; name = (uint8_t *)input; memcpy(name, keyname, namelen); ret = bl31_storage_ops(SECURITY_KEY_READ); if (ret == RET_OK) { *readlen = *output; buf = (uint8_t *)(output+1); memcpy(keybuf, buf, *readlen); } return ret; } static uint64_t bl31_storage_query(uint8_t *keyname, uint32_t *retval) { uint32_t *input = (uint32_t *)storage_share_in_base; uint32_t *output = (uint32_t *)storage_share_out_base; uint32_t namelen; uint8_t *name; uint64_t ret; namelen = strlen((const char *)keyname); *input++ = namelen; name = (uint8_t *)input; memcpy(name, keyname, namelen); ret = bl31_storage_ops(SECURITY_KEY_QUERY); if (ret == RET_OK) *retval = *output; return ret; } static uint64_t bl31_storage_status(uint8_t *keyname, uint32_t *retval) { uint32_t *input = (uint32_t *)storage_share_in_base; uint32_t *output = (uint32_t *)storage_share_out_base; uint32_t namelen; uint8_t *name; uint64_t ret; namelen = strlen((const char *)keyname); *input++ = namelen; name = (uint8_t *)input; memcpy(name, keyname, namelen); ret = bl31_storage_ops(SECURITY_KEY_STATUS); if (ret == RET_OK) *retval = *output; return ret; } static uint64_t bl31_storage_tell(uint8_t *keyname, uint32_t *retval) { uint32_t *input = (uint32_t *)storage_share_in_base; uint32_t *output = (uint32_t *)storage_share_out_base; uint32_t namelen; uint8_t *name; uint64_t ret; namelen = strlen((const char *)keyname); *input++ = namelen; name = (uint8_t *)input; memcpy(name, keyname, namelen); ret = bl31_storage_ops(SECURITY_KEY_TELL); if (ret == RET_OK) *retval = *output; return ret; } static uint64_t bl31_storage_verify(uint8_t *keyname, uint8_t *hashbuf) { uint32_t *input = (uint32_t *)storage_share_in_base; uint32_t *output = (uint32_t *)storage_share_out_base; uint32_t namelen; uint8_t *name; uint64_t ret; namelen = strlen((const char *)keyname); *input++ = namelen; name = (uint8_t *)input; memcpy(name, keyname, namelen); ret = bl31_storage_ops(SECURITY_KEY_VERIFY); if (ret == RET_OK) memcpy(hashbuf, (uint8_t *)output, 32); return ret; } static uint64_t bl31_storage_list(uint8_t *listbuf, uint32_t outlen, uint32_t *readlen) { uint32_t *output = (uint32_t *)storage_share_out_base; uint64_t ret; ret = bl31_storage_ops(SECURITY_KEY_LIST); if (ret == RET_OK) { if (*output > outlen) *readlen = outlen; else *readlen = *output; memcpy(listbuf, (uint8_t *)(output+1), *readlen); } return ret; } static uint64_t bl31_storage_remove(uint8_t *keyname) { uint32_t *input = (uint32_t *)storage_share_in_base; uint32_t namelen; uint8_t *name; namelen = strlen((const char *)keyname); *input++ = namelen; name = (uint8_t *)input; memcpy(name, keyname, namelen); return bl31_storage_ops(SECURITY_KEY_REMOVE); } static inline int32_t smc_to_ns_errno(uint64_t errno) { int32_t ret = (int32_t)(errno&0xffffffff); return ret; } void secure_storage_init(void) { storage_share_in_base = bl31_storage_ops(GET_SHARE_STORAGE_IN_BASE); storage_share_out_base = bl31_storage_ops(GET_SHARE_STORAGE_OUT_BASE); storage_share_block_base = bl31_storage_ops(GET_SHARE_STORAGE_BLOCK_BASE); storage_share_block_size = bl31_storage_ops(GET_SHARE_STORAGE_BLOCK_SIZE); if ((int)storage_share_in_base == SMC_UNK || (int)storage_share_out_base == SMC_UNK || (int)storage_share_block_base == SMC_UNK || (int)storage_share_block_size == SMC_UNK) storage_init_status = -1; else storage_init_status = 1; } void *secure_storage_getbuffer(uint32_t *size) { if (storage_init_status == 0) secure_storage_init(); if (storage_init_status == 1) { storage_share_block_size = bl31_storage_ops(GET_SHARE_STORAGE_BLOCK_SIZE); *size = (uint32_t)storage_share_block_size; return (void *)storage_share_block_base; } else { *size = 0; return NULL; } } void secure_storage_notifier(void) { bl31_storage_ops(SECURITY_KEY_NOTIFY); } void secure_storage_notifier_ex(uint32_t storagesize, uint32_t rsvarg) { bl31_storage_ops3(SECURITY_KEY_NOTIFY_EX, storagesize, rsvarg); } int32_t secure_storage_write(uint8_t *keyname, uint8_t *keybuf, uint32_t keylen, uint32_t keyattr) { uint32_t ret; if (storage_init_status == 0) secure_storage_init(); if (storage_init_status == 1) ret = bl31_storage_write(keyname, keybuf, keylen, keyattr); else ret = RET_EUND; return smc_to_ns_errno(ret); } int32_t secure_storage_read(uint8_t *keyname, uint8_t *keybuf, uint32_t keylen, uint32_t *readlen) { uint64_t ret; if (storage_init_status == 0) secure_storage_init(); if (storage_init_status == 1) ret = bl31_storage_read(keyname, keybuf, keylen, readlen); else ret = RET_EUND; return smc_to_ns_errno(ret); } int32_t secure_storage_query(uint8_t *keyname, uint32_t *retval) { uint64_t ret; if (storage_init_status == 0) secure_storage_init(); if (storage_init_status == 1) ret = bl31_storage_query(keyname, retval); else ret = RET_EUND; return smc_to_ns_errno(ret); } int32_t secure_storage_status(uint8_t *keyname, uint32_t *retval) { uint64_t ret; if (storage_init_status == 0) secure_storage_init(); if (storage_init_status == 1) ret = bl31_storage_status(keyname, retval); else ret = RET_EUND; return smc_to_ns_errno(ret); } int32_t secure_storage_tell(uint8_t *keyname, uint32_t *retval) { uint64_t ret; if (storage_init_status == 0) secure_storage_init(); if (storage_init_status == 1) ret = bl31_storage_tell(keyname, retval); else ret = RET_EUND; return smc_to_ns_errno(ret); } int32_t secure_storage_verify(uint8_t *keyname, uint8_t *hashbuf) { uint64_t ret; if (storage_init_status == 0) secure_storage_init(); if (storage_init_status == 1) ret = bl31_storage_verify(keyname, hashbuf); else ret = RET_EUND; return smc_to_ns_errno(ret); } int32_t secure_storage_list(uint8_t *listbuf, uint32_t buflen, uint32_t *readlen) { uint64_t ret; if (storage_init_status == 0) secure_storage_init(); if (storage_init_status == 1) ret = bl31_storage_list(listbuf, buflen, readlen); else ret = RET_EUND; return smc_to_ns_errno(ret); } int32_t secure_storage_remove(uint8_t *keyname) { uint64_t ret; if (storage_init_status == 0) secure_storage_init(); if (storage_init_status == 1) ret = bl31_storage_remove(keyname); else ret = RET_EUND; return smc_to_ns_errno(ret); } void secure_storage_set_info(uint32_t info) { struct arm_smccc_res res; arm_smccc_smc(SET_STORAGE_INFO, info, 0, 0, 0, 0, 0, 0, &res); } int32_t secure_storage_set_enctype(uint32_t type) { uint64_t ret; ret = bl31_storage_ops2(SECURITY_KEY_SET_ENCTYPE, type); return smc_to_ns_errno(ret); } int32_t secure_storage_get_enctype(void) { uint64_t ret; ret = bl31_storage_ops(SECURITY_KEY_GET_ENCTYPE); return smc_to_ns_errno(ret); } int32_t secure_storage_version(void) { uint64_t ret; ret = bl31_storage_ops(SECURITY_KEY_VERSION); return smc_to_ns_errno(ret); }