xref: /rk3399_rockchip-uboot/drivers/crypto/rockchip/crypto_hash_cache.c (revision 894688431927c1b73c64860c8aa71463c2593ea2)
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