blob: fea9d12609679b7737520483df18600c8588ce51 [file] [log] [blame]
Chia-Wei Wang8a523aa2021-07-30 09:08:04 +08001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (c) 2021 ASPEED Technology Inc.
4 * Author: ChiaWei Wang <chiawei_wang@aspeedtech.com>
5 */
6#include <config.h>
7#include <common.h>
8#include <dm.h>
9#include <log.h>
10#include <malloc.h>
11#include <watchdog.h>
12#include <u-boot/hash.h>
13#include <u-boot/crc.h>
14#include <u-boot/md5.h>
15#include <u-boot/sha1.h>
16#include <u-boot/sha256.h>
17#include <u-boot/sha512.h>
18
19/* CRC16-CCITT */
20static void hash_init_crc16_ccitt(void *ctx)
21{
22 *((uint16_t *)ctx) = 0;
23}
24
25static void hash_update_crc16_ccitt(void *ctx, const void *ibuf, uint32_t ilen)
26{
27 *((uint16_t *)ctx) = crc16_ccitt(*((uint16_t *)ctx), ibuf, ilen);
28}
29
30static void hash_finish_crc16_ccitt(void *ctx, void *obuf)
31{
32 *((uint16_t *)obuf) = *((uint16_t *)ctx);
33}
34
35/* CRC32 */
36static void hash_init_crc32(void *ctx)
37{
38 *((uint32_t *)ctx) = 0;
39}
40
41static void hash_update_crc32(void *ctx, const void *ibuf, uint32_t ilen)
42{
43 *((uint32_t *)ctx) = crc32(*((uint32_t *)ctx), ibuf, ilen);
44}
45
46static void hash_finish_crc32(void *ctx, void *obuf)
47{
48 *((uint32_t *)obuf) = *((uint32_t *)ctx);
49}
50
51/* MD5 */
52static void hash_init_md5(void *ctx)
53{
54 MD5Init((struct MD5Context *)ctx);
55}
56
57static void hash_update_md5(void *ctx, const void *ibuf, uint32_t ilen)
58{
59 MD5Update((struct MD5Context *)ctx, ibuf, ilen);
60}
61
62static void hash_finish_md5(void *ctx, void *obuf)
63{
64 MD5Final(obuf, (struct MD5Context *)ctx);
65}
66
67/* SHA1 */
68static void hash_init_sha1(void *ctx)
69{
70 sha1_starts((sha1_context *)ctx);
71}
72
73static void hash_update_sha1(void *ctx, const void *ibuf, uint32_t ilen)
74{
75 sha1_update((sha1_context *)ctx, ibuf, ilen);
76}
77
78static void hash_finish_sha1(void *ctx, void *obuf)
79{
80 sha1_finish((sha1_context *)ctx, obuf);
81}
82
83/* SHA256 */
84static void hash_init_sha256(void *ctx)
85{
86 sha256_starts((sha256_context *)ctx);
87}
88
89static void hash_update_sha256(void *ctx, const void *ibuf, uint32_t ilen)
90{
91 sha256_update((sha256_context *)ctx, ibuf, ilen);
92}
93
94static void hash_finish_sha256(void *ctx, void *obuf)
95{
96 sha256_finish((sha256_context *)ctx, obuf);
97}
98
99/* SHA384 */
100static void hash_init_sha384(void *ctx)
101{
102 sha384_starts((sha512_context *)ctx);
103}
104
105static void hash_update_sha384(void *ctx, const void *ibuf, uint32_t ilen)
106{
107 sha384_update((sha512_context *)ctx, ibuf, ilen);
108}
109
110static void hash_finish_sha384(void *ctx, void *obuf)
111{
112 sha384_finish((sha512_context *)ctx, obuf);
113}
114
115/* SHA512 */
116static void hash_init_sha512(void *ctx)
117{
118 sha512_starts((sha512_context *)ctx);
119}
120
121static void hash_update_sha512(void *ctx, const void *ibuf, uint32_t ilen)
122{
123 sha512_update((sha512_context *)ctx, ibuf, ilen);
124}
125
126static void hash_finish_sha512(void *ctx, void *obuf)
127{
128 sha512_finish((sha512_context *)ctx, obuf);
129}
130
131struct sw_hash_ctx {
132 enum HASH_ALGO algo;
133 uint8_t algo_ctx[];
134};
135
136struct sw_hash_impl {
137 void (*init)(void *ctx);
138 void (*update)(void *ctx, const void *ibuf, uint32_t ilen);
139 void (*finish)(void *ctx, void *obuf);
140 uint32_t ctx_alloc_sz;
141};
142
143static struct sw_hash_impl sw_hash_impl[HASH_ALGO_NUM] = {
144 [HASH_ALGO_CRC16_CCITT] = {
145 .init = hash_init_crc16_ccitt,
146 .update = hash_update_crc16_ccitt,
147 .finish = hash_finish_crc16_ccitt,
148 .ctx_alloc_sz = sizeof(uint16_t),
149 },
150
151 [HASH_ALGO_CRC32] = {
152 .init = hash_init_crc32,
153 .update = hash_update_crc32,
154 .finish = hash_finish_crc32,
155 .ctx_alloc_sz = sizeof(uint32_t),
156 },
157
158 [HASH_ALGO_MD5] = {
159 .init = hash_init_md5,
160 .update = hash_update_md5,
161 .finish = hash_finish_md5,
162 .ctx_alloc_sz = sizeof(struct MD5Context),
163 },
164
165 [HASH_ALGO_SHA1] = {
166 .init = hash_init_sha1,
167 .update = hash_update_sha1,
168 .finish = hash_finish_sha1,
169 .ctx_alloc_sz = sizeof(sha1_context),
170 },
171
172 [HASH_ALGO_SHA256] = {
173 .init = hash_init_sha256,
174 .update = hash_update_sha256,
175 .finish = hash_finish_sha256,
176 .ctx_alloc_sz = sizeof(sha256_context),
177 },
178
179 [HASH_ALGO_SHA384] = {
180 .init = hash_init_sha384,
181 .update = hash_update_sha384,
182 .finish = hash_finish_sha384,
183 .ctx_alloc_sz = sizeof(sha512_context),
184 },
185
186 [HASH_ALGO_SHA512] = {
187 .init = hash_init_sha512,
188 .update = hash_update_sha512,
189 .finish = hash_finish_sha512,
190 .ctx_alloc_sz = sizeof(sha512_context),
191 },
192};
193
194static int sw_hash_init(struct udevice *dev, enum HASH_ALGO algo, void **ctxp)
195{
196 struct sw_hash_ctx *hash_ctx;
197 struct sw_hash_impl *hash_impl = &sw_hash_impl[algo];
198
199 hash_ctx = malloc(sizeof(hash_ctx->algo) + hash_impl->ctx_alloc_sz);
200 if (!hash_ctx)
201 return -ENOMEM;
202
203 hash_ctx->algo = algo;
204
205 hash_impl->init(hash_ctx->algo_ctx);
206
207 *ctxp = hash_ctx;
208
209 return 0;
210}
211
212static int sw_hash_update(struct udevice *dev, void *ctx, const void *ibuf, uint32_t ilen)
213{
214 struct sw_hash_ctx *hash_ctx = ctx;
215 struct sw_hash_impl *hash_impl = &sw_hash_impl[hash_ctx->algo];
216
217 hash_impl->update(hash_ctx->algo_ctx, ibuf, ilen);
218
219 return 0;
220}
221
222static int sw_hash_finish(struct udevice *dev, void *ctx, void *obuf)
223{
224 struct sw_hash_ctx *hash_ctx = ctx;
225 struct sw_hash_impl *hash_impl = &sw_hash_impl[hash_ctx->algo];
226
227 hash_impl->finish(hash_ctx->algo_ctx, obuf);
228
229 free(ctx);
230
231 return 0;
232}
233
234static int sw_hash_digest_wd(struct udevice *dev, enum HASH_ALGO algo,
235 const void *ibuf, const uint32_t ilen,
236 void *obuf, uint32_t chunk_sz)
237{
238 int rc;
239 void *ctx;
240 const void *cur, *end;
241 uint32_t chunk;
242
243 rc = sw_hash_init(dev, algo, &ctx);
244 if (rc)
245 return rc;
246
247 if (CONFIG_IS_ENABLED(HW_WATCHDOG) || CONFIG_IS_ENABLED(WATCHDOG)) {
248 cur = ibuf;
249 end = ibuf + ilen;
250
251 while (cur < end) {
252 chunk = end - cur;
253 if (chunk > chunk_sz)
254 chunk = chunk_sz;
255
256 rc = sw_hash_update(dev, ctx, cur, chunk);
257 if (rc)
258 return rc;
259
260 cur += chunk;
261 WATCHDOG_RESET();
262 }
263 } else {
264 rc = sw_hash_update(dev, ctx, ibuf, ilen);
265 if (rc)
266 return rc;
267 }
268
269 rc = sw_hash_finish(dev, ctx, obuf);
270 if (rc)
271 return rc;
272
273 return 0;
274}
275
276static int sw_hash_digest(struct udevice *dev, enum HASH_ALGO algo,
277 const void *ibuf, const uint32_t ilen,
278 void *obuf)
279{
280 /* re-use the watchdog version with input length as the chunk_sz */
281 return sw_hash_digest_wd(dev, algo, ibuf, ilen, obuf, ilen);
282}
283
284static const struct hash_ops hash_ops_sw = {
285 .hash_init = sw_hash_init,
286 .hash_update = sw_hash_update,
287 .hash_finish = sw_hash_finish,
288 .hash_digest_wd = sw_hash_digest_wd,
289 .hash_digest = sw_hash_digest,
290};
291
292U_BOOT_DRIVER(hash_sw) = {
293 .name = "hash_sw",
294 .id = UCLASS_HASH,
295 .ops = &hash_ops_sw,
296 .flags = DM_FLAG_PRE_RELOC,
297};
298
299U_BOOT_DRVINFO(hash_sw) = {
300 .name = "hash_sw",
301};