Merge pull request #10765 from night1rider/Xilinx-ASU-TRNG-Hashes-HMAC

Xilinx Versal Gen2 ASU port: TRNG, hashes, HMAC offload
This commit is contained in:
JacobBarthelmeh
2026-07-22 15:27:58 -06:00
committed by GitHub
15 changed files with 2009 additions and 0 deletions
+3
View File
@@ -1047,6 +1047,8 @@ WOLFSSL_USE_FLASHMEM
WOLFSSL_USE_FORCE_ZERO
WOLFSSL_USE_OPTIONS_H
WOLFSSL_VALIDATE_DH_KEYGEN
WOLFSSL_VERSAL_GEN2_ASU
WOLFSSL_VERSAL_GEN2_ASU_RTC
WOLFSSL_WC_SLHDSA_RECURSIVE
WOLFSSL_WC_XMSS_NO_SHA256
WOLFSSL_WICED_PSEUDO_UNIX_EPOCH_TIME
@@ -1074,6 +1076,7 @@ WOLF_CRYPTO_DEV
WOLF_CRYPT_FIPS_H
WOLF_NO_TRAILING_ENUM_COMMAS
WindowsCE
XASU_DISABLE_CACHE
XGETPASSWD
XMSS_CALL_PRF_KEYGEN
XPAR_VERSAL_CIPS_0_PSPMC_0_PSV_CORTEXA72_0_TIMESTAMP_CLK_FREQ
+32
View File
@@ -392,6 +392,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;
@@ -1583,6 +1600,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) {
@@ -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 <config.h>
#endif
#include <wolfssl/wolfcrypt/settings.h>
#ifdef WOLFSSL_VERSAL_GEN2_ASU
#include <wolfssl/wolfcrypt/port/xilinx/versal_gen2_asu/asu_cryptocb.h>
#include <wolfssl/wolfcrypt/error-crypt.h>
#include <wolfssl/wolfcrypt/logging.h>
#ifdef WOLFSSL_VERSAL_GEN2_ASU_TRNG
#include <wolfssl/wolfcrypt/port/xilinx/versal_gen2_asu/asu_rng.h>
#endif
#ifdef WOLFSSL_VERSAL_GEN2_ASU_HASH
#include <wolfssl/wolfcrypt/port/xilinx/versal_gen2_asu/asu_hash.h>
#endif
#ifdef WOLFSSL_VERSAL_GEN2_ASU_HMAC
#include <wolfssl/wolfcrypt/port/xilinx/versal_gen2_asu/asu_hmac.h>
#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 */
@@ -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 <config.h>
#endif
#include <wolfssl/wolfcrypt/settings.h>
#ifdef WOLFSSL_VERSAL_GEN2_ASU_HASH
#include <wolfssl/wolfcrypt/port/xilinx/versal_gen2_asu/asu_hash.h>
#include <wolfssl/wolfcrypt/port/xilinx/versal_gen2_asu/asu_util.h>
#include <wolfssl/wolfcrypt/error-crypt.h>
#include <wolfssl/wolfcrypt/hash.h>
#include <wolfssl/wolfcrypt/sha256.h>
#include <wolfssl/wolfcrypt/sha512.h>
#include <wolfssl/wolfcrypt/sha3.h>
#ifdef NO_INLINE
#include <wolfssl/wolfcrypt/misc.h>
#else
#define WOLFSSL_MISC_INCLUDED
#include <wolfcrypt/src/misc.c>
#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 */
@@ -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 <config.h>
#endif
#include <wolfssl/wolfcrypt/settings.h>
#ifdef WOLFSSL_VERSAL_GEN2_ASU_HMAC
#include <wolfssl/wolfcrypt/port/xilinx/versal_gen2_asu/asu_hmac.h>
#include <wolfssl/wolfcrypt/port/xilinx/versal_gen2_asu/asu_util.h>
#include <wolfssl/wolfcrypt/error-crypt.h>
#include <wolfssl/wolfcrypt/hash.h>
#include <wolfssl/wolfcrypt/hmac.h>
#include <wolfssl/wolfcrypt/sha256.h>
#include <wolfssl/wolfcrypt/sha512.h>
#include <wolfssl/wolfcrypt/sha3.h>
#ifdef NO_INLINE
#include <wolfssl/wolfcrypt/misc.h>
#else
#define WOLFSSL_MISC_INCLUDED
#include <wolfcrypt/src/misc.c>
#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 */
@@ -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 <config.h>
#endif
#include <wolfssl/wolfcrypt/settings.h>
#ifdef WOLFSSL_VERSAL_GEN2_ASU_TRNG
#include <wolfssl/wolfcrypt/port/xilinx/versal_gen2_asu/asu_rng.h>
#include <wolfssl/wolfcrypt/port/xilinx/versal_gen2_asu/asu_util.h>
#include <wolfssl/wolfcrypt/error-crypt.h>
#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 */
@@ -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 <config.h>
#endif
#include <wolfssl/wolfcrypt/settings.h>
#ifdef WOLFSSL_VERSAL_GEN2_ASU
#include <wolfssl/wolfcrypt/port/xilinx/versal_gen2_asu/asu_util.h>
#include <wolfssl/wolfcrypt/error-crypt.h>
#include <wolfssl/wolfcrypt/wc_port.h>
#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, &params);
wolfSSL_CryptHwMutexLock();
status = submit(&params, 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 */
+14
View File
@@ -194,6 +194,10 @@ Threading/Mutex options:
#include <wolfssl/wolfcrypt/cryptocb.h>
#endif
#if defined(WOLFSSL_VERSAL_GEN2_ASU)
#include <wolfssl/wolfcrypt/port/xilinx/versal_gen2_asu/asu_cryptocb.h>
#endif
#ifdef HAVE_INTEL_QA_SYNC
#include <wolfssl/wolfcrypt/port/intel/quickassist_sync.h>
#endif
@@ -572,6 +576,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) {
@@ -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 <wolfssl/wolfcrypt/settings.h>
#ifdef WOLFSSL_VERSAL_GEN2_ASU
#include <wolfssl/wolfcrypt/cryptocb.h>
#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 */
@@ -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 <wolfssl/wolfcrypt/settings.h>
#ifdef WOLFSSL_VERSAL_GEN2_ASU_HASH
#include <wolfssl/wolfcrypt/cryptocb.h>
#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 release (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 */
@@ -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 <wolfssl/wolfcrypt/settings.h>
#ifdef WOLFSSL_VERSAL_GEN2_ASU_HMAC
#include <wolfssl/wolfcrypt/cryptocb.h>
#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
* release (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 */
@@ -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 <wolfssl/wolfcrypt/settings.h>
#ifdef WOLFSSL_VERSAL_GEN2_ASU_TRNG
#include <wolfssl/wolfcrypt/cryptocb.h>
#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 */
@@ -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 */
@@ -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 <wolfssl/wolfcrypt/settings.h>
#ifdef WOLFSSL_VERSAL_GEN2_ASU
#include <wolfssl/wolfcrypt/types.h>
#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 */
+7
View File
@@ -389,6 +389,13 @@
#define __aarch64__ 1
#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 <wolfssl/wolfcrypt/port/xilinx/versal_gen2_asu/asu_settings.h>
#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