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 if (!addr || !size) 84 return; 85 86 /* Must flush dcache before crypto DMA fetch data region */ 87 aligned_input = round_down(addr, alignment); 88 aligned_len = round_up(size + (addr - aligned_input), alignment); 89 flush_cache(aligned_input, aligned_len); 90 } 91 92 struct crypto_hash_cache *crypto_hash_cache_alloc(crypto_hash_calc direct_calc, 93 void *user_data, u32 total, 94 u32 data_align, u32 len_align) 95 { 96 struct crypto_hash_cache *hash_cache = NULL; 97 98 if (!direct_calc) 99 return NULL; 100 101 hash_cache = malloc(sizeof(struct crypto_hash_cache)); 102 if (!hash_cache) 103 return NULL; 104 105 memset(hash_cache, 0x00, sizeof(*hash_cache)); 106 107 hash_cache->direct_calc = direct_calc; 108 hash_cache->user_data = user_data; 109 hash_cache->data_align = data_align; 110 hash_cache->len_align = len_align; 111 hash_cache->left_len = total; 112 113 return hash_cache; 114 } 115 116 void crypto_hash_cache_free(struct crypto_hash_cache *hash_cache) 117 { 118 if (!hash_cache) 119 return; 120 121 if (hash_cache->cache) 122 free(hash_cache->cache); 123 124 free(hash_cache); 125 } 126 127 int crypto_hash_update_with_cache(struct crypto_hash_cache *hash_cache, 128 const u8 *data, u32 data_len) 129 { 130 crypto_hash_calc direct_calc = hash_cache->direct_calc; 131 const u8 *direct_data = NULL, *cache_data = NULL; 132 u32 direct_data_len = 0, cache_data_len = 0; 133 u8 is_last = 0; 134 int ret = 0; 135 136 if (hash_cache->left_len < data_len) 137 goto error; 138 139 is_last = hash_cache->left_len == data_len ? 1 : 0; 140 141 if (!hash_cache->use_cache && 142 IS_ALIGNED((ulong)data, hash_cache->data_align)) { 143 direct_data = data; 144 if (IS_ALIGNED(data_len, hash_cache->len_align) || is_last) { 145 /* calc all directly */ 146 debug("%s, %d: calc all directly\n", 147 __func__, __LINE__); 148 direct_data_len = data_len; 149 } else { 150 /* calc some directly calc some in cache */ 151 debug("%s, %d: calc some directly calc some in cache\n", 152 __func__, __LINE__); 153 direct_data_len = round_down((ulong)data_len, 154 hash_cache->len_align); 155 cache_data = direct_data + direct_data_len; 156 cache_data_len = data_len % hash_cache->len_align; 157 hash_cache->use_cache = 1; 158 } 159 } else { 160 /* calc all in cache */ 161 debug("%s, %d: calc all in cache\n", __func__, __LINE__); 162 cache_data = data; 163 cache_data_len = data_len; 164 hash_cache->use_cache = 1; 165 } 166 167 if (direct_data_len) { 168 debug("%s, %d: calc direct data %u\n", 169 __func__, __LINE__, direct_data_len); 170 ret = direct_calc(hash_cache->user_data, 171 direct_data, direct_data_len, 172 &hash_cache->is_started, is_last); 173 if (ret) 174 goto error; 175 hash_cache->left_len -= direct_data_len; 176 } 177 178 if (cache_data_len) { 179 debug("%s, %d: calc cache data %u\n", 180 __func__, __LINE__, cache_data_len); 181 ret = hash_cache_calc(hash_cache, cache_data, 182 cache_data_len, is_last); 183 if (ret) 184 goto error; 185 hash_cache->left_len -= cache_data_len; 186 } 187 188 return 0; 189 error: 190 if (hash_cache->cache) { 191 free(hash_cache->cache); 192 hash_cache->cache = NULL; 193 } 194 195 return -EINVAL; 196 } 197