1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (c) 2020 Rockchip Electronics Co., Ltd 4 */ 5 6 #include <common.h> 7 #include <clk.h> 8 #include <crypto.h> 9 10 #include <rockchip/crypto_hash_cache.h> 11 12 static int hash_cache_calc(struct crypto_hash_cache *hash_cache, const u8 *data, 13 u32 data_len, u8 is_last) 14 { 15 crypto_hash_calc direct_calc = hash_cache->direct_calc; 16 int ret = 0; 17 18 if (!hash_cache->cache) { 19 hash_cache->cache = (u8 *)memalign(CONFIG_SYS_CACHELINE_SIZE, 20 HASH_CACHE_SIZE); 21 if (!hash_cache->cache) 22 goto error; 23 24 hash_cache->cache_size = 0; 25 } 26 27 while (1) { 28 u32 tmp_len = 0; 29 30 if (hash_cache->cache_size + data_len <= HASH_CACHE_SIZE) { 31 /* copy to cache */ 32 debug("%s, %d: copy to cache %u\n", 33 __func__, __LINE__, data_len); 34 memcpy(hash_cache->cache + hash_cache->cache_size, data, 35 data_len); 36 hash_cache->cache_size += data_len; 37 38 /* if last one calc cache immediately */ 39 if (is_last) { 40 debug("%s, %d: last one calc cache %u\n", 41 __func__, __LINE__, 42 hash_cache->cache_size); 43 44 ret = direct_calc(hash_cache->user_data, 45 hash_cache->cache, 46 hash_cache->cache_size, 47 &hash_cache->is_started, 48 is_last); 49 if (ret) 50 goto error; 51 } 52 break; 53 } 54 55 /* 1. make cache be full */ 56 /* 2. calc cache */ 57 tmp_len = HASH_CACHE_SIZE - hash_cache->cache_size; 58 debug("%s, %d: make cache be full %u\n", 59 __func__, __LINE__, tmp_len); 60 memcpy(hash_cache->cache + hash_cache->cache_size, 61 data, tmp_len); 62 63 ret = direct_calc(hash_cache->user_data, hash_cache->cache, 64 HASH_CACHE_SIZE, &hash_cache->is_started, 0); 65 if (ret) 66 goto error; 67 68 data += tmp_len; 69 data_len -= tmp_len; 70 hash_cache->cache_size = 0; 71 } 72 73 return ret; 74 error: 75 return -EINVAL; 76 } 77 78 void crypto_flush_cacheline(ulong addr, ulong size) 79 { 80 ulong alignment = CONFIG_SYS_CACHELINE_SIZE; 81 ulong aligned_input, aligned_len; 82 83 /* Must flush dcache before crypto DMA fetch data region */ 84 aligned_input = round_down(addr, alignment); 85 aligned_len = round_up(size + (addr - aligned_input), alignment); 86 flush_cache(aligned_input, aligned_len); 87 } 88 89 struct crypto_hash_cache *crypto_hash_cache_alloc(crypto_hash_calc direct_calc, 90 void *user_data, u32 total, 91 u32 data_align, u32 len_align) 92 { 93 struct crypto_hash_cache *hash_cache = NULL; 94 95 if (!direct_calc) 96 return NULL; 97 98 hash_cache = malloc(sizeof(struct crypto_hash_cache)); 99 if (!hash_cache) 100 return NULL; 101 102 memset(hash_cache, 0x00, sizeof(*hash_cache)); 103 104 hash_cache->direct_calc = direct_calc; 105 hash_cache->user_data = user_data; 106 hash_cache->data_align = data_align; 107 hash_cache->len_align = len_align; 108 hash_cache->left_len = total; 109 110 return hash_cache; 111 } 112 113 void crypto_hash_cache_free(struct crypto_hash_cache *hash_cache) 114 { 115 if (!hash_cache) 116 return; 117 118 if (hash_cache->cache) 119 free(hash_cache->cache); 120 121 free(hash_cache); 122 } 123 124 int crypto_hash_update_with_cache(struct crypto_hash_cache *hash_cache, 125 const u8 *data, u32 data_len) 126 { 127 crypto_hash_calc direct_calc = hash_cache->direct_calc; 128 const u8 *direct_data = NULL, *cache_data = NULL; 129 u32 direct_data_len = 0, cache_data_len = 0; 130 u8 is_last = 0; 131 int ret = 0; 132 133 if (hash_cache->left_len < data_len) 134 goto error; 135 136 is_last = hash_cache->left_len == data_len ? 1 : 0; 137 138 if (!hash_cache->use_cache && 139 IS_ALIGNED((ulong)data, hash_cache->data_align)) { 140 direct_data = data; 141 if (IS_ALIGNED(data_len, hash_cache->len_align) || is_last) { 142 /* calc all directly */ 143 debug("%s, %d: calc all directly\n", 144 __func__, __LINE__); 145 direct_data_len = data_len; 146 } else { 147 /* calc some directly calc some in cache */ 148 debug("%s, %d: calc some directly calc some in cache\n", 149 __func__, __LINE__); 150 direct_data_len = round_down((ulong)data_len, 151 hash_cache->len_align); 152 cache_data = direct_data + direct_data_len; 153 cache_data_len = data_len % hash_cache->len_align; 154 hash_cache->use_cache = 1; 155 } 156 } else { 157 /* calc all in cache */ 158 debug("%s, %d: calc all in cache\n", __func__, __LINE__); 159 cache_data = data; 160 cache_data_len = data_len; 161 hash_cache->use_cache = 1; 162 } 163 164 if (direct_data_len) { 165 debug("%s, %d: calc direct data %u\n", 166 __func__, __LINE__, direct_data_len); 167 ret = direct_calc(hash_cache->user_data, 168 direct_data, direct_data_len, 169 &hash_cache->is_started, is_last); 170 if (ret) 171 goto error; 172 hash_cache->left_len -= direct_data_len; 173 } 174 175 if (cache_data_len) { 176 debug("%s, %d: calc cache data %u\n", 177 __func__, __LINE__, cache_data_len); 178 ret = hash_cache_calc(hash_cache, cache_data, 179 cache_data_len, is_last); 180 if (ret) 181 goto error; 182 hash_cache->left_len -= cache_data_len; 183 } 184 185 return 0; 186 error: 187 if (hash_cache->cache) { 188 free(hash_cache->cache); 189 hash_cache->cache = NULL; 190 } 191 192 return -EINVAL; 193 } 194