blob: 141cbedc9c3dea99f8e76a5f3b0197389f849a12 [file] [log] [blame]
/*
* Copyright (C) 2017 Amlogic, Inc. All rights reserved.
* *
This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* *
This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
* *
You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
* *
Description:
*/
#include <common.h>
#include <linux/types.h>
#include <asm/arch/secure_apb.h>
#include <amlogic/secure_storage.h>
#include <asm/arch/bl31_apis.h>
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)
{
asm volatile(
__asmeq("%0", "x0")
"smc #0\n"
: "+r" (function_id));
return function_id;
}
uint64_t bl31_storage_ops2(uint64_t function_id, uint64_t arg1)
{
asm volatile(
__asmeq("%0", "x0")
__asmeq("%1", "x1")
"smc #0\n"
: "+r" (function_id)
: "r"(arg1));
return function_id;
}
uint64_t bl31_storage_ops3(uint64_t function_id, uint64_t arg1, uint32_t arg2)
{
asm volatile(
__asmeq("%0", "x0")
__asmeq("%1", "x1")
__asmeq("%2", "x2")
"smc #0\n"
: "+r" (function_id)
: "r"(arg1), "r"(arg2));
return function_id;
}
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 (storage_share_in_base == SMC_UNK
|| storage_share_out_base == SMC_UNK
|| storage_share_block_base == SMC_UNK
|| 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)
{
register uint64_t x0 asm("x0")= SET_STORAGE_INFO;
register uint64_t x1 asm("x1") = info;
asm volatile(
__asmeq("%0", "x0")
__asmeq("%1", "x1")
"smc #0\n"
: :"r" (x0), "r"(x1));
}
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);
}