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