mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2026-01-27 06:52:21 +01:00
1159 lines
30 KiB
C
1159 lines
30 KiB
C
/* async.c
|
|
*
|
|
* Copyright (C) 2006-2023 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
|
|
*/
|
|
|
|
#include <wolfssl/wolfcrypt/libwolfssl_sources.h>
|
|
|
|
#ifdef WOLFSSL_ASYNC_CRYPT
|
|
|
|
#include <wolfssl/internal.h>
|
|
#include <wolfssl/error-ssl.h>
|
|
|
|
#include <wolfssl/wolfcrypt/async.h>
|
|
|
|
|
|
static WC_ASYNC_DEV* wolfAsync_GetDev(WOLF_EVENT* event)
|
|
{
|
|
WC_ASYNC_DEV* dev = NULL;
|
|
|
|
if (event && event->context) {
|
|
switch (event->type) {
|
|
/* context is WOLFSSL* */
|
|
case WOLF_EVENT_TYPE_ASYNC_WOLFSSL:
|
|
{
|
|
WOLFSSL* ssl = (WOLFSSL*)event->context;
|
|
dev = ssl->asyncDev;
|
|
break;
|
|
}
|
|
|
|
/* context is WC_ASYNC_DEV */
|
|
case WOLF_EVENT_TYPE_ASYNC_WOLFCRYPT:
|
|
{
|
|
dev = (WC_ASYNC_DEV*)event->context;
|
|
break;
|
|
}
|
|
|
|
case WOLF_EVENT_TYPE_NONE:
|
|
default:
|
|
WOLFSSL_MSG("Unhandled event->type context!");
|
|
dev = NULL;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return dev;
|
|
}
|
|
|
|
|
|
#if defined(WOLFSSL_ASYNC_CRYPT_SW)
|
|
|
|
/* Allow way to have async SW code included, and disabled at run-time */
|
|
static int wolfAsyncSwDisabled = 0; /* default off */
|
|
|
|
|
|
static int wolfAsync_DoSw(WC_ASYNC_DEV* asyncDev)
|
|
{
|
|
int ret = 0;
|
|
WC_ASYNC_SW* sw;
|
|
|
|
if (asyncDev == NULL) {
|
|
return BAD_FUNC_ARG;
|
|
}
|
|
sw = &asyncDev->sw;
|
|
|
|
switch (sw->type) {
|
|
#ifdef HAVE_ECC
|
|
case ASYNC_SW_ECC_MAKE:
|
|
{
|
|
ret = wc_ecc_make_key_ex(
|
|
(WC_RNG*)sw->eccMake.rng,
|
|
sw->eccMake.size,
|
|
(ecc_key*)sw->eccMake.key,
|
|
sw->eccMake.curve_id
|
|
);
|
|
break;
|
|
}
|
|
#ifdef HAVE_ECC_SIGN
|
|
case ASYNC_SW_ECC_SIGN:
|
|
{
|
|
ret = wc_ecc_sign_hash_ex(
|
|
sw->eccSign.in,
|
|
sw->eccSign.inSz,
|
|
(WC_RNG*)sw->eccSign.rng,
|
|
(ecc_key*)sw->eccSign.key,
|
|
(mp_int*)sw->eccSign.r,
|
|
(mp_int*)sw->eccSign.s
|
|
);
|
|
break;
|
|
}
|
|
#endif /* HAVE_ECC_SIGN */
|
|
#ifdef HAVE_ECC_VERIFY
|
|
case ASYNC_SW_ECC_VERIFY:
|
|
{
|
|
ret = wc_ecc_verify_hash_ex(
|
|
(mp_int*)sw->eccVerify.r,
|
|
(mp_int*)sw->eccVerify.s,
|
|
sw->eccVerify.hash,
|
|
sw->eccVerify.hashlen,
|
|
sw->eccVerify.stat,
|
|
(ecc_key*)sw->eccVerify.key
|
|
);
|
|
break;
|
|
}
|
|
#endif /* HAVE_ECC_VERIFY */
|
|
#ifdef HAVE_ECC_DHE
|
|
case ASYNC_SW_ECC_SHARED_SEC:
|
|
{
|
|
ret = wc_ecc_shared_secret_gen_sync(
|
|
(ecc_key*)sw->eccSharedSec.private_key,
|
|
(ecc_point*)sw->eccSharedSec.public_point,
|
|
sw->eccSharedSec.out,
|
|
sw->eccSharedSec.outLen
|
|
);
|
|
break;
|
|
}
|
|
#endif /* HAVE_ECC_DHE */
|
|
#endif /* HAVE_ECC */
|
|
#ifndef NO_RSA
|
|
#ifdef WOLFSSL_KEY_GEN
|
|
case ASYNC_SW_RSA_MAKE:
|
|
{
|
|
ret = wc_MakeRsaKey(
|
|
(RsaKey*)sw->rsaMake.key,
|
|
sw->rsaMake.size,
|
|
sw->rsaMake.e,
|
|
(WC_RNG*)sw->rsaMake.rng
|
|
);
|
|
break;
|
|
}
|
|
#endif /* WOLFSSL_KEY_GEN */
|
|
case ASYNC_SW_RSA_FUNC:
|
|
{
|
|
ret = wc_RsaFunction(
|
|
sw->rsaFunc.in,
|
|
sw->rsaFunc.inSz,
|
|
sw->rsaFunc.out,
|
|
sw->rsaFunc.outSz,
|
|
sw->rsaFunc.type,
|
|
(RsaKey*)sw->rsaFunc.key,
|
|
(WC_RNG*)sw->rsaFunc.rng
|
|
);
|
|
break;
|
|
}
|
|
#endif /* !NO_RSA */
|
|
#ifndef NO_DH
|
|
case ASYNC_SW_DH_AGREE:
|
|
{
|
|
ret = wc_DhAgree(
|
|
(DhKey*)sw->dhAgree.key,
|
|
sw->dhAgree.agree,
|
|
sw->dhAgree.agreeSz,
|
|
sw->dhAgree.priv,
|
|
sw->dhAgree.privSz,
|
|
sw->dhAgree.otherPub,
|
|
sw->dhAgree.pubSz
|
|
);
|
|
break;
|
|
}
|
|
case ASYNC_SW_DH_GEN:
|
|
{
|
|
ret = wc_DhGenerateKeyPair(
|
|
(DhKey*)sw->dhGen.key,
|
|
(WC_RNG*)sw->dhGen.rng,
|
|
sw->dhGen.priv,
|
|
sw->dhGen.privSz,
|
|
sw->dhGen.pub,
|
|
sw->dhGen.pubSz
|
|
);
|
|
break;
|
|
}
|
|
#endif /* !NO_DH */
|
|
#ifndef NO_AES
|
|
case ASYNC_SW_AES_CBC_ENCRYPT:
|
|
{
|
|
ret = wc_AesCbcEncrypt(
|
|
(Aes*)sw->aes.aes,
|
|
sw->aes.out,
|
|
sw->aes.in,
|
|
sw->aes.sz
|
|
);
|
|
break;
|
|
}
|
|
#ifdef HAVE_AES_DECRYPT
|
|
case ASYNC_SW_AES_CBC_DECRYPT:
|
|
{
|
|
ret = wc_AesCbcDecrypt(
|
|
(Aes*)sw->aes.aes,
|
|
sw->aes.out,
|
|
sw->aes.in,
|
|
sw->aes.sz
|
|
);
|
|
break;
|
|
}
|
|
#endif /* HAVE_AES_DECRYPT */
|
|
|
|
#ifdef HAVE_AESGCM
|
|
case ASYNC_SW_AES_GCM_ENCRYPT:
|
|
{
|
|
ret = wc_AesGcmEncrypt(
|
|
(Aes*)sw->aes.aes,
|
|
sw->aes.out,
|
|
sw->aes.in,
|
|
sw->aes.sz,
|
|
sw->aes.iv,
|
|
sw->aes.ivSz,
|
|
sw->aes.authTag,
|
|
sw->aes.authTagSz,
|
|
sw->aes.authIn,
|
|
sw->aes.authInSz
|
|
);
|
|
break;
|
|
}
|
|
#ifdef HAVE_AES_DECRYPT
|
|
case ASYNC_SW_AES_GCM_DECRYPT:
|
|
{
|
|
ret = wc_AesGcmDecrypt(
|
|
(Aes*)sw->aes.aes,
|
|
sw->aes.out,
|
|
sw->aes.in,
|
|
sw->aes.sz,
|
|
sw->aes.iv,
|
|
sw->aes.ivSz,
|
|
sw->aes.authTag,
|
|
sw->aes.authTagSz,
|
|
sw->aes.authIn,
|
|
sw->aes.authInSz
|
|
);
|
|
break;
|
|
}
|
|
#endif /* HAVE_AES_DECRYPT */
|
|
#endif /* HAVE_AESGCM */
|
|
#endif /* !NO_AES */
|
|
#ifndef NO_DES3
|
|
case ASYNC_SW_DES3_CBC_ENCRYPT:
|
|
{
|
|
ret = wc_Des3_CbcEncrypt(
|
|
(Des3*)sw->des.des,
|
|
sw->des.out,
|
|
sw->des.in,
|
|
sw->des.sz
|
|
);
|
|
break;
|
|
}
|
|
case ASYNC_SW_DES3_CBC_DECRYPT:
|
|
{
|
|
ret = wc_Des3_CbcDecrypt(
|
|
(Des3*)sw->des.des,
|
|
sw->des.out,
|
|
sw->des.in,
|
|
sw->des.sz
|
|
);
|
|
break;
|
|
}
|
|
#endif /* !NO_DES3 */
|
|
default:
|
|
WOLFSSL_MSG("Invalid async crypt SW type!");
|
|
ret = BAD_FUNC_ARG;
|
|
break;
|
|
};
|
|
|
|
/* Reset test type */
|
|
if (ret == FP_WOULDBLOCK) {
|
|
ret = WC_PENDING_E;
|
|
}
|
|
else if (ret == 0) {
|
|
sw->type = ASYNC_SW_NONE;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int wc_AsyncSwInit(WC_ASYNC_DEV* dev, int type)
|
|
{
|
|
if (dev) {
|
|
WC_ASYNC_SW* sw = &dev->sw;
|
|
if (sw->type == ASYNC_SW_NONE) {
|
|
sw->type = type;
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#endif /* WOLFSSL_ASYNC_CRYPT_SW */
|
|
|
|
int wolfAsync_DevOpenThread(int *pDevId, void* threadId)
|
|
{
|
|
int ret = 0;
|
|
int devId = INVALID_DEVID;
|
|
|
|
#ifdef HAVE_CAVIUM
|
|
ret = NitroxOpenDeviceDefault();
|
|
if (ret >= 0)
|
|
devId = ret;
|
|
else
|
|
ret = ASYNC_INIT_E;
|
|
#elif defined(HAVE_INTEL_QA)
|
|
ret = IntelQaInit(threadId);
|
|
if (ret >= 0)
|
|
devId = ret;
|
|
else
|
|
ret = ASYNC_INIT_E;
|
|
#elif defined(WOLFSSL_ASYNC_CRYPT_SW)
|
|
if (!wolfAsyncSwDisabled) {
|
|
/* For SW use any value 0 or greater */
|
|
devId = 0;
|
|
}
|
|
#endif
|
|
|
|
(void)threadId;
|
|
|
|
/* return devId if requested */
|
|
if (*pDevId)
|
|
*pDevId = devId;
|
|
|
|
return ret;
|
|
}
|
|
|
|
int wolfAsync_HardwareStart(void)
|
|
{
|
|
int ret = 0;
|
|
|
|
#ifdef HAVE_CAVIUM
|
|
/* nothing to do */
|
|
#elif defined(HAVE_INTEL_QA)
|
|
ret = IntelQaHardwareStart(QAT_PROCESS_NAME, QAT_LIMIT_DEV_ACCESS);
|
|
#endif
|
|
|
|
return ret;
|
|
}
|
|
|
|
void wolfAsync_HardwareStop(void)
|
|
{
|
|
#ifdef HAVE_CAVIUM
|
|
/* nothing to do */
|
|
#elif defined(HAVE_INTEL_QA)
|
|
IntelQaHardwareStop();
|
|
#endif
|
|
}
|
|
|
|
int wolfAsync_DevOpen(int *devId)
|
|
{
|
|
return wolfAsync_DevOpenThread(devId, NULL);
|
|
}
|
|
|
|
void wolfAsync_DevClose(int *devId)
|
|
{
|
|
if (devId && *devId != INVALID_DEVID) {
|
|
#ifdef HAVE_CAVIUM
|
|
NitroxCloseDevice(*devId);
|
|
#elif defined(HAVE_INTEL_QA)
|
|
IntelQaDeInit(*devId);
|
|
#endif
|
|
*devId = INVALID_DEVID;
|
|
}
|
|
}
|
|
|
|
int wolfAsync_DevCtxInit(WC_ASYNC_DEV* asyncDev, word32 marker, void* heap,
|
|
int devId)
|
|
{
|
|
int ret = 0;
|
|
|
|
if (asyncDev == NULL) {
|
|
return BAD_FUNC_ARG;
|
|
}
|
|
|
|
/* always clear async device context */
|
|
XMEMSET(asyncDev, 0, sizeof(WC_ASYNC_DEV));
|
|
|
|
/* negative device Id's are invalid */
|
|
if (devId >= 0) {
|
|
asyncDev->marker = marker;
|
|
asyncDev->heap = heap;
|
|
|
|
#ifdef HAVE_CAVIUM
|
|
ret = NitroxAllocContext(asyncDev, devId, CONTEXT_SSL);
|
|
#elif defined(HAVE_INTEL_QA)
|
|
ret = IntelQaOpen(asyncDev, devId);
|
|
#endif
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
void wolfAsync_DevCtxFree(WC_ASYNC_DEV* asyncDev, word32 marker)
|
|
{
|
|
if (asyncDev && asyncDev->marker == marker) {
|
|
#ifdef HAVE_CAVIUM
|
|
NitroxFreeContext(asyncDev);
|
|
#elif defined(HAVE_INTEL_QA)
|
|
IntelQaClose(asyncDev);
|
|
#endif
|
|
asyncDev->marker = WOLFSSL_ASYNC_MARKER_INVALID;
|
|
}
|
|
}
|
|
|
|
int wolfAsync_DevCopy(WC_ASYNC_DEV* src, WC_ASYNC_DEV* dst)
|
|
{
|
|
int ret = 0;
|
|
|
|
if (src == NULL || dst == NULL)
|
|
return BAD_FUNC_ARG;
|
|
|
|
/* make sure we aren't copying to self */
|
|
if (src == dst)
|
|
return ret;
|
|
|
|
#ifdef HAVE_CAVIUM
|
|
/* nothing to do here */
|
|
#elif defined(HAVE_INTEL_QA)
|
|
ret = IntelQaDevCopy(src, dst);
|
|
#endif
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* called from `wolfSSL_AsyncPop` to check if event is done and deliver
|
|
* async return code */
|
|
int wolfAsync_EventPop(WOLF_EVENT* event, enum WOLF_EVENT_TYPE event_type)
|
|
{
|
|
int ret;
|
|
|
|
if (event == NULL) {
|
|
return BAD_FUNC_ARG;
|
|
}
|
|
|
|
if (event->type == event_type) {
|
|
/* Trap the scenario where event is not done */
|
|
if (event->state == WOLF_EVENT_STATE_PENDING) {
|
|
return WC_PENDING_E;
|
|
}
|
|
|
|
/* Get async return code */
|
|
ret = event->ret;
|
|
|
|
/* Reset state */
|
|
event->state = WOLF_EVENT_STATE_READY;
|
|
}
|
|
else {
|
|
ret = WC_NO_PENDING_E;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int wolfAsync_EventQueuePush(WOLF_EVENT_QUEUE* queue, WOLF_EVENT* event)
|
|
{
|
|
if (queue == NULL) {
|
|
return BAD_FUNC_ARG;
|
|
}
|
|
|
|
/* Setup event and push to event queue */
|
|
event->dev.async = wolfAsync_GetDev(event);
|
|
return wolfEventQueue_Push(queue, event);
|
|
}
|
|
|
|
#ifdef HAVE_CAVIUM
|
|
static int wolfAsync_NitroxCheckReq(WC_ASYNC_DEV* asyncDev, WOLF_EVENT* event)
|
|
{
|
|
int ret;
|
|
|
|
/* populate event requestId */
|
|
event->reqId = asyncDev->nitrox.reqId;
|
|
if (event->reqId == 0)
|
|
return WC_INIT_E;
|
|
|
|
/* poll specific request */
|
|
ret = NitroxCheckRequest(asyncDev, event);
|
|
|
|
#ifdef WOLFSSL_NITROX_DEBUG
|
|
if (event->ret == WC_NO_ERR_TRACE(WC_PENDING_E))
|
|
event->pendCount++;
|
|
else
|
|
printf("NitroxCheckRequest: ret %x, req %lx, count %u\n",
|
|
ret,
|
|
event->reqId,
|
|
event->pendCount);
|
|
#else
|
|
(void)ret;
|
|
#endif
|
|
|
|
/* if not pending then clear requestId */
|
|
if (event->ret != WC_NO_ERR_TRACE(WC_PENDING_E)) {
|
|
event->reqId = 0;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif /* HAVE_CAVIUM */
|
|
|
|
int wolfAsync_EventPoll(WOLF_EVENT* event, WOLF_EVENT_FLAG flags)
|
|
{
|
|
int ret = 0;
|
|
WC_ASYNC_DEV* asyncDev;
|
|
|
|
(void)flags;
|
|
|
|
if (event == NULL) {
|
|
return BAD_FUNC_ARG;
|
|
}
|
|
asyncDev = event->dev.async;
|
|
if (asyncDev == NULL) {
|
|
return WC_INIT_E;
|
|
}
|
|
|
|
if (flags & WOLF_POLL_FLAG_CHECK_HW) {
|
|
#if defined(HAVE_CAVIUM)
|
|
ret = wolfAsync_NitroxCheckReq(asyncDev, event);
|
|
#elif defined(HAVE_INTEL_QA)
|
|
/* poll QAT hardware, callback returns data, IntelQaPoll sets event */
|
|
ret = IntelQaPoll(asyncDev);
|
|
#elif defined(WOLFSSL_ASYNC_CRYPT_SW)
|
|
event->ret = wolfAsync_DoSw(asyncDev);
|
|
#endif
|
|
|
|
/* If not pending then mark as done */
|
|
if (event->ret != WC_NO_ERR_TRACE(WC_PENDING_E)) {
|
|
event->state = WOLF_EVENT_STATE_DONE;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
#ifdef HAVE_CAVIUM
|
|
static int wolfAsync_NitroxCheckMultiReqBuf(WC_ASYNC_DEV* asyncDev,
|
|
WOLF_EVENT_QUEUE* queue, void* context_filter,
|
|
CspMultiRequestStatusBuffer* multi_req, int req_count)
|
|
{
|
|
WOLF_EVENT* event;
|
|
int ret = 0, i;
|
|
|
|
if (asyncDev == NULL || queue == NULL || multi_req == NULL) {
|
|
return BAD_FUNC_ARG;
|
|
}
|
|
|
|
/* Perform multi hardware poll */
|
|
ret = NitroxCheckRequests(asyncDev, multi_req);
|
|
if (ret != 0) {
|
|
return ret;
|
|
}
|
|
|
|
/* Iterate event queue */
|
|
for (event = queue->head; event != NULL; event = event->next) {
|
|
if (event->type >= WOLF_EVENT_TYPE_ASYNC_FIRST &&
|
|
event->type <= WOLF_EVENT_TYPE_ASYNC_LAST)
|
|
{
|
|
/* optional filter based on context */
|
|
if (context_filter == NULL || event->context == context_filter) {
|
|
/* find request */
|
|
for (i = 0; i < req_count; i++) {
|
|
if (event->reqId == multi_req->req[i].request_id) {
|
|
|
|
event->ret = NitroxTranslateResponseCode(
|
|
multi_req->req[i].status);
|
|
|
|
#ifdef WOLFSSL_NITROX_DEBUG
|
|
if (event->ret == WC_NO_ERR_TRACE(WC_PENDING_E))
|
|
event->pendCount++;
|
|
else
|
|
printf("NitroxCheckRequests: "
|
|
"ret %x, req %lx, count %u\n",
|
|
multi_req->req[i].status,
|
|
multi_req->req[i].request_id,
|
|
event->pendCount);
|
|
#endif
|
|
|
|
/* If not pending then mark as done */
|
|
if (event->ret != WC_NO_ERR_TRACE(WC_PENDING_E)) {
|
|
event->state = WOLF_EVENT_STATE_DONE;
|
|
event->reqId = 0;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* reset multi request buffer */
|
|
XMEMSET(multi_req, 0, sizeof(CspMultiRequestStatusBuffer));
|
|
multi_req->count = CAVIUM_MAX_POLL;
|
|
|
|
return ret;
|
|
}
|
|
#endif /* HAVE_CAVIUM */
|
|
|
|
int wolfAsync_EventQueuePoll(WOLF_EVENT_QUEUE* queue, void* context_filter,
|
|
WOLF_EVENT** events, int maxEvents, WOLF_EVENT_FLAG flags, int* eventCount)
|
|
{
|
|
WOLF_EVENT* event;
|
|
int ret = 0, count = 0;
|
|
WC_ASYNC_DEV* asyncDev = NULL;
|
|
#if defined(HAVE_CAVIUM)
|
|
CspMultiRequestStatusBuffer multi_req;
|
|
int req_count = 0;
|
|
|
|
/* reset multi request buffer */
|
|
XMEMSET(&multi_req, 0, sizeof(CspMultiRequestStatusBuffer));
|
|
multi_req.count = CAVIUM_MAX_POLL;
|
|
#endif
|
|
|
|
/* possible un-used variable */
|
|
(void)asyncDev;
|
|
|
|
if (queue == NULL) {
|
|
return BAD_FUNC_ARG;
|
|
}
|
|
|
|
#ifndef SINGLE_THREADED
|
|
/* In single threaded mode "event_queue.lock" doesn't exist */
|
|
if ((ret = wc_LockMutex(&queue->lock)) != 0) {
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
if (flags & WOLF_POLL_FLAG_CHECK_HW) {
|
|
/* check event queue */
|
|
for (event = queue->head; event != NULL; event = event->next) {
|
|
if (event->type >= WOLF_EVENT_TYPE_ASYNC_FIRST &&
|
|
event->type <= WOLF_EVENT_TYPE_ASYNC_LAST)
|
|
{
|
|
/* optional filter based on context */
|
|
if (context_filter == NULL ||
|
|
event->context == context_filter) {
|
|
asyncDev = event->dev.async;
|
|
|
|
if (asyncDev == NULL) {
|
|
ret = WC_INIT_E;
|
|
break;
|
|
}
|
|
|
|
count++;
|
|
|
|
#if defined(HAVE_CAVIUM)
|
|
/* populate event requestId */
|
|
event->reqId = asyncDev->nitrox.reqId;
|
|
|
|
/* add entry to multi-request buffer for polling */
|
|
if (event->reqId > 0) {
|
|
multi_req.req[req_count++].request_id = event->reqId;
|
|
}
|
|
/* submit filled multi-request query */
|
|
if (req_count == CAVIUM_MAX_POLL) {
|
|
ret = wolfAsync_NitroxCheckMultiReqBuf(asyncDev,
|
|
queue, context_filter, &multi_req, req_count);
|
|
if (ret != 0) {
|
|
break;
|
|
}
|
|
}
|
|
#else
|
|
#if defined(HAVE_INTEL_QA)
|
|
/* poll QAT hardware, callback returns data,
|
|
* IntelQaPoll sets event */
|
|
ret = IntelQaPoll(asyncDev);
|
|
if (ret != 0) {
|
|
break;
|
|
}
|
|
|
|
#elif defined(WOLFSSL_ASYNC_CRYPT_SW)
|
|
#ifdef WOLF_ASYNC_SW_SKIP_MOD
|
|
/* Simulate random hardware not done */
|
|
if (count % WOLF_ASYNC_SW_SKIP_MOD)
|
|
#endif
|
|
{
|
|
event->ret = wolfAsync_DoSw(asyncDev);
|
|
}
|
|
#elif defined(WOLF_CRYPTO_CB) || defined(HAVE_PK_CALLBACKS)
|
|
/* Use crypto or PK callbacks */
|
|
|
|
#else
|
|
#warning No async crypt device defined!
|
|
#endif
|
|
|
|
/* If not pending then mark as done */
|
|
if (event->ret != WC_NO_ERR_TRACE(WC_PENDING_E)) {
|
|
event->state = WOLF_EVENT_STATE_DONE;
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
} /* for */
|
|
|
|
#if defined(HAVE_CAVIUM)
|
|
/* submit partial multi-request query (if no prev errors) */
|
|
if (ret == 0 && req_count > 0) {
|
|
ret = wolfAsync_NitroxCheckMultiReqBuf(asyncDev,
|
|
queue, context_filter, &multi_req, req_count);
|
|
}
|
|
#endif
|
|
} /* flag WOLF_POLL_FLAG_CHECK_HW */
|
|
|
|
/* process event queue */
|
|
count = 0;
|
|
for (event = queue->head; event != NULL; event = event->next) {
|
|
if (event->type >= WOLF_EVENT_TYPE_ASYNC_FIRST &&
|
|
event->type <= WOLF_EVENT_TYPE_ASYNC_LAST)
|
|
{
|
|
/* optional filter based on context */
|
|
if (context_filter == NULL || event->context == context_filter) {
|
|
/* If event is done then process */
|
|
if (event->state == WOLF_EVENT_STATE_DONE) {
|
|
/* remove from queue */
|
|
ret = wolfEventQueue_Remove(queue, event);
|
|
if (ret < 0) break; /* exit for */
|
|
|
|
/* return pointer in 'events' arg */
|
|
if (events) {
|
|
events[count] = event; /* return pointer */
|
|
}
|
|
count++;
|
|
|
|
/* check to make sure our event list isn't full */
|
|
if (events && count >= maxEvents) {
|
|
break; /* exit for */
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifndef SINGLE_THREADED
|
|
wc_UnLockMutex(&queue->lock);
|
|
#endif
|
|
|
|
/* Return number of properly populated events */
|
|
if (eventCount) {
|
|
*eventCount = count;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int wolfAsync_EventInit(WOLF_EVENT* event, WOLF_EVENT_TYPE type, void* context,
|
|
word32 flags)
|
|
{
|
|
int ret = 0;
|
|
WC_ASYNC_DEV* asyncDev;
|
|
|
|
if (event == NULL) {
|
|
return BAD_FUNC_ARG;
|
|
}
|
|
|
|
event->type = type;
|
|
event->context = context;
|
|
#ifndef WC_NO_ASYNC_THREADING
|
|
event->threadId = wc_AsyncThreadId();
|
|
#endif
|
|
event->ret = WC_PENDING_E;
|
|
event->state = WOLF_EVENT_STATE_PENDING;
|
|
|
|
asyncDev = wolfAsync_GetDev(event);
|
|
event->dev.async = asyncDev;
|
|
event->flags = flags;
|
|
#ifdef HAVE_CAVIUM
|
|
event->reqId = 0;
|
|
#endif
|
|
|
|
return ret;
|
|
}
|
|
|
|
int wolfAsync_EventWait(WOLF_EVENT* event)
|
|
{
|
|
int ret = 0;
|
|
|
|
if (event == NULL) {
|
|
return BAD_FUNC_ARG;
|
|
}
|
|
|
|
/* wait for completion */
|
|
while (ret == 0 && event->ret == WC_NO_ERR_TRACE(WC_PENDING_E)) {
|
|
ret = wolfAsync_EventPoll(event, WOLF_POLL_FLAG_CHECK_HW);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int wc_AsyncHandle(WC_ASYNC_DEV* asyncDev, WOLF_EVENT_QUEUE* queue,
|
|
word32 event_flags)
|
|
{
|
|
int ret;
|
|
WOLF_EVENT* event;
|
|
|
|
if (asyncDev == NULL || queue == NULL) {
|
|
return BAD_FUNC_ARG;
|
|
}
|
|
|
|
/* setup the event and push to queue */
|
|
event = &asyncDev->event;
|
|
ret = wolfAsync_EventInit(event, WOLF_EVENT_TYPE_ASYNC_WOLFCRYPT,
|
|
asyncDev, event_flags);
|
|
if (ret == 0) {
|
|
ret = wolfEventQueue_Push(queue, event);
|
|
}
|
|
|
|
/* check for error (helps with debugging) */
|
|
if (ret != 0) {
|
|
WOLFSSL_MSG("wc_AsyncHandle failed");
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int wc_AsyncWait(int ret, WC_ASYNC_DEV* asyncDev, word32 event_flags)
|
|
{
|
|
if (ret == WC_NO_ERR_TRACE(WC_PENDING_E)) {
|
|
WOLF_EVENT* event;
|
|
|
|
if (asyncDev == NULL)
|
|
return BAD_FUNC_ARG;
|
|
|
|
event = &asyncDev->event;
|
|
ret = wolfAsync_EventInit(event, WOLF_EVENT_TYPE_ASYNC_WOLFCRYPT,
|
|
asyncDev, event_flags);
|
|
if (ret == 0) {
|
|
ret = wolfAsync_EventWait(event);
|
|
if (ret == 0) {
|
|
ret = event->ret;
|
|
|
|
/* clear event */
|
|
event->state = WOLF_EVENT_STATE_READY;
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
#ifndef WC_NO_ASYNC_SLEEP
|
|
int wc_AsyncSleep(word32 ms)
|
|
{
|
|
int ret = 0;
|
|
struct timespec resTime, remTime;
|
|
resTime.tv_sec = ms/1000;
|
|
resTime.tv_nsec = (ms%1000)*1000000;
|
|
do {
|
|
ret = nanosleep(&resTime, &remTime);
|
|
resTime = remTime;
|
|
} while ((ret!=0) && (errno == EINTR));
|
|
|
|
if (ret != 0) {
|
|
fprintf(stderr, "nanoSleep failed with code %d\n", ret);
|
|
return BAD_FUNC_ARG;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
/* Pthread Helpers */
|
|
#ifndef WC_NO_ASYNC_THREADING
|
|
|
|
int wc_AsyncGetNumberOfCpus(void)
|
|
{
|
|
int numCpus;
|
|
|
|
numCpus = (int)sysconf(_SC_NPROCESSORS_ONLN);
|
|
|
|
return numCpus;
|
|
}
|
|
|
|
int wc_AsyncThreadCreate_ex(pthread_t *thread,
|
|
word32 priority, int policy,
|
|
AsyncThreadFunc_t function, void* params)
|
|
{
|
|
int status = 1;
|
|
pthread_attr_t attr;
|
|
struct sched_param param;
|
|
|
|
status = pthread_attr_init(&attr);
|
|
if (status !=0) {
|
|
fprintf(stderr, "pthread_attr_init error: %d\n", status);
|
|
return ASYNC_OP_E;
|
|
}
|
|
|
|
/* Setting scheduling parameter will fail for non root user,
|
|
* as the default value of inheritsched is PTHREAD_EXPLICIT_SCHED in
|
|
* POSIX. It is not required to set it explicitly before setting the
|
|
* scheduling policy */
|
|
|
|
/* Set scheduling policy based on values provided */
|
|
if ((policy != SCHED_RR) &&
|
|
(policy != SCHED_FIFO) &&
|
|
(policy != SCHED_OTHER))
|
|
{
|
|
policy = SCHED_OTHER;
|
|
}
|
|
|
|
status = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
|
|
if (status != 0) {
|
|
goto exit_fail;
|
|
}
|
|
|
|
status = pthread_attr_setschedpolicy(&attr, policy);
|
|
if (status != 0) {
|
|
goto exit_fail;
|
|
}
|
|
|
|
/* Set priority based on value in threadAttr */
|
|
memset(¶m, 0, sizeof(param));
|
|
param.sched_priority = priority;
|
|
if (policy != SCHED_OTHER) {
|
|
status = pthread_attr_setschedparam(&attr, ¶m);
|
|
if (status != 0) {
|
|
goto exit_fail;
|
|
}
|
|
}
|
|
|
|
status = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
|
|
if (status != 0) {
|
|
goto exit_fail;
|
|
}
|
|
|
|
status = pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
|
|
if (status != 0) {
|
|
goto exit_fail;
|
|
}
|
|
|
|
status = pthread_create(thread, &attr, function, params);
|
|
if (status != 0) {
|
|
goto exit_fail;
|
|
}
|
|
|
|
/*destroy the thread attributes as they are no longer required, this does
|
|
* not affect the created thread*/
|
|
status = pthread_attr_destroy(&attr);
|
|
if (status != 0) {
|
|
fprintf(stderr, "AsyncThreadCreate error: %d\n", status);
|
|
return ASYNC_OP_E;
|
|
} else {
|
|
return 0;
|
|
}
|
|
|
|
exit_fail:
|
|
|
|
fprintf(stderr, "AsyncThreadCreate error: %d\n", status);
|
|
status = pthread_attr_destroy(&attr);
|
|
if (status != 0)
|
|
fprintf(stderr, "AsyncThreadCreate cleanup error: %d\n", status);
|
|
return ASYNC_OP_E;
|
|
}
|
|
|
|
int wc_AsyncThreadCreate(pthread_t *thread,
|
|
AsyncThreadFunc_t function, void* params)
|
|
{
|
|
return wc_AsyncThreadCreate_ex(thread, THREAD_DEFAULT_PRIORITY,
|
|
THREAD_DEFAULT_POLICY, function, params);
|
|
}
|
|
|
|
#ifdef __MACH__
|
|
#include <mach/mach.h>
|
|
#include <mach/thread_policy.h>
|
|
|
|
/* native MACH API wrappers */
|
|
#define SYSCTL_CORE_COUNT "machdep.cpu.core_count"
|
|
|
|
typedef struct cpu_set {
|
|
uint32_t count;
|
|
} cpu_set_t;
|
|
|
|
static WC_INLINE void CPU_ZERO(cpu_set_t *cs) {
|
|
cs->count = 0;
|
|
}
|
|
static WC_INLINE void CPU_SET(int num, cpu_set_t *cs) {
|
|
cs->count |= (1 << num);
|
|
}
|
|
static WC_INLINE int CPU_ISSET(int num, cpu_set_t *cs) {
|
|
return (cs->count & (1 << num));
|
|
}
|
|
|
|
static int pthread_setaffinity_np(pthread_t thread, size_t cpu_size,
|
|
cpu_set_t *cpu_set)
|
|
{
|
|
thread_port_t mach_thread;
|
|
thread_affinity_policy_data_t policy;
|
|
int core = 0;
|
|
|
|
for (core = 0; core < 8 * (int)cpu_size; core++) {
|
|
if (CPU_ISSET(core, cpu_set))
|
|
break;
|
|
}
|
|
|
|
policy.affinity_tag = core;
|
|
mach_thread = pthread_mach_thread_np(thread);
|
|
thread_policy_set(mach_thread, THREAD_AFFINITY_POLICY,
|
|
(thread_policy_t)&policy, 1);
|
|
|
|
return 0;
|
|
}
|
|
#endif /* __MACH__ */
|
|
|
|
int wc_AsyncThreadBind(pthread_t *thread, word32 logicalCore)
|
|
{
|
|
int status = 0;
|
|
cpu_set_t cpuset;
|
|
|
|
if (!thread) return BAD_FUNC_ARG;
|
|
|
|
CPU_ZERO(&cpuset);
|
|
CPU_SET(logicalCore, &cpuset);
|
|
|
|
status = pthread_setaffinity_np(*thread, sizeof(cpu_set_t), &cpuset);
|
|
if (status != 0) {
|
|
fprintf(stderr, "pthread_setaffinity_np error: %d\n", status);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
int wc_AsyncThreadStart(pthread_t *thread)
|
|
{
|
|
(void)thread;
|
|
return 0;
|
|
}
|
|
|
|
__attribute__((noreturn))
|
|
void wc_AsyncThreadExit(void *retval)
|
|
{
|
|
pthread_exit(retval);
|
|
}
|
|
|
|
int wc_AsyncThreadKill(pthread_t *thread)
|
|
{
|
|
int status;
|
|
|
|
if (!thread) return BAD_FUNC_ARG;
|
|
|
|
status = pthread_cancel(*thread);
|
|
if (status != 0) {
|
|
fprintf(stderr, "pthread_cancel fail with status %d\n", status);
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
int wc_AsyncThreadPrioritySet(pthread_t *thread, word32 priority)
|
|
{
|
|
int status;
|
|
struct sched_param param;
|
|
int policy;
|
|
word32 minPrio;
|
|
word32 maxPrio;
|
|
|
|
if (!thread) return BAD_FUNC_ARG;
|
|
|
|
status = pthread_getschedparam(*thread, &policy, ¶m);
|
|
if (status != 0) {
|
|
fprintf(stderr, "pthread_getschedparam, failed with status %d\n",
|
|
status);
|
|
return status;
|
|
}
|
|
|
|
minPrio = sched_get_priority_min(policy);
|
|
maxPrio = sched_get_priority_max(policy);
|
|
|
|
if ((priority < minPrio) || (priority > maxPrio)) {
|
|
fprintf(stderr, "priority %u outside valid range\n", priority);
|
|
return BAD_FUNC_ARG;
|
|
}
|
|
|
|
param.sched_priority = priority;
|
|
|
|
status = pthread_setschedparam(*thread, policy, ¶m);
|
|
if (status != 0) {
|
|
fprintf(stderr, "pthread_setschedparam, failed with status %d\n",
|
|
status);
|
|
return status;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
int wc_AsyncThreadSetPolicyAndPriority(pthread_t *thread, word32 policy,
|
|
word32 priority)
|
|
{
|
|
int status;
|
|
struct sched_param param;
|
|
word32 minPrio, maxPrio;
|
|
int policy1;
|
|
|
|
if (!thread) return BAD_FUNC_ARG;
|
|
|
|
/* check for a valid value for 'policy' */
|
|
if ((policy != SCHED_RR) &&
|
|
(policy != SCHED_FIFO) &&
|
|
(policy != SCHED_OTHER))
|
|
{
|
|
fprintf(stderr, "wc_AsyncThreadSetPolicyAndPriority: "
|
|
"invalid policy %u\n", policy);
|
|
return BAD_FUNC_ARG;
|
|
}
|
|
|
|
memset(¶m, 0, sizeof(param));
|
|
|
|
status = pthread_getschedparam(*thread, &policy1, ¶m);
|
|
if (status != 0) {
|
|
fprintf(stderr, "pthread_getschedparam error: %d\n", status);
|
|
return status;
|
|
}
|
|
|
|
minPrio = sched_get_priority_min(policy);
|
|
maxPrio = sched_get_priority_max(policy);
|
|
|
|
if ((priority < minPrio) || (priority > maxPrio)) {
|
|
return BAD_FUNC_ARG;
|
|
}
|
|
|
|
param.sched_priority = priority;
|
|
|
|
status = pthread_setschedparam(*thread, policy, ¶m);
|
|
if (status != 0) {
|
|
fprintf(stderr, "pthread_setschedparam error: %d\n", status);
|
|
return status;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int wc_AsyncThreadJoin(pthread_t *thread)
|
|
{
|
|
int status;
|
|
status = pthread_join(*thread, NULL);
|
|
if (status != 0) {
|
|
fprintf(stderr, "pthread_join failed, status: %d\n", status);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
void wc_AsyncThreadYield(void)
|
|
{
|
|
sched_yield();
|
|
}
|
|
|
|
pthread_t wc_AsyncThreadId(void)
|
|
{
|
|
return pthread_self();
|
|
}
|
|
|
|
#endif /* WC_NO_ASYNC_THREADING */
|
|
|
|
#endif /* WOLFSSL_ASYNC_CRYPT */
|