[PATCH v8 06/15] crypto: hash: support hardware-only progressive hashing
James Hilliard <[email protected]>
| Newsgroups | gmane.comp.boot-loaders.u-boot |
|---|---|
| Message-ID | <20260814-submit-ce-series-v2-v8-6-fe9212431a94__4951.469977253$1786798916$gmane$org@gmail.com> |
FIT configuration signatures hash multiple discontiguous regions through the legacy progressive hash interface. This still requires a software implementation even when image hashes use a driver-model hardware provider. Add provider selection for progressive driver-model hashing and use it from hash_calculate(). Allow SPL_SHA256_LEGACY to be disabled explicitly, link the SHA-256 software support only for a selected software backend, and make legacy fallback paths reject an algorithm whose software callbacks are absent. Make a successful driver-model initialization require the complete init, update, finish and abort lifecycle. Add the abort operation to existing providers and use it to release a provider context after any update failure. Enable DM_HASH in the sandbox configuration so these driver-model paths are built and exercised by the standard sandbox tests. Extend the hash provider-selection test to cover progressive initialization and error cleanup. This permits SPL to retain SHA-256 FIT support while relying exclusively on a hardware hash provider. Reviewed-by: Simon Glass <[email protected]> Signed-off-by: James Hilliard <[email protected]> --- Changes v7 -> v8: - Add an explicit abort operation and release provider contexts after update failures (suggested by Simon Glass) - Add the progressive provider-selection and error-cleanup test omitted from v7 - Enable DM_HASH in sandbox so the hash provider tests are built and run by normal sandbox CI Changes v6 -> v7: - New patch --- boot/image-fit.c | 2 +- common/hash.c | 21 +++++- configs/sandbox_defconfig | 1 + drivers/crypto/aspeed/aspeed_hace.c | 18 ++++- drivers/crypto/aspeed/cptra_sha.c | 34 +++++++--- drivers/crypto/hash/hash-uclass.c | 44 +++++++++++- drivers/crypto/hash/hash_sw.c | 20 ++++-- include/u-boot/hash.h | 30 ++++++++ lib/Makefile | 4 +- lib/hash-checksum.c | 30 +++++++- lib/mbedtls/Kconfig | 2 +- test/dm/hash.c | 132 ++++++++++++++++++++++++++++++++++++ 12 files changed, 312 insertions(+), 26 deletions(-) diff --git a/boot/image-fit.c b/boot/image-fit.c index 9b39696de2d..86ebf58680d 100644 --- a/boot/image-fit.c +++ b/boot/image-fit.c @@ -1342,7 +1342,7 @@ int calculate_hash(const void *data, int data_len, const char *name, #endif ret = hash_lookup_algo(name, &algo); - if (ret < 0) { + if (ret < 0 || !algo->hash_func_ws) { debug("Unsupported hash algorithm\n"); return -1; } diff --git a/common/hash.c b/common/hash.c index 5cbb4926c1d..8bbf9aa4825 100644 --- a/common/hash.c +++ b/common/hash.c @@ -38,6 +38,14 @@ #include <u-boot/md5.h> #include <u-boot/sm3.h> +#ifdef USE_HOSTCC +#define SHA256_SOFTWARE_ENABLED 1 +#else +#define SHA256_SOFTWARE_ENABLED \ + (CONFIG_IS_ENABLED(SHA256_LEGACY) || \ + CONFIG_IS_ENABLED(SHA256_MBEDTLS)) +#endif + static int __maybe_unused hash_init_sha1(struct hash_algo *algo, void **ctxp) { sha1_context *ctx = malloc(sizeof(sha1_context)); @@ -65,6 +73,7 @@ static int __maybe_unused hash_finish_sha1(struct hash_algo *algo, void *ctx, return 0; } +#if SHA256_SOFTWARE_ENABLED static int __maybe_unused hash_init_sha256(struct hash_algo *algo, void **ctxp) { sha256_context *ctx = malloc(sizeof(sha256_context)); @@ -91,6 +100,7 @@ static int __maybe_unused hash_finish_sha256(struct hash_algo *algo, void *ctx, free(ctx); return 0; } +#endif static int __maybe_unused hash_init_sha384(struct hash_algo *algo, void **ctxp) { @@ -273,14 +283,14 @@ static struct hash_algo hash_algo[] = { .chunk_size = CHUNKSZ_SHA256, #if CONFIG_IS_ENABLED(SHA_HW_ACCEL) .hash_func_ws = hw_sha256, -#else +#elif SHA256_SOFTWARE_ENABLED .hash_func_ws = sha256_csum_wd, #endif #if CONFIG_IS_ENABLED(SHA_PROG_HW_ACCEL) .hash_init = hw_sha_init, .hash_update = hw_sha_update, .hash_finish = hw_sha_finish, -#else +#elif SHA256_SOFTWARE_ENABLED .hash_init = hash_init_sha256, .hash_update = hash_update_sha256, .hash_finish = hash_finish_sha256, @@ -634,6 +644,13 @@ int hash_command(const char *algo_name, int flags, struct cmd_tbl *cmdtp, goto done; } } + if (!algo->hash_func_ws) { + printf("Hash algorithm '%s' has no available provider\n", + algo_name); + unmap_sysmem(buf); + free(output); + return CMD_RET_FAILURE; + } algo->hash_func_ws(buf, len, output, algo->chunk_size); done: unmap_sysmem(buf); diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig index 79f46317e45..1d9542f815d 100644 --- a/configs/sandbox_defconfig +++ b/configs/sandbox_defconfig @@ -198,6 +198,7 @@ CONFIG_CLK_K210_SET_RATE=y CONFIG_SANDBOX_CLK_CCF=y CONFIG_CLK_SCMI=y CONFIG_CPU=y +CONFIG_DM_HASH=y CONFIG_DM_AES=y CONFIG_AES_SOFTWARE=y CONFIG_DM_DEMO=y diff --git a/drivers/crypto/aspeed/aspeed_hace.c b/drivers/crypto/aspeed/aspeed_hace.c index 2469f53472f..3be1809c89e 100644 --- a/drivers/crypto/aspeed/aspeed_hace.c +++ b/drivers/crypto/aspeed/aspeed_hace.c @@ -205,6 +205,13 @@ static int aspeed_hace_update(struct udevice *dev, void *ctx, const void *ibuf, return 0; } +static int aspeed_hace_abort(struct udevice *dev, void *ctx) +{ + free(ctx); + + return 0; +} + static int aspeed_hace_finish(struct udevice *dev, void *ctx, void *obuf) { int rc = 0; @@ -269,7 +276,7 @@ static int aspeed_hace_finish(struct udevice *dev, void *ctx, void *obuf) memcpy(obuf, hace_ctx->digest, hash_algo_digest_size(hace_ctx->algo)); free_n_out: - free(ctx); + aspeed_hace_abort(dev, ctx); return rc; } @@ -297,16 +304,20 @@ static int aspeed_hace_digest_wd(struct udevice *dev, enum HASH_ALGO algo, chunk = chunk_sz; rc = aspeed_hace_update(dev, ctx, cur, chunk); - if (rc) + if (rc) { + aspeed_hace_abort(dev, ctx); return rc; + } cur += chunk; schedule(); } } else { rc = aspeed_hace_update(dev, ctx, ibuf, ilen); - if (rc) + if (rc) { + aspeed_hace_abort(dev, ctx); return rc; + } } rc = aspeed_hace_finish(dev, ctx, obuf); @@ -359,6 +370,7 @@ static const struct hash_ops aspeed_hace_ops = { .hash_init = aspeed_hace_init, .hash_update = aspeed_hace_update, .hash_finish = aspeed_hace_finish, + .hash_abort = aspeed_hace_abort, .hash_digest_wd = aspeed_hace_digest_wd, .hash_digest = aspeed_hace_digest, }; diff --git a/drivers/crypto/aspeed/cptra_sha.c b/drivers/crypto/aspeed/cptra_sha.c index 0dc00f306f1..72ea3860eb5 100644 --- a/drivers/crypto/aspeed/cptra_sha.c +++ b/drivers/crypto/aspeed/cptra_sha.c @@ -75,8 +75,11 @@ static int cptra_sha_init(struct udevice *dev, enum HASH_ALGO algo, void **ctxp) cs = dev_get_priv(dev); /* get CPTRA SHA lock */ - if (readl_poll_timeout(cs->regs + CPTRA_SHA_LOCK, reg, reg == 0, 1000000)) - return -EBUSY; + if (readl_poll_timeout(cs->regs + CPTRA_SHA_LOCK, reg, reg == 0, + 1000000)) { + rc = -EBUSY; + goto free_n_out; + } /* zero clear SHA */ writel(CPTRA_SHA_CTRL_ZEROIZE, cs->regs + CPTRA_SHA_CTRL); @@ -133,6 +136,17 @@ static int cptra_sha_update(struct udevice *dev, void *ctx, const void *ibuf, ui return 0; } +static int cptra_sha_abort(struct udevice *dev, void *ctx) +{ + struct cptra_sha *cs = dev_get_priv(dev); + + writel(CPTRA_SHA_CTRL_ZEROIZE, cs->regs + CPTRA_SHA_CTRL); + writel(0x1, cs->regs + CPTRA_SHA_LOCK); + free(ctx); + + return 0; +} + static int cptra_sha_finish(struct udevice *dev, void *ctx, void *obuf) { struct cptra_sha_ctx *cs_ctx; @@ -158,12 +172,7 @@ static int cptra_sha_finish(struct udevice *dev, void *ctx, void *obuf) for (i = 0; i < (cs_ctx->dgst_len / sizeof(*p32)); ++i, p32++) *p32 = be32_to_cpu(readl(cs->regs + CPTRA_SHA_DIGEST(i))); - /* release CPTRA SHA lock */ - writel(0x1, cs->regs + CPTRA_SHA_LOCK); - - free(cs_ctx); - - return 0; + return cptra_sha_abort(dev, ctx); } static int cptra_sha_digest_wd(struct udevice *dev, enum HASH_ALGO algo, @@ -189,16 +198,20 @@ static int cptra_sha_digest_wd(struct udevice *dev, enum HASH_ALGO algo, chunk = chunk_sz; rc = cptra_sha_update(dev, ctx, cur, chunk); - if (rc) + if (rc) { + cptra_sha_abort(dev, ctx); return rc; + } cur += chunk; schedule(); } } else { rc = cptra_sha_update(dev, ctx, ibuf, ilen); - if (rc) + if (rc) { + cptra_sha_abort(dev, ctx); return rc; + } } rc = cptra_sha_finish(dev, ctx, obuf); @@ -237,6 +250,7 @@ static const struct hash_ops cptra_sha_ops = { .hash_init = cptra_sha_init, .hash_update = cptra_sha_update, .hash_finish = cptra_sha_finish, + .hash_abort = cptra_sha_abort, .hash_digest_wd = cptra_sha_digest_wd, .hash_digest = cptra_sha_digest, }; diff --git a/drivers/crypto/hash/hash-uclass.c b/drivers/crypto/hash/hash-uclass.c index ffca19af2de..0340eecf3f6 100644 --- a/drivers/crypto/hash/hash-uclass.c +++ b/drivers/crypto/hash/hash-uclass.c @@ -119,11 +119,43 @@ int hash_digest_wd_lookup(enum HASH_ALGO algo, const void *ibuf, return found ? -EOPNOTSUPP : -ENODEV; } +int hash_init_lookup(enum HASH_ALGO algo, struct udevice **devp, void **ctxp) +{ + struct udevice *dev; + int first_probe_err = 0; + bool found = false; + int ret; + + for (ret = uclass_first_device_check(UCLASS_HASH, &dev); dev; + ret = uclass_next_device_check(&dev)) { + found = true; + if (ret) { + if (!first_probe_err) + first_probe_err = ret; + continue; + } + + ret = hash_init(dev, algo, ctxp); + if (!ret) { + *devp = dev; + return 0; + } + if (!hash_op_unsupported(ret)) + return ret; + } + + if (first_probe_err) + return first_probe_err; + + return found ? -EOPNOTSUPP : -ENODEV; +} + int hash_init(struct udevice *dev, enum HASH_ALGO algo, void **ctxp) { struct hash_ops *ops = (struct hash_ops *)device_get_ops(dev); - if (!ops->hash_init) + if (!ops->hash_init || !ops->hash_update || !ops->hash_finish || + !ops->hash_abort) return -ENOSYS; return ops->hash_init(dev, algo, ctxp); @@ -149,6 +181,16 @@ int hash_finish(struct udevice *dev, void *ctx, void *obuf) return ops->hash_finish(dev, ctx, obuf); } +int hash_abort(struct udevice *dev, void *ctx) +{ + struct hash_ops *ops = (struct hash_ops *)device_get_ops(dev); + + if (!ops->hash_abort) + return -ENOSYS; + + return ops->hash_abort(dev, ctx); +} + UCLASS_DRIVER(hash) = { .id = UCLASS_HASH, .name = "hash", diff --git a/drivers/crypto/hash/hash_sw.c b/drivers/crypto/hash/hash_sw.c index 4590e225481..63a775d904f 100644 --- a/drivers/crypto/hash/hash_sw.c +++ b/drivers/crypto/hash/hash_sw.c @@ -218,6 +218,13 @@ static int sw_hash_update(struct udevice *dev, void *ctx, const void *ibuf, uint return 0; } +static int sw_hash_abort(struct udevice *dev, void *ctx) +{ + free(ctx); + + return 0; +} + static int sw_hash_finish(struct udevice *dev, void *ctx, void *obuf) { struct sw_hash_ctx *hash_ctx = ctx; @@ -225,9 +232,7 @@ static int sw_hash_finish(struct udevice *dev, void *ctx, void *obuf) hash_impl->finish(hash_ctx->algo_ctx, obuf); - free(ctx); - - return 0; + return sw_hash_abort(dev, ctx); } static int sw_hash_digest_wd(struct udevice *dev, enum HASH_ALGO algo, @@ -253,16 +258,20 @@ static int sw_hash_digest_wd(struct udevice *dev, enum HASH_ALGO algo, chunk = chunk_sz; rc = sw_hash_update(dev, ctx, cur, chunk); - if (rc) + if (rc) { + sw_hash_abort(dev, ctx); return rc; + } cur += chunk; schedule(); } } else { rc = sw_hash_update(dev, ctx, ibuf, ilen); - if (rc) + if (rc) { + sw_hash_abort(dev, ctx); return rc; + } } rc = sw_hash_finish(dev, ctx, obuf); @@ -284,6 +293,7 @@ static const struct hash_ops hash_ops_sw = { .hash_init = sw_hash_init, .hash_update = sw_hash_update, .hash_finish = sw_hash_finish, + .hash_abort = sw_hash_abort, .hash_digest_wd = sw_hash_digest_wd, .hash_digest = sw_hash_digest, }; diff --git a/include/u-boot/hash.h b/include/u-boot/hash.h index 7dba66047f5..f07363845e3 100644 --- a/include/u-boot/hash.h +++ b/include/u-boot/hash.h @@ -51,10 +51,39 @@ int hash_digest_wd(struct udevice *dev, enum HASH_ALGO algo, */ int hash_digest_wd_lookup(enum HASH_ALGO algo, const void *ibuf, const u32 ilen, void *obuf, u32 chunk_sz); +/** + * hash_init_lookup() - Start hashing with the first supporting provider + * + * Probe each hash device in order and initialize the first one which supports + * @algo. The selected device is returned for the matching update and finish + * operations. + * + * @algo: Hash algorithm + * @devp: Returns the selected hash device + * @ctxp: Returns the provider's progressive-hash context + * Return: 0 on success, -ENODEV if there are no providers, -EOPNOTSUPP if no + * provider supports @algo, or another negative error from a provider + */ +int hash_init_lookup(enum HASH_ALGO algo, struct udevice **devp, void **ctxp); + +/* + * A successful hash_init() returns a context which must be consumed by + * exactly one hash_finish() or hash_abort() call. Both operations release all + * provider resources, including when they return an error. + */ int hash_init(struct udevice *dev, enum HASH_ALGO algo, void **ctxp); int hash_update(struct udevice *dev, void *ctx, const void *ibuf, const uint32_t ilen); int hash_finish(struct udevice *dev, void *ctx, void *obuf); +/** + * hash_abort() - Discard a progressive hash operation + * + * @dev: Hash device selected by hash_init() or hash_init_lookup() + * @ctx: Progressive-hash context to release + * Return: 0 on success, or a negative provider error + */ +int hash_abort(struct udevice *dev, void *ctx); + /* * struct hash_ops - Driver model for Hash operations * @@ -66,6 +95,7 @@ struct hash_ops { int (*hash_init)(struct udevice *dev, enum HASH_ALGO algo, void **ctxp); int (*hash_update)(struct udevice *dev, void *ctx, const void *ibuf, const uint32_t ilen); int (*hash_finish)(struct udevice *dev, void *ctx, void *obuf); + int (*hash_abort)(struct udevice *dev, void *ctx); /* all-in-one operation */ int (*hash_digest)(struct udevice *dev, enum HASH_ALGO algo, diff --git a/lib/Makefile b/lib/Makefile index 222378a8531..777c48a5728 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -79,8 +79,8 @@ obj-$(CONFIG_BLAKE2) += blake2/blake2b.o obj-$(CONFIG_$(PHASE_)MD5_LEGACY) += md5.o obj-$(CONFIG_$(PHASE_)SHA1_LEGACY) += sha1.o -obj-$(CONFIG_$(PHASE_)SHA256) += sha256_common.o -obj-$(CONFIG_$(PHASE_)SHA256_LEGACY) += sha256.o +obj-$(CONFIG_$(PHASE_)SHA256_LEGACY) += sha256_common.o sha256.o +obj-$(CONFIG_$(PHASE_)SHA256_MBEDTLS) += sha256_common.o obj-$(CONFIG_$(PHASE_)SHA512_LEGACY) += sha512.o obj-$(CONFIG_$(PHASE_)SM3) += sm3.o diff --git a/lib/hash-checksum.c b/lib/hash-checksum.c index 1970a741294..e3e7f6adb7f 100644 --- a/lib/hash-checksum.c +++ b/lib/hash-checksum.c @@ -4,11 +4,13 @@ */ #ifndef USE_HOSTCC +#include <dm.h> #include <fdtdec.h> #include <asm/byteorder.h> #include <linux/errno.h> #include <asm/unaligned.h> #include <hash.h> +#include <u-boot/hash.h> #else #include "fdt_host.h" #endif @@ -20,13 +22,39 @@ int hash_calculate(const char *name, int region_count, uint8_t *checksum) { struct hash_algo *algo; - int ret = 0; + int ret; void *ctx; int i; if (region_count < 1) return -EINVAL; +#ifndef USE_HOSTCC + if (CONFIG_IS_ENABLED(DM_HASH)) { + enum HASH_ALGO hash_algo = hash_algo_lookup_by_name(name); + struct udevice *dev; + + if (hash_algo != HASH_ALGO_INVALID) + ret = hash_init_lookup(hash_algo, &dev, &ctx); + else + ret = -EOPNOTSUPP; + if (!ret) { + for (i = 0; i < region_count; i++) { + ret = hash_update(dev, ctx, region[i].data, + region[i].size); + if (ret) { + hash_abort(dev, ctx); + return ret; + } + } + + return hash_finish(dev, ctx, checksum); + } + if (ret != -ENODEV && ret != -EOPNOTSUPP) + return ret; + } +#endif + ret = hash_progressive_lookup_algo(name, &algo); if (ret) return ret; diff --git a/lib/mbedtls/Kconfig b/lib/mbedtls/Kconfig index 789721ee6cd..a805b1d4a48 100644 --- a/lib/mbedtls/Kconfig +++ b/lib/mbedtls/Kconfig @@ -335,7 +335,7 @@ config SPL_LEGACY_HASHING bool "Use U-Boot legacy hashing libraries (SPL)" select SPL_MD5_LEGACY if SPL_MD5 select SPL_SHA1_LEGACY if SPL_SHA1 - select SPL_SHA256_LEGACY if SPL_SHA256 + imply SPL_SHA256_LEGACY if SPL_SHA256 select SPL_SHA512_LEGACY if SPL_SHA512 select SPL_SHA384_LEGACY if SPL_SHA384 help diff --git a/test/dm/hash.c b/test/dm/hash.c index fe949e33de5..b5ab80d0525 100644 --- a/test/dm/hash.c +++ b/test/dm/hash.c @@ -10,13 +10,83 @@ #include <dm/root.h> #include <dm/test.h> #include <dm/uclass-internal.h> +#include <image.h> #include <u-boot/hash.h> +#include <u-boot/hash-checksum.h> #include <test/test.h> #include <test/ut.h> static int unsupported_calls; static int success_calls; static int hard_error_calls; +static int unsupported_init_calls; +static int success_init_calls; +static int hard_error_init_calls; +static int update_error_calls; +static int finish_calls; +static int abort_calls; + +static int hash_test_unsupported_init(struct udevice *dev, + enum HASH_ALGO algo, void **ctxp) +{ + unsupported_init_calls++; + + return -EOPNOTSUPP; +} + +static int hash_test_success_init(struct udevice *dev, enum HASH_ALGO algo, + void **ctxp) +{ + success_init_calls++; + *ctxp = dev; + + return 0; +} + +static int hash_test_hard_error_init(struct udevice *dev, + enum HASH_ALGO algo, void **ctxp) +{ + hard_error_init_calls++; + + return -EINVAL; +} + +static int hash_test_update_error_init(struct udevice *dev, + enum HASH_ALGO algo, void **ctxp) +{ + *ctxp = dev; + + return 0; +} + +static int hash_test_progressive_update(struct udevice *dev, void *ctx, + const void *ibuf, u32 ilen) +{ + return 0; +} + +static int hash_test_update_error(struct udevice *dev, void *ctx, + const void *ibuf, u32 ilen) +{ + update_error_calls++; + + return -EIO; +} + +static int hash_test_progressive_finish(struct udevice *dev, void *ctx, + void *obuf) +{ + finish_calls++; + + return 0; +} + +static int hash_test_progressive_abort(struct udevice *dev, void *ctx) +{ + abort_calls++; + + return 0; +} static int hash_test_unsupported(struct udevice *dev, enum HASH_ALGO algo, const void *ibuf, const uint32_t ilen, @@ -47,17 +117,36 @@ static int hash_test_hard_error(struct udevice *dev, enum HASH_ALGO algo, } static const struct hash_ops hash_test_unsupported_ops = { + .hash_init = hash_test_unsupported_init, + .hash_update = hash_test_progressive_update, + .hash_finish = hash_test_progressive_finish, + .hash_abort = hash_test_progressive_abort, .hash_digest_wd = hash_test_unsupported, }; static const struct hash_ops hash_test_success_ops = { + .hash_init = hash_test_success_init, + .hash_update = hash_test_progressive_update, + .hash_finish = hash_test_progressive_finish, + .hash_abort = hash_test_progressive_abort, .hash_digest_wd = hash_test_success, }; static const struct hash_ops hash_test_hard_error_ops = { + .hash_init = hash_test_hard_error_init, + .hash_update = hash_test_progressive_update, + .hash_finish = hash_test_progressive_finish, + .hash_abort = hash_test_progressive_abort, .hash_digest_wd = hash_test_hard_error, }; +static const struct hash_ops hash_test_update_error_ops = { + .hash_init = hash_test_update_error_init, + .hash_update = hash_test_update_error, + .hash_finish = hash_test_progressive_finish, + .hash_abort = hash_test_progressive_abort, +}; + U_BOOT_DRIVER(hash_test_unsupported_drv) = { .name = "hash_test_unsupported", .id = UCLASS_HASH, @@ -76,6 +165,12 @@ U_BOOT_DRIVER(hash_test_hard_error_drv) = { .ops = &hash_test_hard_error_ops, }; +U_BOOT_DRIVER(hash_test_update_error_drv) = { + .name = "hash_test_update_error", + .id = UCLASS_HASH, + .ops = &hash_test_update_error_ops, +}; + static int hash_test_unbind_all(void) { struct udevice *dev; @@ -105,7 +200,13 @@ static int hash_test_bind(const struct driver *drv, const char *name) static int dm_test_hash_provider_selection(struct unit_test_state *uts) { + const struct image_region region = { + .data = "test", + .size = 4, + }; + struct udevice *dev; u8 digest[32]; + void *ctx; int ret; ut_assertok(hash_test_unbind_all()); @@ -124,6 +225,18 @@ static int dm_test_hash_provider_selection(struct unit_test_state *uts) for (int i = 0; i < sizeof(digest); i++) ut_asserteq(0x5a, digest[i]); + unsupported_init_calls = 0; + success_init_calls = 0; + ret = hash_init_lookup(HASH_ALGO_SHA256, &dev, &ctx); + ut_assertok(ret); + ut_asserteq(1, unsupported_init_calls); + ut_asserteq(1, success_init_calls); + ut_asserteq_str("hash-success", dev->name); + ut_asserteq_ptr(dev, ctx); + abort_calls = 0; + ut_assertok(hash_abort(dev, ctx)); + ut_asserteq(1, abort_calls); + ut_assertok(hash_test_unbind_all()); ut_assertok(hash_test_bind(DM_DRIVER_GET(hash_test_hard_error_drv), "hash-hard-error")); @@ -137,6 +250,25 @@ static int dm_test_hash_provider_selection(struct unit_test_state *uts) ut_asserteq(1, hard_error_calls); ut_asserteq(0, success_calls); + hard_error_init_calls = 0; + success_init_calls = 0; + ret = hash_init_lookup(HASH_ALGO_SHA256, &dev, &ctx); + ut_asserteq(-EINVAL, ret); + ut_asserteq(1, hard_error_init_calls); + ut_asserteq(0, success_init_calls); + + ut_assertok(hash_test_unbind_all()); + ut_assertok(hash_test_bind(DM_DRIVER_GET(hash_test_update_error_drv), + "hash-update-error")); + update_error_calls = 0; + finish_calls = 0; + abort_calls = 0; + ret = hash_calculate("sha256", ®ion, 1, digest); + ut_asserteq(-EIO, ret); + ut_asserteq(1, update_error_calls); + ut_asserteq(0, finish_calls); + ut_asserteq(1, abort_calls); + return 0; } -- 2.53.0