1// 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 (IS_ENABLED(CONFIG_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 schedule(); 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}; 302