PolarFire SoC: make the Athena hash offload selectable with MPFS_ATHENA_SHA

pull/916/head
David Garske 2026-10-22 07:21:12 -07:00
parent 48ed223ced
commit 682d0b982b
3 changed files with 45 additions and 7 deletions

View File

@ -1203,7 +1203,7 @@ On an encrypted image the decrypt dominates everything else, and the Athena F520
| Integrity SHA-384 | 4.29 s | 5.70 s |
| Verify ECC384 | 0.67 s | 0.67 s |
The AES offload is worth about 4.2x on the decrypt. **The hash offload is about 1.3x slower than software** over an image this size: the engine's per-block setup dominates once the data is in DDR rather than a small buffer in L2 scratch, so enabling it costs boot time rather than saving it. `MPFS_ATHENA=1` turns on the hash offload and `ENCRYPT_WITH_AES256=1` adds the AES offload to it, so an encrypted build that wants only the AES win cannot currently express that.
The AES offload is worth about 4.2x on the decrypt. **The hash offload is about 1.3x slower than software** over an image this size: the engine's per-block setup dominates once the data is in DDR rather than a small buffer in L2 scratch, so enabling it costs boot time rather than saving it. `MPFS_ATHENA_SHA=0` keeps the AES offload and returns hashing to software, which is the fastest arrangement for an encrypted image at 9.5 s; `MPFS_ATHENA` with neither offload selected is refused. Note that hashing in software under `MPFS_ATHENA_SHA=0` is still about 9% slower than a build with no crypto callback at all, because every block enters the callback and is turned away.
Athena also does not fit eNVM alongside the full feature set: with the manifest linked it needs both `GZIP` and `MPFS_SBI_SC_FLASH` dropped. Dropping `GZIP` costs nothing when the FIT's kernel is stored uncompressed.

View File

@ -503,6 +503,7 @@ static int mpfs_athena_aes256_ctr(const void *key, void *iv, const void *in,
/* SHA-384 + AES-256-CTR via the plain-C mpfs_athena_* API (CAL headers cannot
* share a TU with wolfSSL's). Undocumented CAL contract: a non-final update
* must be whole 128-byte blocks, so short tails need the buffer below. */
#ifdef MPFS_ATHENA_SHA
#define ATHENA_SHA384_BLOCK 128
#define ATHENA_HASH_SLOTS 2
@ -516,6 +517,7 @@ struct athena_hash_slot {
};
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. */
@ -525,6 +527,7 @@ static int athena_ready;
* 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 at that address would
* resume stale CAL state (wrong digest). Only reachable via ONESHOT today. */
@ -581,6 +584,7 @@ static int athena_hash_feed(struct athena_hash_slot *slot, const uint8_t *in,
}
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
@ -652,7 +656,9 @@ static int athena_aesctr(wc_CryptoInfo *info)
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;
@ -667,6 +673,9 @@ static int mpfs_athena_cryptocb(int devIdArg, wc_CryptoInfo *info, void *ctx)
}
#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;
@ -724,8 +733,10 @@ static int mpfs_athena_cryptocb(int devIdArg, wc_CryptoInfo *info, void *ctx)
}
return 0;
#endif /* MPFS_ATHENA_SHA */
}
#ifdef MPFS_ATHENA_SHA
/* Known answers for the self-check below. SHA-384 of the bytes 0x00..0xFF:
* a multi-block vector, hashed in chunks that straddle the 128-byte block so
* the intermediate state has to be carried across calls. */
@ -737,6 +748,7 @@ static const uint8_t athena_kat_sha384_256b[48] = {
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] = {
@ -781,9 +793,11 @@ static int athena_ctr_run(const uint8_t *key, const uint8_t *ctr,
static int mpfs_athena_selfcheck(void)
{
#ifdef MPFS_ATHENA_SHA
wc_Sha384 sha;
uint8_t buf[256];
uint8_t digest[48];
#endif
uint8_t buf[256];
#ifdef MPFS_ATHENA_AES
uint8_t key[32], ctr[16], out[32], out2[32];
#endif
@ -797,6 +811,7 @@ static int mpfs_athena_selfcheck(void)
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) {
@ -833,6 +848,9 @@ static int mpfs_athena_selfcheck(void)
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++) {
@ -886,12 +904,14 @@ static int mpfs_athena_selfcheck(void)
* crypto unnoticed: every failure here halts. */
static void mpfs_athena_init(void)
{
#ifdef MPFS_ATHENA_SHA
int i;
for (i = 0; i < ATHENA_HASH_SLOTS; i++) {
athena_hash_slots[i].owner = NULL;
athena_hash_slots[i].part_len = 0;
}
#endif
/* Free slots hold INVALID_DEVID (-2), not 0, so registration returns
* BUFFER_E until the zero-initialised device table is initialised. */
@ -920,10 +940,12 @@ static void mpfs_athena_init(void)
wolfBoot_panic();
}
athena_ready = 1;
#ifdef MPFS_ATHENA_AES
#if defined(MPFS_ATHENA_SHA) && defined(MPFS_ATHENA_AES)
wolfBoot_printf("Athena: SHA-384 + AES-256-CTR offload active\n");
#else
#elif defined(MPFS_ATHENA_SHA)
wolfBoot_printf("Athena: SHA-384 offload active\n");
#else
wolfBoot_printf("Athena: AES-256-CTR offload active\n");
#endif
}
#endif /* MPFS_ATHENA */

View File

@ -1991,10 +1991,18 @@ ifeq ($(MPFS_ATHENA),1)
CFLAGS += -DWOLFBOOT_DEVID_HASH=0xA7
CFLAGS += -DWOLFBOOT_DEVID_CRYPT=0xA7
WOLFCRYPT_OBJS += $(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/cryptocb.o
# The offload and its self-check are SHA-384; an image hashed with
# 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.
MPFS_ATHENA_SHA ?= 1
ifeq ($(MPFS_ATHENA_SHA),1)
CFLAGS += -DMPFS_ATHENA_SHA
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.
ifneq ($(HASH),SHA384)
AUX_HASH_ALGOS+=sha384
ifeq ($(MPFS_ATHENA_SHA),1)
ifneq ($(HASH),SHA384)
AUX_HASH_ALGOS+=sha384
endif
endif
# Archive name differs between Microchip's two published builds.
MPFS_ATHENA_CAL_LIB ?= mpfs-rv64imac-user-crypto-lib.a
@ -2007,6 +2015,14 @@ ifeq ($(MPFS_ATHENA),1)
CFLAGS += -DMPFS_ATHENA_AES
endif
endif
# 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.
ifneq ($(MPFS_ATHENA_SHA),1)
ifneq ($(MPFS_ATHENA_AES),1)
$(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)
endif
endif
endif
# Size of the wolfHSM comm data payload, shared by the client and server blocks