197 lines
4.8 KiB
C
197 lines
4.8 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (c) 2020 Rockchip Electronics Co., Ltd
|
|
*/
|
|
|
|
#include <common.h>
|
|
#include <clk.h>
|
|
#include <crypto.h>
|
|
|
|
#include <rockchip/crypto_hash_cache.h>
|
|
|
|
static int hash_cache_calc(struct crypto_hash_cache *hash_cache, const u8 *data,
|
|
u32 data_len, u8 is_last)
|
|
{
|
|
crypto_hash_calc direct_calc = hash_cache->direct_calc;
|
|
int ret = 0;
|
|
|
|
if (!hash_cache->cache) {
|
|
hash_cache->cache = (u8 *)memalign(CONFIG_SYS_CACHELINE_SIZE,
|
|
HASH_CACHE_SIZE);
|
|
if (!hash_cache->cache)
|
|
goto error;
|
|
|
|
hash_cache->cache_size = 0;
|
|
}
|
|
|
|
while (1) {
|
|
u32 tmp_len = 0;
|
|
|
|
if (hash_cache->cache_size + data_len <= HASH_CACHE_SIZE) {
|
|
/* copy to cache */
|
|
debug("%s, %d: copy to cache %u\n",
|
|
__func__, __LINE__, data_len);
|
|
memcpy(hash_cache->cache + hash_cache->cache_size, data,
|
|
data_len);
|
|
hash_cache->cache_size += data_len;
|
|
|
|
/* if last one calc cache immediately */
|
|
if (is_last) {
|
|
debug("%s, %d: last one calc cache %u\n",
|
|
__func__, __LINE__,
|
|
hash_cache->cache_size);
|
|
|
|
ret = direct_calc(hash_cache->user_data,
|
|
hash_cache->cache,
|
|
hash_cache->cache_size,
|
|
&hash_cache->is_started,
|
|
is_last);
|
|
if (ret)
|
|
goto error;
|
|
}
|
|
break;
|
|
}
|
|
|
|
/* 1. make cache be full */
|
|
/* 2. calc cache */
|
|
tmp_len = HASH_CACHE_SIZE - hash_cache->cache_size;
|
|
debug("%s, %d: make cache be full %u\n",
|
|
__func__, __LINE__, tmp_len);
|
|
memcpy(hash_cache->cache + hash_cache->cache_size,
|
|
data, tmp_len);
|
|
|
|
ret = direct_calc(hash_cache->user_data, hash_cache->cache,
|
|
HASH_CACHE_SIZE, &hash_cache->is_started, 0);
|
|
if (ret)
|
|
goto error;
|
|
|
|
data += tmp_len;
|
|
data_len -= tmp_len;
|
|
hash_cache->cache_size = 0;
|
|
}
|
|
|
|
return ret;
|
|
error:
|
|
return -EINVAL;
|
|
}
|
|
|
|
void crypto_flush_cacheline(ulong addr, ulong size)
|
|
{
|
|
ulong alignment = CONFIG_SYS_CACHELINE_SIZE;
|
|
ulong aligned_input, aligned_len;
|
|
|
|
if (!addr || !size)
|
|
return;
|
|
|
|
/* Must flush dcache before crypto DMA fetch data region */
|
|
aligned_input = round_down(addr, alignment);
|
|
aligned_len = round_up(size + (addr - aligned_input), alignment);
|
|
flush_cache(aligned_input, aligned_len);
|
|
}
|
|
|
|
struct crypto_hash_cache *crypto_hash_cache_alloc(crypto_hash_calc direct_calc,
|
|
void *user_data, u32 total,
|
|
u32 data_align, u32 len_align)
|
|
{
|
|
struct crypto_hash_cache *hash_cache = NULL;
|
|
|
|
if (!direct_calc)
|
|
return NULL;
|
|
|
|
hash_cache = malloc(sizeof(struct crypto_hash_cache));
|
|
if (!hash_cache)
|
|
return NULL;
|
|
|
|
memset(hash_cache, 0x00, sizeof(*hash_cache));
|
|
|
|
hash_cache->direct_calc = direct_calc;
|
|
hash_cache->user_data = user_data;
|
|
hash_cache->data_align = data_align;
|
|
hash_cache->len_align = len_align;
|
|
hash_cache->left_len = total;
|
|
|
|
return hash_cache;
|
|
}
|
|
|
|
void crypto_hash_cache_free(struct crypto_hash_cache *hash_cache)
|
|
{
|
|
if (!hash_cache)
|
|
return;
|
|
|
|
if (hash_cache->cache)
|
|
free(hash_cache->cache);
|
|
|
|
free(hash_cache);
|
|
}
|
|
|
|
int crypto_hash_update_with_cache(struct crypto_hash_cache *hash_cache,
|
|
const u8 *data, u32 data_len)
|
|
{
|
|
crypto_hash_calc direct_calc = hash_cache->direct_calc;
|
|
const u8 *direct_data = NULL, *cache_data = NULL;
|
|
u32 direct_data_len = 0, cache_data_len = 0;
|
|
u8 is_last = 0;
|
|
int ret = 0;
|
|
|
|
if (hash_cache->left_len < data_len)
|
|
goto error;
|
|
|
|
is_last = hash_cache->left_len == data_len ? 1 : 0;
|
|
|
|
if (!hash_cache->use_cache &&
|
|
IS_ALIGNED((ulong)data, hash_cache->data_align)) {
|
|
direct_data = data;
|
|
if (IS_ALIGNED(data_len, hash_cache->len_align) || is_last) {
|
|
/* calc all directly */
|
|
debug("%s, %d: calc all directly\n",
|
|
__func__, __LINE__);
|
|
direct_data_len = data_len;
|
|
} else {
|
|
/* calc some directly calc some in cache */
|
|
debug("%s, %d: calc some directly calc some in cache\n",
|
|
__func__, __LINE__);
|
|
direct_data_len = round_down((ulong)data_len,
|
|
hash_cache->len_align);
|
|
cache_data = direct_data + direct_data_len;
|
|
cache_data_len = data_len % hash_cache->len_align;
|
|
hash_cache->use_cache = 1;
|
|
}
|
|
} else {
|
|
/* calc all in cache */
|
|
debug("%s, %d: calc all in cache\n", __func__, __LINE__);
|
|
cache_data = data;
|
|
cache_data_len = data_len;
|
|
hash_cache->use_cache = 1;
|
|
}
|
|
|
|
if (direct_data_len) {
|
|
debug("%s, %d: calc direct data %u\n",
|
|
__func__, __LINE__, direct_data_len);
|
|
ret = direct_calc(hash_cache->user_data,
|
|
direct_data, direct_data_len,
|
|
&hash_cache->is_started, is_last);
|
|
if (ret)
|
|
goto error;
|
|
hash_cache->left_len -= direct_data_len;
|
|
}
|
|
|
|
if (cache_data_len) {
|
|
debug("%s, %d: calc cache data %u\n",
|
|
__func__, __LINE__, cache_data_len);
|
|
ret = hash_cache_calc(hash_cache, cache_data,
|
|
cache_data_len, is_last);
|
|
if (ret)
|
|
goto error;
|
|
hash_cache->left_len -= cache_data_len;
|
|
}
|
|
|
|
return 0;
|
|
error:
|
|
if (hash_cache->cache) {
|
|
free(hash_cache->cache);
|
|
hash_cache->cache = NULL;
|
|
}
|
|
|
|
return -EINVAL;
|
|
}
|