diff --git a/wolfcrypt/src/hmac.c b/wolfcrypt/src/hmac.c index 68d21ab0523..e8597eddc3e 100644 --- a/wolfcrypt/src/hmac.c +++ b/wolfcrypt/src/hmac.c @@ -390,6 +390,23 @@ int wc_HmacCopy(Hmac* src, Hmac* dst) { ret = HmacKeyCopyHash(src->macType, &src->hash, &dst->hash); +#if defined(WOLF_CRYPTO_CB) && defined(WOLF_CRYPTO_CB_COPY) + /* The shallow copy above left dst sharing any per-context state a device + * hung off devCtx; let the device give dst its own copy. The struct and the + * hash context are already copied, so the callback only fixes up devCtx. */ + #ifndef WOLF_CRYPTO_CB_FIND + if ((ret == 0) && (src->devId != INVALID_DEVID)) + #else + if (ret == 0) + #endif + { + int cbRet = wc_CryptoCb_Copy(src->devId, WC_ALGO_TYPE_HMAC, + src->macType, (void*)src, (void*)dst); + if (cbRet != WC_NO_ERR_TRACE(CRYPTOCB_UNAVAILABLE)) + ret = cbRet; + } +#endif + if (ret != 0) XMEMSET(dst, 0, sizeof(*dst)); return ret; @@ -1581,6 +1598,21 @@ void wc_HmacFree(Hmac* hmac) if (hmac == NULL) return; +#if defined(WOLF_CRYPTO_CB) && defined(WOLF_CRYPTO_CB_FREE) + /* Let a device release any per-context state it hung off devCtx directly. If + * a device handles it, devCtx is cleared and the finalize fallback below is + * skipped; otherwise this is a no-op and the fallback still runs. */ + #ifndef WOLF_CRYPTO_CB_FIND + if (hmac->devId != INVALID_DEVID && hmac->devCtx != NULL) + #else + if (hmac->devCtx != NULL) + #endif + { + (void)wc_CryptoCb_Free(hmac->devId, WC_ALGO_TYPE_HMAC, hmac->macType, 0, + (void*)hmac); + } +#endif + #ifdef WOLF_CRYPTO_CB /* handle cleanup case where final is not called */ if (hmac->devId != INVALID_DEVID && hmac->devCtx != NULL) { diff --git a/wolfcrypt/src/port/xilinx/versal_gen2_asu/asu_cryptocb.c b/wolfcrypt/src/port/xilinx/versal_gen2_asu/asu_cryptocb.c new file mode 100644 index 00000000000..6722e07a79d --- /dev/null +++ b/wolfcrypt/src/port/xilinx/versal_gen2_asu/asu_cryptocb.c @@ -0,0 +1,159 @@ +/* asu_cryptocb.c + * + * Copyright (C) 2006-2026 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +#ifdef HAVE_CONFIG_H + #include +#endif + +#include + +#ifdef WOLFSSL_VERSAL_GEN2_ASU + +#include +#include +#include + +#ifdef WOLFSSL_VERSAL_GEN2_ASU_TRNG + #include +#endif +#ifdef WOLFSSL_VERSAL_GEN2_ASU_HASH + #include +#endif +#ifdef WOLFSSL_VERSAL_GEN2_ASU_HMAC + #include +#endif + +#ifndef WOLF_CRYPTO_CB + #error "WOLFSSL_VERSAL_GEN2_ASU requires WOLF_CRYPTO_CB" +#endif + +/* Route a context copy (WC_ALGO_TYPE_COPY) to the engine that owns the object, + * keyed on the copy sub-algo. Each engine's single entry handles the copy. + * Engines added later (cipher, pk) get a case here. */ +static int wc_AsuCopy(wc_CryptoInfo* info) +{ + int ret = CRYPTOCB_UNAVAILABLE; + + switch (info->copy.algo) { + #ifdef WOLFSSL_VERSAL_GEN2_ASU_HASH + case WC_ALGO_TYPE_HASH: + ret = wc_AsuHash(info); + break; + #endif + #ifdef WOLFSSL_VERSAL_GEN2_ASU_HMAC + case WC_ALGO_TYPE_HMAC: + ret = wc_AsuHmac(info); + break; + #endif + default: + break; + } + + return ret; +} + +/* Route a context free (WC_ALGO_TYPE_FREE) to the engine that owns the object, + * keyed on the free sub-algo, the same way as wc_AsuCopy. */ +static int wc_AsuFree(wc_CryptoInfo* info) +{ + int ret = CRYPTOCB_UNAVAILABLE; + + switch (info->free.algo) { + #ifdef WOLFSSL_VERSAL_GEN2_ASU_HASH + case WC_ALGO_TYPE_HASH: + ret = wc_AsuHash(info); + break; + #endif + #ifdef WOLFSSL_VERSAL_GEN2_ASU_HMAC + case WC_ALGO_TYPE_HMAC: + ret = wc_AsuHmac(info); + break; + #endif + default: + break; + } + + return ret; +} + +/* Crypto callback dispatcher. Each engine handler runs the full operation + * (looping over ASU transactions as needed) and returns the wolfCrypt result: + * 0 when the ASU handled it, CRYPTOCB_UNAVAILABLE to fall back to software, or a + * negative error. Engine cases are filled in per milestone: M1 hash and rng, + * M2 aes, M3 public key. */ +static int wc_AsuCryptoDevCb(int devId, wc_CryptoInfo* info, void* ctx) +{ + int ret = CRYPTOCB_UNAVAILABLE; + + (void)devId; + (void)ctx; + + if (info == NULL) { + return BAD_FUNC_ARG; + } + + switch (info->algo_type) { + case WC_ALGO_TYPE_HASH: /* M1 asu_hash */ + #ifdef WOLFSSL_VERSAL_GEN2_ASU_HASH + ret = wc_AsuHash(info); + #endif + break; + case WC_ALGO_TYPE_HMAC: /* M1 asu_hmac */ + #ifdef WOLFSSL_VERSAL_GEN2_ASU_HMAC + ret = wc_AsuHmac(info); + #endif + break; + case WC_ALGO_TYPE_SEED: /* M1 asu_rng */ + case WC_ALGO_TYPE_RNG: /* M1 asu_rng */ + #ifdef WOLFSSL_VERSAL_GEN2_ASU_TRNG + ret = wc_AsuRng(info); + #endif + break; + case WC_ALGO_TYPE_CIPHER: /* M2 asu_aes */ + break; + case WC_ALGO_TYPE_CMAC: /* M2 asu_aes */ + break; + case WC_ALGO_TYPE_PK: /* M3 asu_rsa and asu_ecc */ + break; + case WC_ALGO_TYPE_COPY: /* context copy: route by sub-algo to its engine */ + ret = wc_AsuCopy(info); + break; + case WC_ALGO_TYPE_FREE: /* context free: route by sub-algo to its engine */ + ret = wc_AsuFree(info); + break; + default: + break; + } + + return ret; +} + +int wc_AsuCryptoCb_RegisterDevice(int devId) +{ + return wc_CryptoCb_RegisterDevice(devId, wc_AsuCryptoDevCb, NULL); +} + +void wc_AsuCryptoCb_UnRegisterDevice(int devId) +{ + wc_CryptoCb_UnRegisterDevice(devId); +} + +#endif /* WOLFSSL_VERSAL_GEN2_ASU */ diff --git a/wolfcrypt/src/port/xilinx/versal_gen2_asu/asu_hash.c b/wolfcrypt/src/port/xilinx/versal_gen2_asu/asu_hash.c new file mode 100644 index 00000000000..afaa090fb6a --- /dev/null +++ b/wolfcrypt/src/port/xilinx/versal_gen2_asu/asu_hash.c @@ -0,0 +1,584 @@ +/* asu_hash.c + * + * Copyright (C) 2006-2026 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +/* ASU hashing for the wolfSSL crypto callback: SHA2 256/384/512, SHA3 + * 256/384/512 and SHAKE256. + * + * Why the message is buffered instead of streamed to the hardware: + * wolfSSL drives hashing as update()...update()...final(), and may have + * several hash contexts in flight at the same time (interleaved). The ASU SHA + * core supports START/UPDATE/FINISH streaming, but it keeps the running hash + * state only inside the core and exposes no way to save and restore it: + * XSha_Start always begins a fresh hash and the digest registers are read + * only (read out at FINISH). The client library therefore allows only one + * multi update stream in progress per priority channel. Because the hardware + * cannot hold more than one partial hash, interleaved hardware streaming is + * physically impossible. + * + * To support arbitrary interleaving correctly, each hash context's message is + * accumulated in its own buffer hung off the wolfSSL hash devCtx (using the + * wolfSSL _wc_Hash_Grow helper), and the digest is produced with a single + * atomic ASU operation (START|UPDATE|FINISH) at final(). Several contexts can + * be mid stream at once, each in its own buffer; the ASU only ever performs + * one complete hash at a time (serialized by wc_AsuTransact). + * + * Because the state lives in devCtx, the copy and free crypto callbacks are + * required: copy gives the destination context its own deep copy of the + * buffer (a plain struct copy would share the pointer), and free releases the + * buffer if a context is freed without being finalized. + * + * SHAKE256 is an extendable output function: the output length chosen at final() + * is carried to this callback in the hash info outSz field (by wc_CryptoCb_Shake). + * An output that fits the ASU response mailbox (WC_ASU_SHAKE_HW_MAX_BYTES) is + * produced in one ASU SHAKE256 operation; a longer output cannot be returned by + * the hardware (see that define) and is computed in software from the same + * accumulated message. SHAKE128 has no ASU mode, so it is declined and runs in + * software. Only the update()/final() hash style routes here; the + * absorb()/squeezeBlocks() streaming XOF (used by ML-KEM and ML-DSA) is not on + * the callback path and stays in software. + */ + +#ifdef HAVE_CONFIG_H + #include +#endif + +#include + +#ifdef WOLFSSL_VERSAL_GEN2_ASU_HASH + +#include +#include +#include +#include +#include +#include +#include + +#ifdef NO_INLINE + #include +#else + #define WOLFSSL_MISC_INCLUDED + #include +#endif + +#include "xasu_sha2.h" +#include "xasu_sha3.h" +#include "xasu_shainfo.h" +#include "xstatus.h" + +#ifndef WOLFSSL_HASH_KEEP + #error "WOLFSSL_VERSAL_GEN2_ASU_HASH requires WOLFSSL_HASH_KEEP (_wc_Hash_Grow)" +#endif + +#ifndef WOLFSSL_SHA512_HASHTYPE + #error "WOLFSSL_VERSAL_GEN2_ASU_HASH requires WOLFSSL_SHA512_HASHTYPE to tell \ +the SHA-512 family variants apart" +#endif + +/* Per hash context message accumulation, held in the wolfSSL hash devCtx. */ +typedef struct { + byte* msg; /* accumulated message */ + word32 used; /* bytes accumulated */ + word32 len; /* buffer capacity */ +} AsuHashKeep; + +/* One ASU hash request. */ +typedef struct { + XAsu_ShaOperationCmd cmd; + int isSha3; +} AsuHashReq; + +/* Release a kept message record. The message buffer holds the plaintext that + * was hashed, so it is zeroized before being returned to the allocator. */ +static void wc_AsuHashKeepFree(AsuHashKeep* keep) +{ + if (keep == NULL) { + return; + } + if (keep->msg != NULL) { + ForceZero(keep->msg, keep->len); + XFREE(keep->msg, NULL, DYNAMIC_TYPE_TMP_BUFFER); + } + XFREE(keep, NULL, DYNAMIC_TYPE_TMP_BUFFER); +} + +/* Submit thunk: queue one ASU hash operation. Called by wc_AsuTransact with the + * submit lock held, so it only queues the request. */ +static int wc_AsuHashSubmit(XAsu_ClientParams* params, void* ctx) +{ + AsuHashReq* req = (AsuHashReq*)ctx; + + if (params == NULL || req == NULL) { + return XST_FAILURE; + } + + if (req->isSha3 != 0) { + return XAsu_Sha3Operation(params, &req->cmd); + } + else { + return XAsu_Sha2Operation(params, &req->cmd); + } +} + +/* Return the size of the hash context struct for the given hash type, or 0 for + * an unsupported type. The copy callback needs this to duplicate the whole + * context (see wc_AsuHashCopy). */ +static word32 wc_AsuHashCtxSize(int hashType) +{ + switch (hashType) { + case WC_HASH_TYPE_SHA256: + return (word32)sizeof(wc_Sha256); + case WC_HASH_TYPE_SHA384: + return (word32)sizeof(wc_Sha384); + case WC_HASH_TYPE_SHA512: + return (word32)sizeof(wc_Sha512); + case WC_HASH_TYPE_SHA3_256: + case WC_HASH_TYPE_SHA3_384: + case WC_HASH_TYPE_SHA3_512: + case WC_HASH_TYPE_SHAKE256: /* wc_Shake is a wc_Sha3 */ + return (word32)sizeof(wc_Sha3); + default: + return 0; + } +} + +/* Return the address of the devCtx field of the hash context for the given hash + * type, or NULL for an unsupported type. */ +static void** wc_AsuHashDevCtx(void* hashCtx, int hashType) +{ + if (hashCtx == NULL) { + return NULL; + } + + switch (hashType) { + case WC_HASH_TYPE_SHA256: + return &((wc_Sha256*)hashCtx)->devCtx; + case WC_HASH_TYPE_SHA384: + return &((wc_Sha384*)hashCtx)->devCtx; + case WC_HASH_TYPE_SHA512: + return &((wc_Sha512*)hashCtx)->devCtx; + case WC_HASH_TYPE_SHA3_256: + case WC_HASH_TYPE_SHA3_384: + case WC_HASH_TYPE_SHA3_512: + case WC_HASH_TYPE_SHAKE256: /* wc_Shake is a wc_Sha3 */ + return &((wc_Sha3*)hashCtx)->devCtx; + default: + return NULL; + } +} + +/* Resolve the hash info to the ASU type and mode, the digest length, and the + * address of the context's devCtx field. Returns 0 if supported, otherwise + * CRYPTOCB_UNAVAILABLE. */ +static int wc_AsuHashResolve(wc_CryptoInfo* info, void*** devCtx, u8* shaType, + u8* shaMode, word32* hashLen) +{ + if (info == NULL || devCtx == NULL || shaType == NULL || + shaMode == NULL || hashLen == NULL) { + return BAD_FUNC_ARG; + } + + switch (info->hash.type) { + case WC_HASH_TYPE_SHA256: + *devCtx = wc_AsuHashDevCtx(info->hash.sha256, info->hash.type); + *shaType = XASU_SHA2_TYPE; + *shaMode = XASU_SHA_MODE_256; + *hashLen = WC_SHA256_DIGEST_SIZE; + break; + case WC_HASH_TYPE_SHA384: + *devCtx = wc_AsuHashDevCtx(info->hash.sha384, info->hash.type); + *shaType = XASU_SHA2_TYPE; + *shaMode = XASU_SHA_MODE_384; + *hashLen = WC_SHA384_DIGEST_SIZE; + break; + case WC_HASH_TYPE_SHA512: + /* SHA-512/224 and SHA-512/256 share the wc_Sha512 context and reach + * this callback as plain SHA-512 on update() (the variant is only + * known at final()). The ASU does only full SHA-512, and the + * truncated variants use different initial values, so decline them + * here and let wolfSSL run them entirely in software. */ + if (info->hash.sha512 != NULL && + (info->hash.sha512->hashType == WC_HASH_TYPE_SHA512_224 || + info->hash.sha512->hashType == WC_HASH_TYPE_SHA512_256)) { + return CRYPTOCB_UNAVAILABLE; + } + *devCtx = wc_AsuHashDevCtx(info->hash.sha512, info->hash.type); + *shaType = XASU_SHA2_TYPE; + *shaMode = XASU_SHA_MODE_512; + *hashLen = WC_SHA512_DIGEST_SIZE; + break; + case WC_HASH_TYPE_SHA3_256: + *devCtx = wc_AsuHashDevCtx(info->hash.sha3, info->hash.type); + *shaType = XASU_SHA3_TYPE; + *shaMode = XASU_SHA_MODE_256; + *hashLen = WC_SHA3_256_DIGEST_SIZE; + break; + case WC_HASH_TYPE_SHA3_384: + *devCtx = wc_AsuHashDevCtx(info->hash.sha3, info->hash.type); + *shaType = XASU_SHA3_TYPE; + *shaMode = XASU_SHA_MODE_384; + *hashLen = WC_SHA3_384_DIGEST_SIZE; + break; + case WC_HASH_TYPE_SHA3_512: + *devCtx = wc_AsuHashDevCtx(info->hash.sha3, info->hash.type); + *shaType = XASU_SHA3_TYPE; + *shaMode = XASU_SHA_MODE_512; + *hashLen = WC_SHA3_512_DIGEST_SIZE; + break; + case WC_HASH_TYPE_SHAKE256: + /* SHAKE is an extendable output function: the digest length is the + * caller's requested output, carried in outSz on the final call. + * SHAKE128 is not a hardware mode, so it falls through to the + * default and runs in software. */ + *devCtx = wc_AsuHashDevCtx(info->hash.sha3, info->hash.type); + *shaType = XASU_SHA3_TYPE; + *shaMode = XASU_SHA_MODE_SHAKE256; + *hashLen = info->hash.outSz; + break; + default: + return CRYPTOCB_UNAVAILABLE; + } + +#ifdef WOLFSSL_HASH_FLAGS + /* Keccak-256 (legacy 0x01 padding) is selected with a hash flag on a SHA3 + * context. The ASU SHA3 core only does NIST SHA3 (0x06) padding, so decline + * Keccak and let wolfSSL compute it in software. */ + if (*shaType == XASU_SHA3_TYPE && info->hash.sha3 != NULL && + (info->hash.sha3->flags & WC_HASH_SHA3_KECCAK256) != 0) { + return CRYPTOCB_UNAVAILABLE; + } +#endif + + if (*devCtx == NULL) { + return CRYPTOCB_UNAVAILABLE; + } + + return 0; +} + +/* Hash dataLen bytes from data in one atomic ASU operation, writing hashLen + * bytes of digest. */ +static int wc_AsuHashOneShot(u8 shaType, u8 shaMode, const byte* data, + word32 dataLen, byte* digest, word32 hashLen) +{ + AsuHashReq req; + word32 status; + byte* outAddr = digest; + word32 outLen = hashLen; + byte xofTmp[XASU_SHAKE_256_MAX_HASH_LEN]; + + if (digest == NULL || (data == NULL && dataLen > 0)) { + return BAD_FUNC_ARG; + } + + /* SHAKE256 is an extendable output function with a caller chosen length. The + * ASU reads the result out of the digest registers a 32 bit word at a time, + * so a length that is not a multiple of 4 would drop the final partial word. + * Round the request up to a word boundary into a temporary buffer and copy + * back exactly the bytes asked for. The ASU also caps a single SHAKE squeeze + * at one rate block (XASU_SHAKE_256_MAX_HASH_LEN), which bounds the temp. */ + if ((shaMode == XASU_SHA_MODE_SHAKE256) && ((hashLen % 4u) != 0u) && + (hashLen <= XASU_SHAKE_256_MAX_HASH_LEN)) { + outLen = (hashLen + 3u) & ~3u; + outAddr = xofTmp; + } + + XMEMSET(&req, 0, sizeof(req)); + req.cmd.DataAddr = (u64)(UINTPTR)data; + req.cmd.DataSize = dataLen; + req.cmd.HashAddr = (u64)(UINTPTR)outAddr; + req.cmd.HashBufSize = outLen; + req.cmd.ShaMode = shaMode; + req.cmd.IsLast = (u8)XASU_TRUE; + if (dataLen > 0) { + req.cmd.OperationFlags = + (u8)(XASU_SHA_START | XASU_SHA_UPDATE | XASU_SHA_FINISH); + } + else { + req.cmd.OperationFlags = (u8)(XASU_SHA_START | XASU_SHA_FINISH); + } + if (shaType == XASU_SHA3_TYPE) { + req.isSha3 = 1; + } + else { + req.isSha3 = 0; + } + + WC_ASU_PRINTF("[ASU] hash type=%d mode=%d dataLen=%u hashLen=%u\r\n", + (int)shaType, (int)shaMode, (unsigned int)dataLen, (unsigned int)hashLen); + + /* The ASU DMAs the input message from memory, so clean it out. The digest is + * delivered back through the response path (a CPU copy), so it needs no + * cache maintenance here. */ + if (dataLen > 0) { + wc_AsuCacheFlush(data, dataLen); + } + + status = wc_AsuTransact(wc_AsuHashSubmit, &req, NULL); + if (status != XST_SUCCESS) { + return WC_HW_E; + } + + /* Copy back the exact byte count when a temp buffer was used for the SHAKE + * word-alignment round up. */ + if (outAddr != digest) { + XMEMCPY(digest, xofTmp, hashLen); + } + + return 0; +} + +/* The ASU returns a hash through a fixed response mailbox slot of 16 words (64 + * bytes), sized for the largest fixed digest (SHA-512). SHAKE256 is an + * extendable output function, so a requested output up to this size fits in one + * ASU operation and is offloaded; a longer output is computed in software + * instead (see wc_AsuShakeSoftware). + * + * The hardware could in principle emit more by continuing the squeeze a rate + * block at a time, but that path is closed to us: the XAsu_ShaOperationCmd + * "next xof" continue-squeeze flag (ShakeReserved) is documented "NA for client, + * ASUFW internal use", and the ASU server resets the squeeze after every finish. + * So a client cannot chain blocks, and anything past one mailbox stays software. */ +#define WC_ASU_SHAKE_HW_MAX_BYTES 64 + +/* Compute SHAKE256 of the already accumulated message in software, for outputs + * larger than the ASU can return. A private context with INVALID_DEVID keeps it + * off the crypto callback (no recursion) so wolfSSL runs its own SHAKE. */ +static int wc_AsuShakeSoftware(const byte* data, word32 dataLen, byte* digest, + word32 hashLen) +{ + wc_Shake shake; + int ret; + + if (digest == NULL || (data == NULL && dataLen > 0)) { + return BAD_FUNC_ARG; + } + + ret = wc_InitShake256(&shake, NULL, INVALID_DEVID); + if (ret != 0) { + return ret; + } + + if (dataLen > 0) { + ret = wc_Shake256_Update(&shake, data, dataLen); + } + if (ret == 0) { + ret = wc_Shake256_Final(&shake, digest, hashLen); + } + + wc_Shake256_Free(&shake); + return ret; +} + +/* update() and final() handling for WC_ALGO_TYPE_HASH. Internal helper reached + * through the wc_AsuHash dispatcher. */ +static int wc_AsuHashCompute(wc_CryptoInfo* info) +{ + void** devCtxPtr = NULL; + u8 shaType = 0; + u8 shaMode = 0; + word32 hashLen = 0; + AsuHashKeep* keep; + int ret; + + if (info == NULL) { + return BAD_FUNC_ARG; + } + + ret = wc_AsuHashResolve(info, &devCtxPtr, &shaType, &shaMode, &hashLen); + if (ret != 0) { + return ret; + } + + keep = (AsuHashKeep*)(*devCtxPtr); + + /* update(): accumulate the message with the wolfSSL grow helper. */ + if (info->hash.in != NULL) { + if (keep == NULL) { + keep = (AsuHashKeep*)XMALLOC(sizeof(AsuHashKeep), NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (keep == NULL) { + return MEMORY_E; + } + XMEMSET(keep, 0, sizeof(*keep)); + *devCtxPtr = keep; + } + + ret = _wc_Hash_Grow(&keep->msg, &keep->used, &keep->len, + info->hash.in, (int)info->hash.inSz, NULL); + if (ret != 0) { + return ret; + } + } + + /* final(): hash the whole accumulated message in one ASU operation, then + * release the buffer. */ + if (info->hash.digest != NULL) { + const byte* data = NULL; + word32 dataLen = 0; + + if (keep != NULL) { + data = keep->msg; + dataLen = keep->used; + } + + /* SHAKE256 output longer than the ASU response mailbox can carry is + * produced in software from the same accumulated message; everything + * else (the fixed hashes and short SHAKE) is one ASU operation. */ + if ((shaMode == XASU_SHA_MODE_SHAKE256) && + (hashLen > WC_ASU_SHAKE_HW_MAX_BYTES)) { + ret = wc_AsuShakeSoftware(data, dataLen, info->hash.digest, hashLen); + } + else { + ret = wc_AsuHashOneShot(shaType, shaMode, data, dataLen, + info->hash.digest, hashLen); + } + + if (keep != NULL) { + wc_AsuHashKeepFree(keep); + *devCtxPtr = NULL; + } + + if (ret != 0) { + return ret; + } + } + + return 0; +} + +/* WC_ALGO_TYPE_COPY handling for a hash context. Internal helper reached + * through the wc_AsuHash dispatcher. */ +static int wc_AsuHashCopy(wc_CryptoInfo* info) +{ + void** srcDevCtx; + void** dstDevCtx; + AsuHashKeep* srcKeep; + AsuHashKeep* dstKeep; + word32 ctxSize; + int ret; + + if (info == NULL) { + return BAD_FUNC_ARG; + } + if (info->copy.algo != WC_ALGO_TYPE_HASH) { + return CRYPTOCB_UNAVAILABLE; + } + + srcDevCtx = wc_AsuHashDevCtx(info->copy.src, info->copy.type); + dstDevCtx = wc_AsuHashDevCtx(info->copy.dst, info->copy.type); + ctxSize = wc_AsuHashCtxSize(info->copy.type); + if (srcDevCtx == NULL || dstDevCtx == NULL || ctxSize == 0) { + return CRYPTOCB_UNAVAILABLE; + } + + /* wolfSSL calls this callback before its own struct copy and skips both that + * copy and its own free of the destination when we return success, so the + * callback owns the entire copy. Free any buffer the destination already + * holds first (it is about to be overwritten), or it would leak. */ + wc_AsuHashKeepFree((AsuHashKeep*)(*dstDevCtx)); + + /* Duplicate the whole context struct, which carries devId (so the copy keeps + * routing to this port) and the rest of the state. The struct copy leaves the + * destination devCtx pointing at the source buffer, so then replace it with + * the destination's own deep copy of the kept message. */ + XMEMCPY(info->copy.dst, info->copy.src, ctxSize); + + srcKeep = (AsuHashKeep*)(*srcDevCtx); + if (srcKeep == NULL) { + *dstDevCtx = NULL; + return 0; + } + + dstKeep = (AsuHashKeep*)XMALLOC(sizeof(AsuHashKeep), NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (dstKeep == NULL) { + *dstDevCtx = NULL; + return MEMORY_E; + } + XMEMSET(dstKeep, 0, sizeof(*dstKeep)); + + if (srcKeep->used > 0) { + ret = _wc_Hash_Grow(&dstKeep->msg, &dstKeep->used, &dstKeep->len, + srcKeep->msg, (int)srcKeep->used, NULL); + if (ret != 0) { + wc_AsuHashKeepFree(dstKeep); + *dstDevCtx = NULL; + return ret; + } + } + + *dstDevCtx = dstKeep; + return 0; +} + +/* WC_ALGO_TYPE_FREE handling for a hash context. Internal helper reached + * through the wc_AsuHash dispatcher. */ +static int wc_AsuHashFree(wc_CryptoInfo* info) +{ + void** devCtx; + AsuHashKeep* keep; + + if (info == NULL) { + return BAD_FUNC_ARG; + } + if (info->free.algo != WC_ALGO_TYPE_HASH) { + return CRYPTOCB_UNAVAILABLE; + } + + devCtx = wc_AsuHashDevCtx(info->free.obj, info->free.type); + if (devCtx != NULL) { + keep = (AsuHashKeep*)(*devCtx); + if (keep != NULL) { + wc_AsuHashKeepFree(keep); + *devCtx = NULL; + } + } + + /* Return unavailable so wolfSSL still runs its own ForceZero. devCtx is now + * NULL, so there is no second free. */ + return CRYPTOCB_UNAVAILABLE; +} + +/* Single entry point for the SHA2/SHA3 engine. The crypto callback dispatcher + * routes every hash related operation here and this handler decides which one it + * is: update/final (WC_ALGO_TYPE_HASH), context copy (WC_ALGO_TYPE_COPY), or + * context free (WC_ALGO_TYPE_FREE). Keeping the whole lifecycle behind one entry + * keeps it owned by this module. */ +int wc_AsuHash(wc_CryptoInfo* info) +{ + if (info == NULL) { + return BAD_FUNC_ARG; + } + + switch (info->algo_type) { + case WC_ALGO_TYPE_HASH: + return wc_AsuHashCompute(info); + case WC_ALGO_TYPE_COPY: + return wc_AsuHashCopy(info); + case WC_ALGO_TYPE_FREE: + return wc_AsuHashFree(info); + default: + return CRYPTOCB_UNAVAILABLE; + } +} + +#endif /* WOLFSSL_VERSAL_GEN2_ASU_HASH */ diff --git a/wolfcrypt/src/port/xilinx/versal_gen2_asu/asu_hmac.c b/wolfcrypt/src/port/xilinx/versal_gen2_asu/asu_hmac.c new file mode 100644 index 00000000000..33b00eb09f3 --- /dev/null +++ b/wolfcrypt/src/port/xilinx/versal_gen2_asu/asu_hmac.c @@ -0,0 +1,403 @@ +/* asu_hmac.c + * + * Copyright (C) 2006-2026 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +/* ASU HMAC for the wolfSSL crypto callback: HMAC over SHA2 256/384/512 and SHA3 + * 256/384/512. + * + * The approach mirrors the SHA hash port (asu_hash.c): wolfSSL drives HMAC as + * update()...update()...final() and may have several contexts in flight, but the + * ASU keeps the running state only inside the core and cannot save and restore + * it. So each context's message is accumulated in its own buffer hung off the + * wolfSSL Hmac devCtx (with the wolfSSL _wc_Hash_Grow helper) and the whole HMAC + * is produced in one atomic ASU operation at final(). The raw key is taken from + * the context: wolfSSL records keyRaw and keyLen on the Hmac whenever the crypto + * callback is enabled, and the ASU HMAC engine performs the key reduction + * internally, so the unmodified user key is passed straight through. + * + * Lifecycle: unlike the hash contexts, wc_HmacCopy does not run through the copy + * crypto callback and wc_HmacFree does not run through the free callback, so no + * copy/free handlers are wired for HMAC. This is safe because the buffer is freed + * in final() (the common path), wc_HmacFree finalizes any context that still owns + * a buffer through this same callback (so an abandoned context is cleaned up), + * and wolfSSL only copies an HMAC context right after the key is set, before any + * update, when devCtx is still NULL (so the shallow struct copy shares nothing). + * + * HMAC output is always the underlying digest size (<= 64 bytes), so unlike SHAKE + * it always fits the ASU response mailbox and is always offloaded for the + * supported MAC types. HMAC over SHA-1, SHA-224 and the truncated SHA-512 + * variants has no ASU mode and is declined to software. + */ + +#ifdef HAVE_CONFIG_H + #include +#endif + +#include + +#ifdef WOLFSSL_VERSAL_GEN2_ASU_HMAC + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef NO_INLINE + #include +#else + #define WOLFSSL_MISC_INCLUDED + #include +#endif + +#include "xasu_hmac.h" +#include "xasu_hmacinfo.h" +#include "xasu_shainfo.h" +#include "xstatus.h" + +#ifndef WOLFSSL_HASH_KEEP + #error "WOLFSSL_VERSAL_GEN2_ASU_HMAC requires WOLFSSL_HASH_KEEP (_wc_Hash_Grow)" +#endif + +/* Per HMAC context message accumulation, held in the wolfSSL Hmac devCtx. */ +typedef struct { + byte* msg; /* accumulated message */ + word32 used; /* bytes accumulated */ + word32 len; /* buffer capacity */ +} AsuHmacKeep; + +/* One ASU HMAC request. */ +typedef struct { + XAsu_HmacParams params; +} AsuHmacReq; + +/* Release a kept message record. The message buffer holds plaintext that was + * MAC'd, so it is zeroized before being returned to the allocator. */ +static void wc_AsuHmacKeepFree(AsuHmacKeep* keep) +{ + if (keep == NULL) { + return; + } + if (keep->msg != NULL) { + ForceZero(keep->msg, keep->len); + XFREE(keep->msg, NULL, DYNAMIC_TYPE_TMP_BUFFER); + } + XFREE(keep, NULL, DYNAMIC_TYPE_TMP_BUFFER); +} + +/* Submit thunk: queue one ASU HMAC operation. Called by wc_AsuTransact with the + * submit lock held, so it only queues the request. */ +static int wc_AsuHmacSubmit(XAsu_ClientParams* params, void* ctx) +{ + AsuHmacReq* req = (AsuHmacReq*)ctx; + + if (params == NULL || req == NULL) { + return XST_FAILURE; + } + + return XAsu_HmacCompute(params, &req->params); +} + +/* Resolve the wolfSSL MAC (hash) type to the ASU SHA type and mode and the HMAC + * output length. Returns 0 if supported, otherwise CRYPTOCB_UNAVAILABLE. */ +static int wc_AsuHmacResolve(int macType, u8* shaType, u8* shaMode, + word32* hmacLen) +{ + if (shaType == NULL || shaMode == NULL || hmacLen == NULL) { + return BAD_FUNC_ARG; + } + + switch (macType) { + case WC_HASH_TYPE_SHA256: + *shaType = XASU_SHA2_TYPE; + *shaMode = XASU_SHA_MODE_256; + *hmacLen = WC_SHA256_DIGEST_SIZE; + break; + case WC_HASH_TYPE_SHA384: + *shaType = XASU_SHA2_TYPE; + *shaMode = XASU_SHA_MODE_384; + *hmacLen = WC_SHA384_DIGEST_SIZE; + break; + case WC_HASH_TYPE_SHA512: + *shaType = XASU_SHA2_TYPE; + *shaMode = XASU_SHA_MODE_512; + *hmacLen = WC_SHA512_DIGEST_SIZE; + break; + case WC_HASH_TYPE_SHA3_256: + *shaType = XASU_SHA3_TYPE; + *shaMode = XASU_SHA_MODE_256; + *hmacLen = WC_SHA3_256_DIGEST_SIZE; + break; + case WC_HASH_TYPE_SHA3_384: + *shaType = XASU_SHA3_TYPE; + *shaMode = XASU_SHA_MODE_384; + *hmacLen = WC_SHA3_384_DIGEST_SIZE; + break; + case WC_HASH_TYPE_SHA3_512: + *shaType = XASU_SHA3_TYPE; + *shaMode = XASU_SHA_MODE_512; + *hmacLen = WC_SHA3_512_DIGEST_SIZE; + break; + default: + return CRYPTOCB_UNAVAILABLE; + } + + return 0; +} + +/* Compute HMAC over the whole message in one atomic ASU operation. */ +static int wc_AsuHmacOneShot(u8 shaType, u8 shaMode, const byte* key, + word32 keyLen, const byte* msg, word32 msgLen, byte* mac, word32 macLen) +{ + AsuHmacReq req; + word32 status; + + if (key == NULL || mac == NULL || (msg == NULL && msgLen > 0)) { + return BAD_FUNC_ARG; + } + + XMEMSET(&req, 0, sizeof(req)); + req.params.ShaType = shaType; + req.params.ShaMode = shaMode; + req.params.IsLast = (u8)XASU_TRUE; + req.params.KeyLen = keyLen; + req.params.MsgLen = msgLen; + req.params.HmacLen = macLen; + req.params.KeyAddr = (u64)(UINTPTR)key; + req.params.MsgBufferAddr = (u64)(UINTPTR)msg; + req.params.HmacAddr = (u64)(UINTPTR)mac; + if (msgLen > 0) { + req.params.OperationFlags = + (u8)(XASU_HMAC_INIT | XASU_HMAC_UPDATE | XASU_HMAC_FINAL); + } + else { + req.params.OperationFlags = (u8)(XASU_HMAC_INIT | XASU_HMAC_FINAL); + } + + WC_ASU_PRINTF("[ASU] hmac type=%d mode=%d keyLen=%u msgLen=%u macLen=%u\r\n", + (int)shaType, (int)shaMode, (unsigned int)keyLen, (unsigned int)msgLen, + (unsigned int)macLen); + + /* The ASU DMAs the key and message from memory, so clean them out. The MAC + * is delivered back through the response path, so it needs no cache + * maintenance here. */ + wc_AsuCacheFlush(key, keyLen); + if (msgLen > 0) { + wc_AsuCacheFlush(msg, msgLen); + } + + status = wc_AsuTransact(wc_AsuHmacSubmit, &req, NULL); + if (status != XST_SUCCESS) { + return WC_HW_E; + } + + return 0; +} + +/* update() and final() handling for WC_ALGO_TYPE_HMAC. Internal helper reached + * through the wc_AsuHmac dispatcher. */ +static int wc_AsuHmacCompute(wc_CryptoInfo* info) +{ + Hmac* hmac; + AsuHmacKeep* keep; + u8 shaType = 0; + u8 shaMode = 0; + word32 hmacLen = 0; + int ret; + + if (info == NULL) { + return BAD_FUNC_ARG; + } + + hmac = info->hmac.hmac; + if (hmac == NULL) { + return BAD_FUNC_ARG; + } + + ret = wc_AsuHmacResolve(info->hmac.macType, &shaType, &shaMode, &hmacLen); + if (ret != 0) { + return ret; + } + + /* The ASU HMAC engine needs a non empty raw key; if wolfSSL did not retain + * one, let it compute the HMAC in software. keyRaw and keyLen are fixed by + * the preceding SetKey, so this decision is the same on every update and + * final for a given context. */ + if ((hmac->keyRaw == NULL) || (hmac->keyLen == 0)) { + return CRYPTOCB_UNAVAILABLE; + } + + keep = (AsuHmacKeep*)hmac->devCtx; + + /* update(): accumulate the message with the wolfSSL grow helper. */ + if (info->hmac.in != NULL) { + if (keep == NULL) { + keep = (AsuHmacKeep*)XMALLOC(sizeof(AsuHmacKeep), NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (keep == NULL) { + return MEMORY_E; + } + XMEMSET(keep, 0, sizeof(*keep)); + hmac->devCtx = keep; + } + + ret = _wc_Hash_Grow(&keep->msg, &keep->used, &keep->len, + info->hmac.in, (int)info->hmac.inSz, NULL); + if (ret != 0) { + return ret; + } + } + + /* final(): HMAC the whole accumulated message in one ASU operation, then + * release the buffer. */ + if (info->hmac.digest != NULL) { + const byte* msg = NULL; + word32 msgLen = 0; + + if (keep != NULL) { + msg = keep->msg; + msgLen = keep->used; + } + + ret = wc_AsuHmacOneShot(shaType, shaMode, hmac->keyRaw, + (word32)hmac->keyLen, msg, msgLen, info->hmac.digest, hmacLen); + + if (keep != NULL) { + wc_AsuHmacKeepFree(keep); + hmac->devCtx = NULL; + } + + if (ret != 0) { + return ret; + } + } + + return 0; +} + +/* WC_ALGO_TYPE_COPY handling for an HMAC context. Unlike the hash copy callback, + * wc_HmacCopy performs the struct copy itself (and deep copies the inner hash), + * then calls this only to fix up the kept message: the shallow struct copy left + * the destination sharing the source buffer pointer, so replace it with the + * destination's own deep copy. Internal helper reached through wc_AsuHmac. */ +static int wc_AsuHmacCopy(wc_CryptoInfo* info) +{ + Hmac* src; + Hmac* dst; + AsuHmacKeep* srcKeep; + AsuHmacKeep* dstKeep; + int ret; + + if (info == NULL) { + return BAD_FUNC_ARG; + } + if (info->copy.algo != WC_ALGO_TYPE_HMAC) { + return CRYPTOCB_UNAVAILABLE; + } + + src = (Hmac*)info->copy.src; + dst = (Hmac*)info->copy.dst; + if (src == NULL || dst == NULL) { + return CRYPTOCB_UNAVAILABLE; + } + + srcKeep = (AsuHmacKeep*)src->devCtx; + if (srcKeep == NULL) { + dst->devCtx = NULL; + return 0; + } + + dstKeep = (AsuHmacKeep*)XMALLOC(sizeof(AsuHmacKeep), NULL, + DYNAMIC_TYPE_TMP_BUFFER); + if (dstKeep == NULL) { + dst->devCtx = NULL; + return MEMORY_E; + } + XMEMSET(dstKeep, 0, sizeof(*dstKeep)); + + if (srcKeep->used > 0) { + ret = _wc_Hash_Grow(&dstKeep->msg, &dstKeep->used, &dstKeep->len, + srcKeep->msg, (int)srcKeep->used, NULL); + if (ret != 0) { + wc_AsuHmacKeepFree(dstKeep); + dst->devCtx = NULL; + return ret; + } + } + + dst->devCtx = dstKeep; + return 0; +} + +/* WC_ALGO_TYPE_FREE handling for an HMAC context: release the accumulated + * message buffer so an abandoned context (updated but never finalized) is freed + * without a stray ASU operation. Internal helper reached through wc_AsuHmac. */ +static int wc_AsuHmacFree(wc_CryptoInfo* info) +{ + Hmac* hmac; + AsuHmacKeep* keep; + + if (info == NULL) { + return BAD_FUNC_ARG; + } + if (info->free.algo != WC_ALGO_TYPE_HMAC) { + return CRYPTOCB_UNAVAILABLE; + } + + hmac = (Hmac*)info->free.obj; + if (hmac != NULL) { + keep = (AsuHmacKeep*)hmac->devCtx; + if (keep != NULL) { + wc_AsuHmacKeepFree(keep); + hmac->devCtx = NULL; + } + } + + /* Return unavailable so wolfSSL still runs its own cleanup. devCtx is now + * NULL, so there is no second free. */ + return CRYPTOCB_UNAVAILABLE; +} + +/* Single entry point for the HMAC engine. The crypto callback dispatcher routes + * every HMAC related operation here and this handler decides which it is: update + * and final (WC_ALGO_TYPE_HMAC), context copy (WC_ALGO_TYPE_COPY) or context + * free (WC_ALGO_TYPE_FREE). */ +int wc_AsuHmac(wc_CryptoInfo* info) +{ + if (info == NULL) { + return BAD_FUNC_ARG; + } + + switch (info->algo_type) { + case WC_ALGO_TYPE_HMAC: + return wc_AsuHmacCompute(info); + case WC_ALGO_TYPE_COPY: + return wc_AsuHmacCopy(info); + case WC_ALGO_TYPE_FREE: + return wc_AsuHmacFree(info); + default: + return CRYPTOCB_UNAVAILABLE; + } +} + +#endif /* WOLFSSL_VERSAL_GEN2_ASU_HMAC */ diff --git a/wolfcrypt/src/port/xilinx/versal_gen2_asu/asu_rng.c b/wolfcrypt/src/port/xilinx/versal_gen2_asu/asu_rng.c new file mode 100644 index 00000000000..df32a5770e9 --- /dev/null +++ b/wolfcrypt/src/port/xilinx/versal_gen2_asu/asu_rng.c @@ -0,0 +1,133 @@ +/* asu_rng.c + * + * Copyright (C) 2006-2026 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +#ifdef HAVE_CONFIG_H + #include +#endif + +#include + +#ifdef WOLFSSL_VERSAL_GEN2_ASU_TRNG + +#include +#include +#include + +#include "xasu_trng.h" +#include "xstatus.h" + +/* One TRNG read request, passed as the transaction context. */ +typedef struct { + byte* buf; + word32 len; +} AsuTrngReq; + +/* Submit thunk: queue one TRNG read of up to one strength block. Called by + * wc_AsuTransact with the submit lock held, so it only queues the request. The + * completion ISR copies the random bytes into buf, so no cache maintenance is + * needed here. */ +static int wc_AsuTrngSubmit(XAsu_ClientParams* params, void* ctx) +{ + AsuTrngReq* req = (AsuTrngReq*)ctx; + + if (params == NULL || req == NULL) { + return XST_FAILURE; + } + + return XAsu_TrngGetRandomNum(params, req->buf, req->len); +} + +/* Fill out with len bytes from the ASU TRNG. The TRNG returns at most one + * strength block (32 bytes) per call, so larger requests run over several + * transactions, each its own ASU unique id. */ +static int wc_AsuTrngFill(byte* out, word32 len) +{ + AsuTrngReq req; + word32 chunk; + + if (out == NULL) { + return BAD_FUNC_ARG; + } + + while (len > 0) { + if (len < XASU_TRNG_RANDOM_NUM_IN_BYTES) { + chunk = len; + } + else { + chunk = XASU_TRNG_RANDOM_NUM_IN_BYTES; + } + + req.buf = out; + req.len = chunk; + + if (wc_AsuTransact(wc_AsuTrngSubmit, &req, NULL) != XST_SUCCESS) { + return WC_HW_E; + } + + out += chunk; + len -= chunk; + } + + return 0; +} + +/* WC_ALGO_TYPE_SEED: provide the ASU TRNG as a seed source for the DRBG. + * Internal helper reached through the wc_AsuRng dispatcher. */ +static int wc_AsuRngSeed(wc_CryptoInfo* info) +{ + if (info == NULL) { + return BAD_FUNC_ARG; + } + + return wc_AsuTrngFill(info->seed.seed, info->seed.sz); +} + +/* WC_ALGO_TYPE_RNG: serve random blocks straight from the ASU TRNG. + * Internal helper reached through the wc_AsuRng dispatcher. */ +static int wc_AsuRngGenerate(wc_CryptoInfo* info) +{ + if (info == NULL) { + return BAD_FUNC_ARG; + } + + return wc_AsuTrngFill(info->rng.out, info->rng.sz); +} + +/* Single entry point for the ASU TRNG. The crypto callback dispatcher routes + * both random number requests here and this handler decides which it is: seed a + * DRBG (WC_ALGO_TYPE_SEED) or serve random blocks (WC_ALGO_TYPE_RNG). */ +int wc_AsuRng(wc_CryptoInfo* info) +{ + if (info == NULL) { + return BAD_FUNC_ARG; + } + + switch (info->algo_type) { + case WC_ALGO_TYPE_SEED: + return wc_AsuRngSeed(info); + case WC_ALGO_TYPE_RNG: + return wc_AsuRngGenerate(info); + default: + return CRYPTOCB_UNAVAILABLE; + } +} + +#endif /* WOLFSSL_VERSAL_GEN2_ASU_TRNG */ diff --git a/wolfcrypt/src/port/xilinx/versal_gen2_asu/asu_util.c b/wolfcrypt/src/port/xilinx/versal_gen2_asu/asu_util.c new file mode 100644 index 00000000000..b83f05af2ba --- /dev/null +++ b/wolfcrypt/src/port/xilinx/versal_gen2_asu/asu_util.c @@ -0,0 +1,220 @@ +/* asu_util.c + * + * Copyright (C) 2006-2026 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +#ifdef HAVE_CONFIG_H + #include +#endif + +#include + +#ifdef WOLFSSL_VERSAL_GEN2_ASU + +#include +#include +#include + +#include "xil_cache.h" +#include "xstatus.h" + +#ifdef WOLFSSL_VERSAL_GEN2_ASU_RTC + #include "xiltimer.h" + #include "xrtcpsu.h" + #include "xparameters.h" + + #ifndef COUNTS_PER_SECOND + #define COUNTS_PER_SECOND XPAR_CPU_TIMESTAMP_CLK_FREQ + #endif +#endif + +/* Shared response handler registered with every ASU request. The ASU client + * passes the AsuWait record back through the callback reference. */ +static void wc_AsuResponseHandler(void* ref, u32 status) +{ + AsuWait* wait = (AsuWait*)ref; + + if (wait != NULL) { + wait->Status = (word32)status; + wait->Done = 1; + } +} + +void wc_AsuWaitPrepare(AsuWait* wait, XAsu_ClientParams* params) +{ + wait->Done = 0; + wait->Status = (word32)XST_FAILURE; + + params->Priority = XASU_PRIORITY_HIGH; + params->SecureFlag = XASU_CMD_SECURE; + params->CallBackFuncPtr = (XAsuClient_ResponseHandler)wc_AsuResponseHandler; + params->CallBackRefPtr = (void*)wait; + params->AdditionalStatus = (u32)XST_FAILURE; +} + +word32 wc_AsuWaitDone(AsuWait* wait) +{ + while (wait->Done == 0) { + /* busy wait for the single threaded baremetal client */ + } + + return wait->Status; +} + +/* When WC_ASU_DISABLE_CACHE is set (mirrored from XASU_DISABLE_CACHE in + * asu_settings.h) the data cache is off for the whole application, so buffer + * maintenance is unnecessary and these become no ops. Otherwise the cache is on + * and the port cleans inputs and invalidates outputs around each ASU access. */ +void wc_AsuCacheFlush(const void* addr, word32 len) +{ +#ifdef WC_ASU_DISABLE_CACHE + (void)addr; + (void)len; +#else + Xil_DCacheFlushRange((INTPTR)addr, (INTPTR)len); +#endif +} + +void wc_AsuCacheInvalidate(void* addr, word32 len) +{ +#ifdef WC_ASU_DISABLE_CACHE + (void)addr; + (void)len; +#else + Xil_DCacheInvalidateRange((INTPTR)addr, (INTPTR)len); +#endif +} + + +/* ----------------------------------------------------------------------- */ +/* Transaction and concurrency (ticketing) */ +/* ----------------------------------------------------------------------- */ +/* The ASU associates a unique id with each call and routes its completion back + * to the request's own callback, so that id is the ticket: every transaction + * gets its own AsuWait and several run concurrently. The only shared state that + * needs guarding is the submit, since the client request allocation is not + * thread safe. Locking uses the wolfSSL crypto hardware mutex (enabled for the + * multi threaded build in asu_settings.h, a no op otherwise) and is held only + * across the submit, never across the wait. */ +word32 wc_AsuTransact(AsuSubmitFn submit, void* ctx, word32* additionalStatus) +{ + XAsu_ClientParams params; + AsuWait wait; + s32 status; + + if (submit == NULL) { + return (word32)XST_FAILURE; + } + + /* The prepared params carry this request's completion context, which the + * ASU associates with the unique id it assigns. */ + wc_AsuWaitPrepare(&wait, ¶ms); + + wolfSSL_CryptHwMutexLock(); + status = submit(¶ms, ctx); + wolfSSL_CryptHwMutexUnLock(); + + if (status != XST_SUCCESS) { + WC_ASU_PRINTF("[ASU] submit failed status=%d\r\n", (int)status); + return (word32)status; + } + + /* Wait on our own completion outside the lock, so other callers submit and + * run concurrently up to the ASU queue depth. */ + status = (s32)wc_AsuWaitDone(&wait); + + WC_ASU_PRINTF("[ASU] op done status=%d\r\n", (int)status); + + if (additionalStatus != NULL) { + *additionalStatus = params.AdditionalStatus; + } + + return (word32)status; +} + +#ifdef WOLFSSL_VERSAL_GEN2_ASU_RTC + +/* Timer and RTC. The benchmark time base is the Cortex A78 generic timer, which + * is free running and needs no init. The system RTC is brought up by + * wc_AsuTimerInit and read with wc_AsuRtcSeconds for wall clock timestamps. */ + +static XRtcPsu asuRtc; +static int asuRtcReady = 0; + +int wc_AsuTimerInit(void) +{ + XRtcPsu_Config* cfg; + + if (asuRtcReady) { + return 0; + } + + cfg = XRtcPsu_LookupConfig(XPAR_XRTCPSU_0_BASEADDR); + if (cfg == NULL) { + return WC_HW_E; + } + + if (XRtcPsu_CfgInitialize(&asuRtc, cfg, XPAR_XRTCPSU_0_BASEADDR) + != XST_SUCCESS) { + return WC_HW_E; + } + + asuRtcReady = 1; + return 0; +} + +word64 wc_AsuTimerCount(void) +{ + XTime now = 0; + + XTime_GetTime(&now); + + return (word64)now; +} + +double wc_AsuTimerSeconds(void) +{ + return (double)wc_AsuTimerCount() / (double)COUNTS_PER_SECOND; +} + +word32 wc_AsuRtcSeconds(void) +{ + if (!asuRtcReady && wc_AsuTimerInit() != 0) { + return 0; + } + + return (word32)XRtcPsu_GetCurrentTime(&asuRtc); +} + +#if defined(WOLFSSL_USER_CURRTIME) + +/* Benchmark time source. benchmark.c declares this extern when + * WOLFSSL_USER_CURRTIME is set and calls it to time each operation. */ +double current_time(int reset) +{ + (void)reset; /* the generic timer counter is free running */ + + return wc_AsuTimerSeconds(); +} + +#endif /* WOLFSSL_USER_CURRTIME */ + +#endif /* WOLFSSL_VERSAL_GEN2_ASU_RTC */ + +#endif /* WOLFSSL_VERSAL_GEN2_ASU */ diff --git a/wolfcrypt/src/wc_port.c b/wolfcrypt/src/wc_port.c index 63c1bb57f54..d38df2395aa 100644 --- a/wolfcrypt/src/wc_port.c +++ b/wolfcrypt/src/wc_port.c @@ -194,6 +194,10 @@ Threading/Mutex options: #include #endif +#if defined(WOLFSSL_VERSAL_GEN2_ASU) + #include +#endif + #ifdef HAVE_INTEL_QA_SYNC #include #endif @@ -569,6 +573,16 @@ int wolfCrypt_Init(void) WOLFCRYPT_INIT_RAISE_BAD_STATE(); } #endif + + /* Register the Versal Gen2 ASU device so wolfCrypt operations route to the + * ASU hardware. The ASU client must already be initialized by the + * application with XAsu_ClientInit. */ + #if defined(WOLFSSL_VERSAL_GEN2_ASU) && defined(WOLF_CRYPTO_CB) + ret = wc_AsuCryptoCb_RegisterDevice(WOLFSSL_VERSAL_GEN2_ASU_DEVID); + if (ret != 0) { + WOLFCRYPT_INIT_RAISE_BAD_STATE(); + } + #endif #if defined(MAX3266X_RTC) ret = wc_MXC_RTC_Init(); if (ret != 0) { diff --git a/wolfssl/wolfcrypt/port/xilinx/versal_gen2_asu/asu_cryptocb.h b/wolfssl/wolfcrypt/port/xilinx/versal_gen2_asu/asu_cryptocb.h new file mode 100644 index 00000000000..a168c66d37b --- /dev/null +++ b/wolfssl/wolfcrypt/port/xilinx/versal_gen2_asu/asu_cryptocb.h @@ -0,0 +1,53 @@ +/* asu_cryptocb.h + * + * Copyright (C) 2006-2026 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +/* wolfSSL crypto callback device for the Versal Gen2 ASU. Registering this + * device routes wolfCrypt operations to the ASU hardware engines, with a + * software fallback for anything the ASU does not handle. */ + +#ifndef WOLFSSL_VERSAL_GEN2_ASU_CRYPTOCB_H +#define WOLFSSL_VERSAL_GEN2_ASU_CRYPTOCB_H + +#include + +#ifdef WOLFSSL_VERSAL_GEN2_ASU + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Register the ASU device with the wolfSSL crypto callback framework. The ASU + * client must already be initialized with XAsu_ClientInit. Pass the same devId + * that WC_USE_DEVID is set to so wolfSSL routes operations to this device. */ +WOLFSSL_API int wc_AsuCryptoCb_RegisterDevice(int devId); + +/* Remove the ASU device from the crypto callback framework. */ +WOLFSSL_API void wc_AsuCryptoCb_UnRegisterDevice(int devId); + +#ifdef __cplusplus +} +#endif + +#endif /* WOLFSSL_VERSAL_GEN2_ASU */ + +#endif /* WOLFSSL_VERSAL_GEN2_ASU_CRYPTOCB_H */ diff --git a/wolfssl/wolfcrypt/port/xilinx/versal_gen2_asu/asu_hash.h b/wolfssl/wolfcrypt/port/xilinx/versal_gen2_asu/asu_hash.h new file mode 100644 index 00000000000..a06a85fd9bc --- /dev/null +++ b/wolfssl/wolfcrypt/port/xilinx/versal_gen2_asu/asu_hash.h @@ -0,0 +1,53 @@ +/* asu_hash.h + * + * Copyright (C) 2006-2026 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +/* ASU hashing for the wolfSSL crypto callback: SHA2 256/384/512 and SHA3 + * 256/384/512. The message is accumulated per hash context and hashed in a + * single ASU operation at finalize. See asu_hash.c for why. */ + +#ifndef WOLFSSL_VERSAL_GEN2_ASU_HASH_H +#define WOLFSSL_VERSAL_GEN2_ASU_HASH_H + +#include + +#ifdef WOLFSSL_VERSAL_GEN2_ASU_HASH + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Single entry point for the SHA2/SHA3 engine. The crypto callback dispatcher + * routes every hash related operation here and this handler decides which it is: + * update and final (WC_ALGO_TYPE_HASH), context copy (WC_ALGO_TYPE_COPY), or + * context free (WC_ALGO_TYPE_FREE). Supports SHA2 256/384/512 and SHA3 + * 256/384/512. Returns 0 on success, CRYPTOCB_UNAVAILABLE for an unsupported + * operation or hash type (software fallback), or a negative error. */ +WOLFSSL_LOCAL int wc_AsuHash(wc_CryptoInfo* info); + +#ifdef __cplusplus +} +#endif + +#endif /* WOLFSSL_VERSAL_GEN2_ASU_HASH */ + +#endif /* WOLFSSL_VERSAL_GEN2_ASU_HASH_H */ diff --git a/wolfssl/wolfcrypt/port/xilinx/versal_gen2_asu/asu_hmac.h b/wolfssl/wolfcrypt/port/xilinx/versal_gen2_asu/asu_hmac.h new file mode 100644 index 00000000000..d39498508a2 --- /dev/null +++ b/wolfssl/wolfcrypt/port/xilinx/versal_gen2_asu/asu_hmac.h @@ -0,0 +1,55 @@ +/* asu_hmac.h + * + * Copyright (C) 2006-2026 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +/* ASU HMAC for the wolfSSL crypto callback: HMAC over SHA2 256/384/512 and SHA3 + * 256/384/512. The message is accumulated per HMAC context and the whole HMAC is + * produced in a single ASU operation at finalize. See asu_hmac.c for why. */ + +#ifndef WOLFSSL_VERSAL_GEN2_ASU_HMAC_H +#define WOLFSSL_VERSAL_GEN2_ASU_HMAC_H + +#include + +#ifdef WOLFSSL_VERSAL_GEN2_ASU_HMAC + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Single entry point for the HMAC engine. The crypto callback dispatcher routes + * every HMAC related operation here and this handler decides which it is: update + * and final (WC_ALGO_TYPE_HMAC), context copy (WC_ALGO_TYPE_COPY) or context + * free (WC_ALGO_TYPE_FREE). The message is accumulated per context and the HMAC + * is computed in one ASU operation at final using the raw key wolfSSL keeps on + * the context. Supports HMAC over SHA2 256/384/512 and SHA3 256/384/512. Returns + * 0 on success, CRYPTOCB_UNAVAILABLE for an unsupported MAC type or key (software + * fallback), or a negative error. */ +WOLFSSL_LOCAL int wc_AsuHmac(wc_CryptoInfo* info); + +#ifdef __cplusplus +} +#endif + +#endif /* WOLFSSL_VERSAL_GEN2_ASU_HMAC */ + +#endif /* WOLFSSL_VERSAL_GEN2_ASU_HMAC_H */ diff --git a/wolfssl/wolfcrypt/port/xilinx/versal_gen2_asu/asu_rng.h b/wolfssl/wolfcrypt/port/xilinx/versal_gen2_asu/asu_rng.h new file mode 100644 index 00000000000..0b83d7493f5 --- /dev/null +++ b/wolfssl/wolfcrypt/port/xilinx/versal_gen2_asu/asu_rng.h @@ -0,0 +1,53 @@ +/* asu_rng.h + * + * Copyright (C) 2006-2026 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +/* ASU TRNG entropy for the wolfSSL crypto callback. Seeds the wolfCrypt Hash + * DRBG from the ASU true random number generator. */ + +#ifndef WOLFSSL_VERSAL_GEN2_ASU_RNG_H +#define WOLFSSL_VERSAL_GEN2_ASU_RNG_H + +#include + +#ifdef WOLFSSL_VERSAL_GEN2_ASU_TRNG + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* Single entry point for the ASU TRNG. The crypto callback dispatcher routes + * both random number operations here and this handler decides which it is: seed + * a DRBG (WC_ALGO_TYPE_SEED, fills info->seed) or serve random blocks + * (WC_ALGO_TYPE_RNG, fills info->rng). The ASU TRNG returns at most one strength + * block (32 bytes) per call, so larger requests are filled over several ASU + * transactions. Returns 0 on success, CRYPTOCB_UNAVAILABLE for an unsupported + * operation, or a negative error. */ +WOLFSSL_LOCAL int wc_AsuRng(wc_CryptoInfo* info); + +#ifdef __cplusplus +} +#endif + +#endif /* WOLFSSL_VERSAL_GEN2_ASU_TRNG */ + +#endif /* WOLFSSL_VERSAL_GEN2_ASU_RNG_H */ diff --git a/wolfssl/wolfcrypt/port/xilinx/versal_gen2_asu/asu_settings.h b/wolfssl/wolfcrypt/port/xilinx/versal_gen2_asu/asu_settings.h new file mode 100644 index 00000000000..c4eaa86770c --- /dev/null +++ b/wolfssl/wolfcrypt/port/xilinx/versal_gen2_asu/asu_settings.h @@ -0,0 +1,112 @@ +/* asu_settings.h + * + * Copyright (C) 2006-2026 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +/* Compile time configuration for the Versal Gen2 ASU port. This header holds + * only preprocessor macros and pulls in no BSP headers, so wolfSSL settings.h + * can include it to select engines and map WC_USE_DEVID before the unmodified + * wolfcrypt test and benchmark read it. + * + * Engine selection: + * WOLFSSL_VERSAL_GEN2_ASU enables the port and must always be defined in + * user_settings.h. With only that defined, every supported engine is + * offloaded. To offload a subset, also define one or more of the engine + * macros below, in which case only those are offloaded: + * WOLFSSL_VERSAL_GEN2_ASU_TRNG + * WOLFSSL_VERSAL_GEN2_ASU_HASH + * WOLFSSL_VERSAL_GEN2_ASU_HMAC + * WOLFSSL_VERSAL_GEN2_ASU_AES + * WOLFSSL_VERSAL_GEN2_ASU_CMAC + * WOLFSSL_VERSAL_GEN2_ASU_RSA + * WOLFSSL_VERSAL_GEN2_ASU_ECC + * An engine macro on its own does not enable the port. + */ + +#ifndef WOLFSSL_VERSAL_GEN2_ASU_SETTINGS_H +#define WOLFSSL_VERSAL_GEN2_ASU_SETTINGS_H + +#ifdef WOLFSSL_VERSAL_GEN2_ASU + +/* The port routes operations through the wolfSSL crypto callback framework. */ +#ifndef WOLF_CRYPTO_CB + #define WOLF_CRYPTO_CB +#endif + +/* If the port is on but no specific engine was requested, enable the full + * supported set. */ +#if !defined(WOLFSSL_VERSAL_GEN2_ASU_TRNG) && \ + !defined(WOLFSSL_VERSAL_GEN2_ASU_HASH) && \ + !defined(WOLFSSL_VERSAL_GEN2_ASU_HMAC) && \ + !defined(WOLFSSL_VERSAL_GEN2_ASU_AES) && \ + !defined(WOLFSSL_VERSAL_GEN2_ASU_CMAC) && \ + !defined(WOLFSSL_VERSAL_GEN2_ASU_RSA) && \ + !defined(WOLFSSL_VERSAL_GEN2_ASU_ECC) + #define WOLFSSL_VERSAL_GEN2_ASU_TRNG + #define WOLFSSL_VERSAL_GEN2_ASU_HASH + #define WOLFSSL_VERSAL_GEN2_ASU_HMAC + #define WOLFSSL_VERSAL_GEN2_ASU_AES + #define WOLFSSL_VERSAL_GEN2_ASU_CMAC + #define WOLFSSL_VERSAL_GEN2_ASU_RSA + #define WOLFSSL_VERSAL_GEN2_ASU_ECC +#endif + +/* Device id used to register and route to the ASU crypto callback. Override by + * defining WOLFSSL_VERSAL_GEN2_ASU_DEVID (or WC_USE_DEVID) in user_settings.h + * before settings.h. Any int other than INVALID_DEVID (-2) is valid; this is an + * identifier, not an address or index. */ +#ifndef WOLFSSL_VERSAL_GEN2_ASU_DEVID + #define WOLFSSL_VERSAL_GEN2_ASU_DEVID 0x4153 /* 'AS' for ASU */ +#endif + +/* Let the unmodified wolfcrypt test and benchmark route every operation through + * this device by giving their devId the ASU value. */ +#ifndef WC_USE_DEVID + #define WC_USE_DEVID WOLFSSL_VERSAL_GEN2_ASU_DEVID +#endif + +/* When the timer and RTC are turned on (WOLFSSL_VERSAL_GEN2_ASU_RTC in + * user_settings.h), supply the benchmark current_time() hook from the port. */ +#ifdef WOLFSSL_VERSAL_GEN2_ASU_RTC + #ifndef WOLFSSL_USER_CURRTIME + #define WOLFSSL_USER_CURRTIME + #endif +#endif + +/* Mirror the application data cache switch into a port owned macro so the port + * translation units do not depend on the application macro name. When + * XASU_DISABLE_CACHE is set globally the data cache is off, so the port skips + * buffer maintenance; otherwise it cleans inputs and invalidates outputs. */ +#ifdef XASU_DISABLE_CACHE + #ifndef WC_ASU_DISABLE_CACHE + #define WC_ASU_DISABLE_CACHE + #endif +#endif + +/* Threading. The ticketing concurrency that lets several threads keep the ASU + * queue busy is compiled out for a single threaded build, which instead uses + * the wolfSSL crypto hardware mutex. Derived from SINGLE_THREADED. */ +#ifdef SINGLE_THREADED + #undef WOLFSSL_VERSAL_GEN2_ASU_SINGLE_THREADED + #define WOLFSSL_VERSAL_GEN2_ASU_SINGLE_THREADED +#endif + +#endif /* WOLFSSL_VERSAL_GEN2_ASU */ + +#endif /* WOLFSSL_VERSAL_GEN2_ASU_SETTINGS_H */ diff --git a/wolfssl/wolfcrypt/port/xilinx/versal_gen2_asu/asu_util.h b/wolfssl/wolfcrypt/port/xilinx/versal_gen2_asu/asu_util.h new file mode 100644 index 00000000000..3fd2c13e023 --- /dev/null +++ b/wolfssl/wolfcrypt/port/xilinx/versal_gen2_asu/asu_util.h @@ -0,0 +1,128 @@ +/* asu_util.h + * + * Copyright (C) 2006-2026 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +/* Shared helpers for the Versal Gen2 ASU port: the asynchronous request to + * synchronous completion bridge and cache maintenance for ASU buffers. */ + +#ifndef WOLFSSL_VERSAL_GEN2_ASU_UTIL_H +#define WOLFSSL_VERSAL_GEN2_ASU_UTIL_H + +#include + +#ifdef WOLFSSL_VERSAL_GEN2_ASU + +#include +#include "xasu_client.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Debug print to confirm operations are going through the ASU port. Enable by + * defining WOLFSSL_VERSAL_GEN2_ASU_DEBUG in user_settings.h. Prints over the + * standalone console (xil_printf); compiles out otherwise. */ +#ifdef WOLFSSL_VERSAL_GEN2_ASU_DEBUG + #include "xil_printf.h" + #define WC_ASU_PRINTF(...) xil_printf(__VA_ARGS__) +#else + #define WC_ASU_PRINTF(...) ((void)0) +#endif + +/* Completion record for one asynchronous ASU request. The ASU client invokes + * the shared response handler from its mailbox path, which fills this record; + * the submitting code then spins until Done is set. */ +typedef struct AsuWait { + volatile byte Done; /* set when the response handler has run */ + volatile word32 Status; /* server status captured by the handler */ +} AsuWait; + +/* Initialize Wait and point ClientParams at the shared response handler. The + * request is configured as high priority and secure by default. */ +WOLFSSL_LOCAL void wc_AsuWaitPrepare(AsuWait* wait, XAsu_ClientParams* params); + +/* Block until the request bound to Wait completes and return the server + * status. Single threaded baremetal client, so a busy wait is correct. */ +WOLFSSL_LOCAL word32 wc_AsuWaitDone(AsuWait* wait); + +/* Clean a buffer out to memory so the ASU sees the latest CPU writes. */ +WOLFSSL_LOCAL void wc_AsuCacheFlush(const void* addr, word32 len); + +/* Invalidate a buffer so the CPU reads what the ASU wrote to memory. */ +WOLFSSL_LOCAL void wc_AsuCacheInvalidate(void* addr, word32 len); + + +/* ----------------------------------------------------------------------- */ +/* Transaction and concurrency (ticketing) */ +/* ----------------------------------------------------------------------- */ +/* Submit function for one ASU transaction. The implementation fills its + * request from ctx and calls the matching XAsu_* client API with the prepared + * ClientParams, returning the client submission status (XST_SUCCESS when the + * request was queued). It is called with the submit lock held, so it must only + * queue the request, never wait. */ +typedef int (*AsuSubmitFn)(XAsu_ClientParams* params, void* ctx); + +/* Run one ASU transaction and return the server status (XST_SUCCESS on success, + * otherwise a failure status). If additionalStatus is not NULL it receives the + * server AdditionalStatus field, used by operations like AES GCM tag checks. + * + * With WOLFSSL_VERSAL_GEN2_ASU_SINGLE_THREADED this is submit then wait under + * the wolfSSL crypto hardware mutex. Otherwise it takes a FIFO ticket, submits + * under the short submit lock so the non thread safe client allocation is + * serialized, hands the turn to the next waiter, then waits on its own + * completion outside the lock, so up to the ASU queue depth of requests run + * concurrently across threads. */ +WOLFSSL_LOCAL word32 wc_AsuTransact(AsuSubmitFn submit, void* ctx, + word32* additionalStatus); + + +/* ----------------------------------------------------------------------- */ +/* Timer and RTC (optional, for benchmarking) */ +/* ----------------------------------------------------------------------- */ +/* The entire timer and RTC facility is gated by WOLFSSL_VERSAL_GEN2_ASU_RTC, + * turned on in user_settings.h, so it compiles out completely for a build that + * does not benchmark. When enabled it provides the benchmark current_time() + * hook from the Cortex A78 generic timer and an optional system RTC wall clock + * read. */ +#ifdef WOLFSSL_VERSAL_GEN2_ASU_RTC + +/* Bring up the time source. Returns 0 on success. */ +WOLFSSL_LOCAL int wc_AsuTimerInit(void); + +/* Raw monotonic count from the generic timer. */ +WOLFSSL_LOCAL word64 wc_AsuTimerCount(void); + +/* Monotonic time in seconds from the generic timer. This is what the benchmark + * current_time() hook reports. */ +WOLFSSL_LOCAL double wc_AsuTimerSeconds(void); + +/* Wall clock time in seconds from the system RTC. One second resolution, so it + * is for timestamps, not per operation timing. */ +WOLFSSL_LOCAL word32 wc_AsuRtcSeconds(void); + +#endif /* WOLFSSL_VERSAL_GEN2_ASU_RTC */ + +#ifdef __cplusplus +} +#endif + +#endif /* WOLFSSL_VERSAL_GEN2_ASU */ + +#endif /* WOLFSSL_VERSAL_GEN2_ASU_UTIL_H */ diff --git a/wolfssl/wolfcrypt/settings.h b/wolfssl/wolfcrypt/settings.h index 9f699145847..40e3c47c3e5 100644 --- a/wolfssl/wolfcrypt/settings.h +++ b/wolfssl/wolfcrypt/settings.h @@ -380,6 +380,13 @@ #endif #endif +/* Versal Gen2 ASU port: enable the crypto callback and map WC_USE_DEVID before + * the rest of settings.h and before the unmodified test and benchmark read it. + * This header is macro only and pulls in no BSP dependencies. */ +#if defined(WOLFSSL_VERSAL_GEN2_ASU) + #include +#endif + /* Forward propagation of the legacy parent gate to the canonical name * (HAVE_DILITHIUM -> WOLFSSL_HAVE_MLDSA). Always active: required so that * a user_settings.h or build flag using only the legacy spelling still