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
hash_cache_calc(struct crypto_hash_cache * hash_cache,const u8 * data,u32 data_len,u8 is_last)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
crypto_flush_cacheline(ulong addr,ulong size)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
crypto_hash_cache_alloc(crypto_hash_calc direct_calc,void * user_data,u32 total,u32 data_align,u32 len_align)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
crypto_hash_cache_free(struct crypto_hash_cache * hash_cache)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
crypto_hash_update_with_cache(struct crypto_hash_cache * hash_cache,const u8 * data,u32 data_len)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