PolarFire SoC: drive the Athena F5200 through the wolfCrypt port

pull/916/head
David Garske 2026-10-26 11:47:39 -07:00
parent ffb65a9a29
commit 4cedb7126a
2 changed files with 76 additions and 560 deletions

View File

@ -49,22 +49,11 @@
#endif
#ifdef MPFS_ATHENA
#include <wolfssl/wolfcrypt/cryptocb.h>
/* 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 <stdint.h> */
#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 <wolfssl/wolfcrypt/wc_port.h>
#include <wolfssl/wolfcrypt/port/microchip/mpfs_athena.h>
#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 */

View File

@ -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