From 4cedb7126acb2f0cbcfd47d93ebbbdaa162ca2dc Mon Sep 17 00:00:00 2001 From: David Garske Date: Mon, 26 Oct 2026 11:47:39 -0700 Subject: [PATCH] PolarFire SoC: drive the Athena F5200 through the wolfCrypt port --- hal/mpfs250.c | 586 ++++---------------------------------------------- options.mk | 50 +++-- 2 files changed, 76 insertions(+), 560 deletions(-) diff --git a/hal/mpfs250.c b/hal/mpfs250.c index 3789c9d9..4a26432e 100644 --- a/hal/mpfs250.c +++ b/hal/mpfs250.c @@ -49,22 +49,11 @@ #endif #ifdef MPFS_ATHENA -#include -/* Microchip's CAL headers for the Athena F5200, referenced not vendored (they - * carry a Mercury Systems notice); MPFS_ATHENA_CAL_DIR puts them on the path. */ -#ifndef CALCONFIGH /* the HSS calpolicy.h defines both */ -#define CALCONFIGH "config_user.h" -#endif -#ifndef INC_STDINT_H -#define INC_STDINT_H /* make caltypes.h use */ -#endif -/* caltypes.h and wolfSSL's types.h both define a uint128_t, a union of words - * there and __uint128_t here; nothing below needs CAL's. */ -#define uint128_t cal_uint128_t -#include "calini.h" -#include "hash.h" -#include "sym.h" -#undef uint128_t +/* CAL is reached only through the wolfCrypt port, so none of Microchip's + * headers are included here and the uint128_t clash between caltypes.h and + * wolfSSL's types.h stays inside that one translation unit. */ +#include +#include #endif #if defined(DISK_SDCARD) || defined(DISK_EMMC) @@ -330,547 +319,52 @@ static void qspi_uart_program(void); #endif #ifdef MPFS_ATHENA -/* Ungate and release the Athena F5200 (per HSS opensbi_crypto_ecall.c). - * Idempotent: ATHENA_CR_RESET after CALIni() kills AES, not hashing. */ -static void mpfs_athena_enable(void) -{ - static int athena_enabled; - uint64_t cyc; - - if (athena_enabled) { - return; - } - - SYSREG_SUBBLK_CLOCK_CR |= MSS_PERIPH_ATHENA; - SYSREG_SOFT_RESET_CR &= ~MSS_PERIPH_ATHENA; - __asm__ volatile("rdcycle %0" : "=r"(cyc)); - ATHENA_STALL_CR = (uint32_t)(cyc ^ (cyc >> 32)); - ATHENA_CR = ATHENA_CR_RESET | ATHENA_CR_RINGOSCON; - ATHENA_CR = ATHENA_CR_RINGOSCON | ATHENA_CR_STALL_EN; - athena_enabled = 1; -} - -/* CAL finds the engine through this global: the User Crypto base in the Libero - * design. The HSS build has it compiled in and ignores this symbol. */ -uint32_t g_user_crypto_base_addr = 0x22000000UL; - -/* Hash context handed to CAL; sized for SATRESCONTEXT and checked below so a - * CAL update cannot silently overflow it. */ -#define MPFS_ATHENA_CTX_SIZE 256 -typedef char athena_ctx_size_check[ - (MPFS_ATHENA_CTX_SIZE >= (int)sizeof(SATRESCONTEXT)) ? 1 : -1]; - -static int mpfs_athena_engine_init(void) -{ - /* CALIni() must follow the un-reset, and the core must not be reset after - * it: that silently kills AES (writes nothing, returns success). */ - mpfs_athena_enable(); - if (CALIni() != SATR_SUCCESS) { - return -1; - } - return 0; -} - -/* CAL status of the last call that failed, reported by the self-check. */ -static int athena_last_cal_rc; - -static int mpfs_athena_sha384_init(void *ctx) -{ - SATR rc = CALHashCtxIni((SATRESCONTEXTPTR)ctx, SATHASHTYPE_SHA384); - - if (rc != SATR_SUCCESS) { - athena_last_cal_rc = (int)rc; - return -1; - } - return 0; -} - -/* len must be a whole number of blocks; a partial non-final chunk is rejected - * by the engine with SATR_BADHASHLEN. */ -static int mpfs_athena_sha384_update(void *ctx, const void *in, uint32_t len) -{ - SATR rc = CALHashCtx((SATRESHANDLE)0, (SATRESCONTEXTPTR)ctx, in, - (SATUINT32_t)len, NULL, SAT_FALSE); - - if (rc != SATR_SUCCESS) { - athena_last_cal_rc = (int)rc; - return -1; - } - return 0; -} - -/* The final call may carry any remaining length, including zero. */ -static int mpfs_athena_sha384_final(void *ctx, const void *in, uint32_t len, - void *digest) -{ - SATR rc = CALHashCtx((SATRESHANDLE)0, (SATRESCONTEXTPTR)ctx, in, - (SATUINT32_t)len, digest, SAT_TRUE); - - if (rc != SATR_SUCCESS) { - athena_last_cal_rc = (int)rc; - return -1; - } - return 0; -} - -#ifdef MPFS_ATHENA_AES -/* AES-256-CTR. CTR is symmetric, so this serves encrypt and decrypt alike. - * iv is advanced in place by the engine, so a caller may chain calls. */ -static int mpfs_athena_aes256_ctr(const void *key, void *iv, const void *in, - void *out, uint32_t len) -{ - if (CALSymEncrypt(SATSYMTYPE_AES256, (const SATUINT32_t *)key, - SATSYMMODE_CTR, iv, SAT_TRUE, in, out, (SATUINT32_t)len) - != SATR_SUCCESS) { - return -1; - } - /* CALSymEncrypt only starts the transfer. Without this wait the output - * buffer is never written while both calls still report SATR_SUCCESS. */ - if (CALSymTrfRes(SAT_TRUE) != SATR_SUCCESS) { - return -1; - } - return 0; -} -#endif /* MPFS_ATHENA_AES */ -#endif /* MPFS_ATHENA */ - -#ifdef MPFS_ATHENA -/* SHA-384 + AES-256-CTR via the plain-C mpfs_athena_* API. CAL contract: a - * non-final update must be whole 128-byte blocks, so tails are buffered. */ -#ifdef MPFS_ATHENA_SHA -#define ATHENA_SHA384_BLOCK 128 -#define ATHENA_HASH_SLOTS 2 - -struct athena_hash_slot { - void *owner; /* wc_Sha384* that owns this slot */ - uint8_t ctx[MPFS_ATHENA_CTX_SIZE]; /* opaque CAL hash context */ - uint8_t part[ATHENA_SHA384_BLOCK]; /* partial block awaiting more data */ - uint32_t part_len; - uint8_t failed; /* an update faulted: no digest from - * this context can be trusted */ -}; - -static struct athena_hash_slot athena_hash_slots[ATHENA_HASH_SLOTS]; -#endif /* MPFS_ATHENA_SHA */ - -/* Set once the self-check has passed: from then on a SHA-384 request the - * engine cannot take is a hardware error, never a silent software fallback. */ -static int athena_ready; - -/* Counts callback entries actually serviced by the engine, so a correct - * digest cannot be mistaken for hardware use when the callback never ran. */ -static uint32_t athena_cb_calls; - -#ifdef MPFS_ATHENA_SHA -/* Keyed by wc_Sha384 address. The cryptocb has no free event, so a context - * freed without Final strands its slot and a later one there resumes it. */ -static struct athena_hash_slot *athena_slot_find(void *owner) -{ - int i; - - for (i = 0; i < ATHENA_HASH_SLOTS; i++) { - if (athena_hash_slots[i].owner == owner) { - return &athena_hash_slots[i]; - } - } - return NULL; -} - -/* Feed whole blocks from the slot buffer plus the caller's data. Anything - * short of a block is retained for the next call or the final. */ -static int athena_hash_feed(struct athena_hash_slot *slot, const uint8_t *in, - uint32_t len) -{ - uint32_t take; - - if (slot->part_len > 0) { - take = ATHENA_SHA384_BLOCK - slot->part_len; - if (take > len) { - take = len; - } - memcpy(&slot->part[slot->part_len], in, take); - slot->part_len += take; - in += take; - len -= take; - if (slot->part_len < ATHENA_SHA384_BLOCK) { - return 0; /* still short of a block */ - } - if (mpfs_athena_sha384_update(slot->ctx, slot->part, - ATHENA_SHA384_BLOCK) != 0) { - return -1; - } - slot->part_len = 0; - } - - take = len - (len % ATHENA_SHA384_BLOCK); - if (take > 0) { - if (mpfs_athena_sha384_update(slot->ctx, in, take) != 0) { - return -1; - } - in += take; - len -= take; - } - - if (len > 0) { - memcpy(slot->part, in, len); - slot->part_len = len; - } - return 0; -} -#endif /* MPFS_ATHENA_SHA */ - -#if defined(MPFS_ATHENA_AES) && defined(WOLFSSL_AES_COUNTER) && !defined(NO_AES) -/* AES-256-CTR, one path for both directions. Key from aes->devKey, not the - * SETKEY hook: succeeding there strands the software fallback. */ -static int athena_aesctr(wc_CryptoInfo *info) -{ - Aes *aes; - word32 sz; - word32 whole; - - if (info->cipher.type != WC_CIPHER_AES_CTR) { - return CRYPTOCB_UNAVAILABLE; - } - aes = info->cipher.aesctr.aes; - if (aes == NULL) { - return CRYPTOCB_UNAVAILABLE; - } - /* AES-256 only; the engine supports 128/192 but wolfBoot's encrypted - * images are AES-256 and an untested path is worse than none. */ - if (aes->keylen != 32) { - return CRYPTOCB_UNAVAILABLE; - } - /* aes->left != 0 means wolfCrypt holds keystream from a previous partial - * block; picking up mid-keystream would desync the counter. */ - if (aes->left != 0) { - return CRYPTOCB_UNAVAILABLE; - } - sz = info->cipher.aesctr.sz; - if (sz == 0) { - return 0; - } - - /* The engine advances the counter in place, so aes->reg stays correct for - * any subsequent call on the same context. */ - whole = sz - (sz % WC_AES_BLOCK_SIZE); - if (whole > 0) { - if (mpfs_athena_aes256_ctr(aes->devKey, aes->reg, - info->cipher.aesctr.in, info->cipher.aesctr.out, - whole) != 0) { - return WC_HW_E; - } - } - if (whole < sz) { - /* Trailing partial block: leave the unused keystream where wolfCrypt - * keeps its own (aes->tmp, aes->left) so either path can continue. */ - uint8_t ks[WC_AES_BLOCK_SIZE]; - word32 i; - - memset(ks, 0, sizeof(ks)); - if (mpfs_athena_aes256_ctr(aes->devKey, aes->reg, ks, ks, - WC_AES_BLOCK_SIZE) != 0) { - return WC_HW_E; - } - for (i = whole; i < sz; i++) { - info->cipher.aesctr.out[i] = info->cipher.aesctr.in[i] ^ - ks[i - whole]; - } - memcpy(aes->tmp, ks, WC_AES_BLOCK_SIZE); - aes->left = WC_AES_BLOCK_SIZE - (sz - whole); - memset(ks, 0, sizeof(ks)); - } - athena_cb_calls++; - return 0; -} -#endif /* MPFS_ATHENA_AES && WOLFSSL_AES_COUNTER && !NO_AES */ - -static int mpfs_athena_cryptocb(int devIdArg, wc_CryptoInfo *info, void *ctx) -{ -#ifdef MPFS_ATHENA_SHA - struct athena_hash_slot *slot; -#endif - - (void)devIdArg; - (void)ctx; - - if (info == NULL) { - return CRYPTOCB_UNAVAILABLE; - } - -#if defined(MPFS_ATHENA_AES) && defined(WOLFSSL_AES_COUNTER) && !defined(NO_AES) - if (info->algo_type == WC_ALGO_TYPE_CIPHER) { - return athena_aesctr(info); - } -#endif - -#ifndef MPFS_ATHENA_SHA - return CRYPTOCB_UNAVAILABLE; -#else - if (info->algo_type != WC_ALGO_TYPE_HASH || - info->hash.type != WC_HASH_TYPE_SHA384) { - return CRYPTOCB_UNAVAILABLE; - } - - slot = athena_slot_find(info->hash.sha384); - if ((slot != NULL) && (info->hash.sha384->devCtx != slot)) { - /* Same address, but a context initialized after the one that held - * the slot was abandoned without a final: start over. */ - slot->owner = NULL; - slot->failed = 0; - slot = NULL; - } - if ((slot != NULL) && (slot->failed != 0)) { - /* An earlier update faulted, so the engine holds a partial digest. - * Starting fresh here would digest only the data after the fault. */ - return WC_HW_E; - } - if (slot == NULL) { - /* First call: the only safe point to decline, since afterwards - * wolfCrypt's own state is incomplete and the digest would be wrong. */ - slot = athena_slot_find(NULL); - if (slot == NULL) { - return athena_ready ? WC_HW_E : CRYPTOCB_UNAVAILABLE; - } - if (mpfs_athena_sha384_init(slot->ctx) != 0) { - return athena_ready ? WC_HW_E : CRYPTOCB_UNAVAILABLE; - } - slot->owner = info->hash.sha384; - info->hash.sha384->devCtx = slot; - slot->part_len = 0; - slot->failed = 0; - } - - if (info->hash.in != NULL && info->hash.inSz > 0) { - if (athena_hash_feed(slot, info->hash.in, info->hash.inSz) != 0) { - slot->failed = 1; - return WC_HW_E; - } - } - - athena_cb_calls++; - - if (info->hash.digest != NULL) { - int ret = mpfs_athena_sha384_final(slot->ctx, slot->part, - slot->part_len, info->hash.digest); - slot->owner = NULL; /* release for reuse */ - slot->part_len = 0; - slot->failed = 0; - if (ret != 0) { - return WC_HW_E; - } - } - - return 0; -#endif /* MPFS_ATHENA_SHA */ -} - -#ifdef MPFS_ATHENA_SHA -/* Known answers for the self-check: SHA-384 of 0x00..0xFF, hashed in chunks - * that straddle the 128-byte block so intermediate state must carry. */ -static const uint8_t athena_kat_sha384_256b[48] = { - 0xff, 0xda, 0xeb, 0xff, 0x65, 0xed, 0x05, 0xcf, - 0x40, 0x0f, 0x02, 0x21, 0xc4, 0xcc, 0xfb, 0x4b, - 0x21, 0x04, 0xfb, 0x6a, 0x51, 0xf8, 0x7e, 0x40, - 0xbe, 0x6c, 0x43, 0x09, 0x38, 0x6b, 0xfd, 0xec, - 0x28, 0x92, 0xe9, 0x17, 0x9b, 0x34, 0x63, 0x23, - 0x31, 0xa5, 0x95, 0x92, 0x73, 0x7d, 0xb5, 0xc5 -}; -#endif /* MPFS_ATHENA_SHA */ -#ifdef MPFS_ATHENA_AES -/* AES-256-CTR of the bytes 0x00..0x1F under key 0x00..0x1F, counter 0x00..0x0F. */ -static const uint8_t athena_kat_aesctr[32] = { - 0x5a, 0x6f, 0x06, 0x54, 0x0c, 0xfe, 0x77, 0x91, - 0xf8, 0x27, 0x5f, 0x36, 0x0e, 0xce, 0xa8, 0x9d, - 0x70, 0xe2, 0x02, 0xc6, 0xd7, 0x90, 0x4e, 0x4a, - 0x4d, 0x0f, 0xe1, 0x4a, 0x6e, 0xf8, 0x3e, 0xd0 -}; -#endif - -/* Run the offload through the callback path once and compare. The callback - * count is part of it: wolfCrypt falls back to software silently. */ -/* What the self-check tripped on, for the panic message. */ -static const char *athena_fail_what; -static int athena_fail_rc; - -#ifdef MPFS_ATHENA_AES -/* One CTR run from a fresh key schedule, split into one or two calls so the - * self-check can prove the counter carries across them. */ -static int athena_ctr_run(const uint8_t *key, const uint8_t *ctr, - const uint8_t *in, uint8_t *out, uint32_t first, uint32_t second) -{ - Aes aes; - int ret; - - ret = wc_AesInit(&aes, NULL, WOLFBOOT_DEVID_CRYPT); - if (ret == 0) { - ret = wc_AesSetKeyDirect(&aes, key, 32, ctr, AES_ENCRYPTION); - } - if (ret == 0) { - ret = wc_AesCtrEncrypt(&aes, out, in, first); - } - if ((ret == 0) && (second > 0u)) { - ret = wc_AesCtrEncrypt(&aes, out + first, in + first, second); - } - wc_AesFree(&aes); - return ret; -} -#endif - -static int mpfs_athena_selfcheck(void) -{ -#ifdef MPFS_ATHENA_SHA - wc_Sha384 sha; - uint8_t digest[48]; -#endif - uint8_t buf[256]; -#ifdef MPFS_ATHENA_AES - uint8_t key[32], ctr[16], out[32], out2[32]; -#endif - int ret; - int i; - - athena_fail_what = NULL; - athena_fail_rc = 0; - athena_last_cal_rc = 0; - - for (i = 0; i < (int)sizeof(buf); i++) { - buf[i] = (uint8_t)i; - } -#ifdef MPFS_ATHENA_SHA - athena_cb_calls = 0; - ret = wc_InitSha384_ex(&sha, NULL, WOLFBOOT_DEVID_HASH); - if (ret != 0) { - athena_fail_what = "SHA-384 init"; - } - if (ret == 0) { - ret = wc_Sha384Update(&sha, buf, 100); - } - if (ret == 0) { - ret = wc_Sha384Update(&sha, &buf[100], 100); - } - if (ret == 0) { - ret = wc_Sha384Update(&sha, &buf[200], 56); - } - if ((ret != 0) && (athena_fail_what == NULL)) { - athena_fail_what = "SHA-384 update"; - } - if (ret == 0) { - ret = wc_Sha384Final(&sha, digest); - if (ret != 0) { - athena_fail_what = "SHA-384 final"; - } - } - wc_Sha384Free(&sha); - if (ret != 0) { - athena_fail_rc = ret; - return -1; - } - if (athena_cb_calls == 0) { - athena_fail_what = "SHA-384 callback never serviced (software fallback)"; - return -1; - } - if (memcmp(digest, athena_kat_sha384_256b, sizeof(digest)) != 0) { - athena_fail_what = "SHA-384 digest mismatch"; - return -1; - } -#else - ret = 0; -#endif /* MPFS_ATHENA_SHA */ - -#ifdef MPFS_ATHENA_AES - for (i = 0; i < 32; i++) { - key[i] = (uint8_t)i; - } - for (i = 0; i < 16; i++) { - ctr[i] = (uint8_t)i; - } - athena_cb_calls = 0; - ret = athena_ctr_run(key, ctr, buf, out, 32, 0); - if (ret != 0) { - athena_fail_what = "AES-256-CTR"; - athena_fail_rc = ret; - return -1; - } - if (athena_cb_calls == 0) { - athena_fail_what = "AES-256-CTR callback never serviced (software " - "fallback)"; - return -1; - } - if (memcmp(out, athena_kat_aesctr, sizeof(out)) != 0) { - athena_fail_what = "AES-256-CTR known-answer mismatch"; - return -1; - } - /* The disk decrypt path calls CTR per chunk, so the counter must carry: - * two 16-byte calls must equal one 32-byte call, ragged splits too. */ - ret = athena_ctr_run(key, ctr, buf, out2, 16, 16); - if (ret == 0) { - if (memcmp(out, out2, sizeof(out)) != 0) { - athena_fail_what = "AES-256-CTR counter does not carry across " - "calls"; - return -1; - } - ret = athena_ctr_run(key, ctr, buf, out2, 20, 12); - } - if (ret != 0) { - athena_fail_what = "AES-256-CTR split run"; - athena_fail_rc = ret; - return -1; - } - if (memcmp(out2, athena_kat_aesctr, sizeof(out2)) != 0) { - athena_fail_what = "AES-256-CTR partial block mismatch"; - return -1; - } -#endif - return 0; -} - -/* A build that asks for the hardware must not fall through to software - * crypto unnoticed: every failure here halts. */ +/* The Athena F5200 is driven by the wolfCrypt port in + * wolfcrypt/src/port/microchip/mpfs_athena.c, which owns the CAL calls, the + * crypto callback and the known-answer tests. A build that asks for the + * hardware must not fall through to software unnoticed: every failure halts. */ static void mpfs_athena_init(void) { -#ifdef MPFS_ATHENA_SHA - int i; + word32 calls; + int ret; - for (i = 0; i < ATHENA_HASH_SLOTS; i++) { - athena_hash_slots[i].owner = NULL; - athena_hash_slots[i].part_len = 0; + /* The port deliberately does not call wc_CryptoCb_Init(), which would + * clear the whole device table. wolfCrypt_Init() does it, and is + * reference counted, so a later caller is harmless. */ + ret = wolfCrypt_Init(); + if (ret != 0) { + wolfBoot_printf("Athena: wolfCrypt_Init failed (%d)\n", ret); + wolfBoot_panic(); } + /* One registration serves both: the callback dispatches on algo_type and + * options.mk gives the hash and the cipher the same devId. MPFS_ATHENA_SHA=0 + * leaves the hash devId invalid, so image hashing stays in software. */ +#if defined(MPFS_ATHENA_SHA) && (WOLFBOOT_DEVID_HASH != WOLFBOOT_DEVID_CRYPT) +#error "the Athena port registers one devId: keep DEVID_HASH and DEVID_CRYPT equal" #endif - - /* Free slots hold INVALID_DEVID (-2), not 0, so registration returns - * BUFFER_E until the zero-initialised device table is initialised. */ - wc_CryptoCb_Init(); - - if (mpfs_athena_engine_init() != 0) { - wolfBoot_printf("Athena: engine init failed\n"); + ret = wc_MpfsAthena_RegisterDevice(WOLFBOOT_DEVID_CRYPT); + if (ret != 0) { + wolfBoot_printf("Athena: RegisterDevice failed (%d)\n", ret); wolfBoot_panic(); } - if (wc_CryptoCb_RegisterDevice(WOLFBOOT_DEVID_HASH, mpfs_athena_cryptocb, - NULL) != 0) { - wolfBoot_printf("Athena: RegisterDevice failed\n"); + ret = wc_MpfsAthena_SelfTest(); + if (ret != 0) { + wolfBoot_printf("Athena: self-test failed: %s (rc %d)\n", + wc_MpfsAthena_SelfTestDesc(), ret); wolfBoot_panic(); } -#if defined(WOLFBOOT_DEVID_CRYPT) && (WOLFBOOT_DEVID_CRYPT != WOLFBOOT_DEVID_HASH) - if (wc_CryptoCb_RegisterDevice(WOLFBOOT_DEVID_CRYPT, mpfs_athena_cryptocb, - NULL) != 0) { - wolfBoot_printf("Athena: cipher RegisterDevice failed\n"); + /* A correct digest proves nothing on its own: with registration failed + * wolfCrypt computes the right answer in software. The port counts the + * calls the engine actually served, and asserts its own count inside each + * known-answer test it compiles, so zero here means no offload path was + * built and the engine would sit idle behind a reassuring banner. */ + calls = wc_MpfsAthena_GetCbCount(); + if (calls == 0) { + wolfBoot_printf("Athena: self-test served no engine call\n"); wolfBoot_panic(); } -#endif - if (mpfs_athena_selfcheck() != 0) { - wolfBoot_printf("Athena: self-check failed: %s (rc %d, CAL rc %d, " - "callbacks %u)\n", athena_fail_what, athena_fail_rc, - athena_last_cal_rc, (unsigned)athena_cb_calls); - wolfBoot_panic(); - } - athena_ready = 1; -#if defined(MPFS_ATHENA_SHA) && defined(MPFS_ATHENA_AES) - wolfBoot_printf("Athena: SHA-384 + AES-256-CTR offload active\n"); -#elif defined(MPFS_ATHENA_SHA) - wolfBoot_printf("Athena: SHA-384 offload active\n"); -#else - wolfBoot_printf("Athena: AES-256-CTR offload active\n"); -#endif + wolfBoot_printf("Athena: offload active, engine served %u call(s)\n", + (unsigned)calls); } #endif /* MPFS_ATHENA */ diff --git a/options.mk b/options.mk index e8b9123b..b1de7043 100644 --- a/options.mk +++ b/options.mk @@ -1983,19 +1983,44 @@ ifeq ($(MPFS_ATHENA),1) $(error MPFS_ATHENA=1 requires MPFS_ATHENA_CAL_DIR to point at the \ Microchip user-crypto (CAL) directory) endif + # The engine is driven by the wolfCrypt port, so the wolfSSL in use has to + # carry it. Checked here because an older tree -- a stale submodule, or a + # WOLFBOOT_LIB_WOLFSSL override -- otherwise fails as a missing header and a + # pile of undefined wc_MpfsAthena_* symbols. + MPFS_ATHENA_PORT_SRC = \ + $(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/port/microchip/mpfs_athena.c + ifeq ($(wildcard $(MPFS_ATHENA_PORT_SRC)),) + $(error MPFS_ATHENA=1 needs a wolfSSL containing the Athena port at \ + wolfcrypt/src/port/microchip/mpfs_athena.c; update the lib/wolfssl \ + submodule or point WOLFBOOT_LIB_WOLFSSL at a tree that has it) + endif # Both CAL archives are soft-float lp64, so callers must be too (see arch.mk). # M-mode: hart-software-services/services/crypto. S-mode: the rv64imafd # build from polarfire-soc-bare-metal-examples .../middleware/cal. + # The include path is for the wolfCrypt port, which owns the CAL calls, not + # for this HAL. WOLFSSL_MICROCHIP_MPFS selects the SoC family and + # WOLFSSL_MPFS_ATHENA says the part carries the engine; wolfSSL's settings.h + # turns on WOLF_CRYPTO_CB and the COPY/FREE events from the latter, so they + # are not repeated here. Which engines are offloaded follows the ordinary + # WOLFSSL_SHA384 and WOLFSSL_AES_COUNTER gates, so AES-256-CTR comes with an + # AES-256 ENCRYPT build. CFLAGS += -DMPFS_ATHENA -I$(MPFS_ATHENA_CAL_DIR) - CFLAGS += -DWOLF_CRYPTO_CB - CFLAGS += -DWOLFBOOT_DEVID_HASH=0xA7 + CFLAGS += -DWOLFSSL_MICROCHIP_MPFS -DWOLFSSL_MPFS_ATHENA + # Matches the port's own WC_MPFS_ATHENA_DEVID default; wolfBoot tags its + # cipher contexts with this one. CFLAGS += -DWOLFBOOT_DEVID_CRYPT=0xA7 WOLFCRYPT_OBJS += $(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/cryptocb.o + WOLFCRYPT_OBJS += \ + $(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/port/microchip/mpfs_athena.o # SHA-384 offload. Over a whole image in DDR it is slower than the software - # hash, so an encrypted build wanting only the AES win sets MPFS_ATHENA_SHA=0. + # hash, so an encrypted build wanting only the AES win sets MPFS_ATHENA_SHA=0, + # which leaves WOLFBOOT_DEVID_HASH at INVALID_DEVID and image hashing in + # software. The port's self-test still runs its SHA-384 known-answer test + # whenever WOLFSSL_SHA384 is compiled, so the engine's hash path is still + # brought up and checked; the knob moves the image hash, not the self-test. MPFS_ATHENA_SHA ?= 1 ifeq ($(MPFS_ATHENA_SHA),1) - CFLAGS += -DMPFS_ATHENA_SHA + CFLAGS += -DMPFS_ATHENA_SHA -DWOLFBOOT_DEVID_HASH=0xA7 endif # The hash offload and its self-check are SHA-384; an image hashed with # something else keeps that in software and still gets the AES offload. @@ -2007,20 +2032,17 @@ ifeq ($(MPFS_ATHENA),1) # Archive name differs between Microchip's two published builds. MPFS_ATHENA_CAL_LIB ?= mpfs-rv64imac-user-crypto-lib.a LIBS += $(MPFS_ATHENA_CAL_DIR)/$(MPFS_ATHENA_CAL_LIB) - # AES-256-CTR offload rides on the AES-CTR path an AES-256 ENCRYPT build - # compiles; other builds offload the hash only. MPFS_ATHENA_AES=0 opts out. - ifeq ($(ENCRYPT_WITH_AES256),1) - MPFS_ATHENA_AES ?= 1 - ifeq ($(MPFS_ATHENA_AES),1) - CFLAGS += -DMPFS_ATHENA_AES - endif - endif + # AES-256-CTR offload now follows the port's own WOLFSSL_AES_COUNTER gate, so + # it is present exactly when an AES-256 ENCRYPT build compiles that path. # With neither offload selected the engine is brought up and self-checked for # nothing, so say so rather than linking CAL into a build that cannot use it. + # ENCRYPT_WITH_AES256=1 on its own is not enough: WOLFSSL_AES_COUNTER, which + # the port's cipher path is gated on, is only defined under ENCRYPT=1. ifneq ($(MPFS_ATHENA_SHA),1) - ifneq ($(MPFS_ATHENA_AES),1) + ifneq ($(ENCRYPT)$(ENCRYPT_WITH_AES256),11) $(error MPFS_ATHENA=1 with MPFS_ATHENA_SHA=0 and no AES offload leaves \ - nothing offloaded: drop MPFS_ATHENA, or set ENCRYPT_WITH_AES256=1) + nothing offloaded: drop MPFS_ATHENA, or set ENCRYPT=1 \ + ENCRYPT_WITH_AES256=1) endif endif endif