summaryrefslogtreecommitdiff
path: root/wolfcrypt/src/port/caam
diff options
context:
space:
mode:
authorauth12 <[email protected]>2020-07-22 08:34:12 -0700
committerauth12 <[email protected]>2020-07-22 08:34:12 -0700
commit5015ddb9b1eee748efc24056e46f81888c975f7a (patch)
treea810f6ee90f8bfe0e934fdd9142198e6b3862957 /wolfcrypt/src/port/caam
downloadwolfssl_windows-5015ddb9b1eee748efc24056e46f81888c975f7a.tar.xz
wolfssl_windows-5015ddb9b1eee748efc24056e46f81888c975f7a.zip
Initial commit
Diffstat (limited to 'wolfcrypt/src/port/caam')
-rw-r--r--wolfcrypt/src/port/caam/caam_aes.c649
-rw-r--r--wolfcrypt/src/port/caam/caam_doc.pdfbin0 -> 1107370 bytes
-rw-r--r--wolfcrypt/src/port/caam/caam_driver.c1713
-rw-r--r--wolfcrypt/src/port/caam/caam_init.c289
-rw-r--r--wolfcrypt/src/port/caam/caam_sha.c397
5 files changed, 3048 insertions, 0 deletions
diff --git a/wolfcrypt/src/port/caam/caam_aes.c b/wolfcrypt/src/port/caam/caam_aes.c
new file mode 100644
index 0000000..e00214d
--- /dev/null
+++ b/wolfcrypt/src/port/caam/caam_aes.c
@@ -0,0 +1,649 @@
+/* caam_aes.c
+ *
+ * Copyright (C) 2006-2020 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 2 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/settings.h>
+
+#if defined(WOLFSSL_IMX6_CAAM) && !defined(NO_AES) && \
+ !defined(NO_IMX6_CAAM_AES)
+
+#include <wolfssl/wolfcrypt/logging.h>
+#include <wolfssl/wolfcrypt/error-crypt.h>
+#include <wolfssl/wolfcrypt/aes.h>
+
+#ifdef NO_INLINE
+ #include <wolfssl/wolfcrypt/misc.h>
+#else
+ #define WOLFSSL_MISC_INCLUDED
+ #include <wolfcrypt/src/misc.c>
+#endif
+
+#include <wolfssl/wolfcrypt/port/caam/wolfcaam.h>
+#include <wolfssl/wolfcrypt/port/caam/caam_driver.h>
+
+#if defined(WOLFSSL_CAAM_DEBUG) || defined(WOLFSSL_CAAM_PRINT)
+#include <stdio.h>
+#endif
+
+int wc_AesSetKey(Aes* aes, const byte* key, word32 len,
+ const byte* iv, int dir)
+{
+ int ret;
+
+ if (aes == NULL || key == NULL) {
+ return BAD_FUNC_ARG;
+ }
+
+ if (len > 32) {
+ byte out[32]; /* max AES key size */
+ word32 outSz;
+ int ret;
+
+ if (len != 64 && len != 72 && len != 80) {
+ return BAD_FUNC_ARG;
+ }
+
+ outSz = sizeof(out);
+ /* if length greater then 32 then try to unencapsulate */
+ if ((ret = wc_caamOpenBlob((byte*)key, len, out, &outSz)) != 0) {
+ return ret;
+ }
+
+ XMEMCPY((byte*)aes->key, out, outSz);
+ aes->keylen = outSz;
+ }
+ else {
+ if (len != 16 && len != 24 && len != 32) {
+ return BAD_FUNC_ARG;
+ }
+
+ XMEMCPY((byte*)aes->key, key, len);
+ aes->keylen = len;
+ }
+
+ switch (aes->keylen) {
+ case 16: aes->rounds = 10; break;
+ case 24: aes->rounds = 12; break;
+ case 32: aes->rounds = 14; break;
+ default:
+ return BAD_FUNC_ARG;
+ }
+
+ if ((ret = wc_AesSetIV(aes, iv)) != 0) {
+ return ret;
+ }
+
+#ifdef WOLFSSL_AES_COUNTER
+ aes->left = 0;
+#endif
+
+ return 0;
+}
+
+
+int wc_AesCbcEncrypt(Aes* aes, byte* out,
+ const byte* in, word32 sz)
+{
+ word32 blocks;
+
+ WOLFSSL_ENTER("wc_AesCbcEncrypt");
+ if (aes == NULL || out == NULL || in == NULL) {
+ return BAD_FUNC_ARG;
+ }
+
+ blocks = sz / AES_BLOCK_SIZE;
+
+ if (blocks > 0) {
+ Buffer buf[4];
+ word32 arg[4];
+ word32 keySz;
+ int ret;
+
+ if (wc_AesGetKeySize(aes, &keySz) != 0) {
+ return BAD_FUNC_ARG;
+ }
+
+ /* Set buffers for key, cipher text, and plain text */
+ buf[0].BufferType = DataBuffer;
+ buf[0].TheAddress = (Address)aes->key;
+ buf[0].Length = keySz;
+
+ buf[1].BufferType = DataBuffer;
+ buf[1].TheAddress = (Address)aes->reg;
+ buf[1].Length = AES_BLOCK_SIZE;
+
+ buf[2].BufferType = DataBuffer;
+ buf[2].TheAddress = (Address)in;
+ buf[2].Length = blocks * AES_BLOCK_SIZE;
+
+ buf[3].BufferType = DataBuffer | LastBuffer;
+ buf[3].TheAddress = (Address)out;
+ buf[3].Length = blocks * AES_BLOCK_SIZE;
+
+ arg[0] = CAAM_ENC;
+ arg[1] = keySz;
+ arg[2] = blocks * AES_BLOCK_SIZE;
+
+ if ((ret = wc_caamAddAndWait(buf, arg, CAAM_AESCBC)) != 0) {
+ WOLFSSL_MSG("Error with CAAM AES CBC encrypt");
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+
+int wc_AesCbcDecrypt(Aes* aes, byte* out,
+ const byte* in, word32 sz)
+{
+ word32 blocks;
+
+ WOLFSSL_ENTER("wc_AesCbcDecrypt");
+ if (aes == NULL || out == NULL || in == NULL) {
+ return BAD_FUNC_ARG;
+ }
+
+ blocks = sz / AES_BLOCK_SIZE;
+
+ if (blocks > 0) {
+ Buffer buf[4];
+ word32 arg[4];
+ word32 keySz;
+ int ret;
+
+ if (wc_AesGetKeySize(aes, &keySz) != 0) {
+ return BAD_FUNC_ARG;
+ }
+
+ /* Set buffers for key, cipher text, and plain text */
+ buf[0].BufferType = DataBuffer;
+ buf[0].TheAddress = (Address)aes->key;
+ buf[0].Length = keySz;
+
+ buf[1].BufferType = DataBuffer;
+ buf[1].TheAddress = (Address)aes->reg;
+ buf[1].Length = AES_BLOCK_SIZE;
+
+ buf[2].BufferType = DataBuffer;
+ buf[2].TheAddress = (Address)in;
+ buf[2].Length = blocks * AES_BLOCK_SIZE;
+
+ buf[3].BufferType = DataBuffer | LastBuffer;
+ buf[3].TheAddress = (Address)out;
+ buf[3].Length = blocks * AES_BLOCK_SIZE;
+
+ arg[0] = CAAM_DEC;
+ arg[1] = keySz;
+ arg[2] = blocks * AES_BLOCK_SIZE;
+
+ if ((ret = wc_caamAddAndWait(buf, arg, CAAM_AESCBC)) != 0) {
+ WOLFSSL_MSG("Error with CAAM AES CBC decrypt");
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+#if defined(HAVE_AES_ECB)
+/* is assumed that input size is a multiple of AES_BLOCK_SIZE */
+int wc_AesEcbEncrypt(Aes* aes, byte* out,
+ const byte* in, word32 sz)
+{
+ word32 blocks;
+ Buffer buf[3];
+ word32 arg[4];
+ word32 keySz;
+ int ret;
+
+ if (aes == NULL || out == NULL || in == NULL) {
+ return BAD_FUNC_ARG;
+ }
+
+ blocks = sz / AES_BLOCK_SIZE;
+
+ if (wc_AesGetKeySize(aes, &keySz) != 0) {
+ return BAD_FUNC_ARG;
+ }
+
+ /* Set buffers for key, cipher text, and plain text */
+ buf[0].BufferType = DataBuffer;
+ buf[0].TheAddress = (Address)aes->key;
+ buf[0].Length = keySz;
+
+ buf[1].BufferType = DataBuffer;
+ buf[1].TheAddress = (Address)in;
+ buf[1].Length = blocks * AES_BLOCK_SIZE;
+
+ buf[2].BufferType = DataBuffer | LastBuffer;
+ buf[2].TheAddress = (Address)out;
+ buf[2].Length = blocks * AES_BLOCK_SIZE;
+
+ arg[0] = CAAM_ENC;
+ arg[1] = keySz;
+ arg[2] = blocks * AES_BLOCK_SIZE;
+
+ if ((ret = wc_caamAddAndWait(buf, arg, CAAM_AESECB)) != 0) {
+ WOLFSSL_MSG("Error with CAAM AES ECB encrypt");
+ return ret;
+ }
+
+ return 0;
+}
+
+
+int wc_AesEcbDecrypt(Aes* aes, byte* out,
+ const byte* in, word32 sz)
+{
+ word32 blocks;
+ Buffer buf[3];
+ word32 arg[4];
+ word32 keySz;
+ int ret;
+
+ if (aes == NULL || out == NULL || in == NULL) {
+ return BAD_FUNC_ARG;
+ }
+
+ blocks = sz / AES_BLOCK_SIZE;
+
+ if (wc_AesGetKeySize(aes, &keySz) != 0) {
+ return BAD_FUNC_ARG;
+ }
+
+ /* Set buffers for key, cipher text, and plain text */
+ buf[0].BufferType = DataBuffer;
+ buf[0].TheAddress = (Address)aes->key;
+ buf[0].Length = keySz;
+
+ buf[1].BufferType = DataBuffer;
+ buf[1].TheAddress = (Address)in;
+ buf[1].Length = blocks * AES_BLOCK_SIZE;
+
+ buf[2].BufferType = DataBuffer | LastBuffer;
+ buf[2].TheAddress = (Address)out;
+ buf[2].Length = blocks * AES_BLOCK_SIZE;
+
+ arg[0] = CAAM_DEC;
+ arg[1] = keySz;
+ arg[2] = blocks * AES_BLOCK_SIZE;
+
+ if ((ret = wc_caamAddAndWait(buf, arg, CAAM_AESECB)) != 0) {
+ WOLFSSL_MSG("Error with CAAM AES ECB decrypt");
+ return ret;
+ }
+
+ return 0;
+}
+#endif
+
+/* AES-CTR */
+#ifdef WOLFSSL_AES_COUNTER
+/* Increment AES counter (from wolfcrypt/src/aes.c) */
+static WC_INLINE void IncrementAesCounter(byte* inOutCtr)
+{
+ /* in network byte order so start at end and work back */
+ int i;
+ for (i = AES_BLOCK_SIZE - 1; i >= 0; i--) {
+ if (++inOutCtr[i]) /* we're done unless we overflow */
+ return;
+ }
+}
+
+
+int wc_AesCtrEncrypt(Aes* aes, byte* out,
+ const byte* in, word32 sz)
+{
+ byte* tmp;
+ Buffer buf[4];
+ word32 arg[4];
+ word32 keySz;
+ int ret, blocks;
+
+ if (aes == NULL || out == NULL || in == NULL) {
+ return BAD_FUNC_ARG;
+ }
+
+ if (wc_AesGetKeySize(aes, &keySz) != 0) {
+ return BAD_FUNC_ARG;
+ }
+
+ /* consume any unused bytes left in aes->tmp */
+ tmp = (byte*)aes->tmp + AES_BLOCK_SIZE - aes->left;
+ while (aes->left && sz) {
+ *(out++) = *(in++) ^ *(tmp++);
+ aes->left--;
+ sz--;
+ }
+
+ /* do full blocks to then get potential left over amount */
+ blocks = sz / AES_BLOCK_SIZE;
+ if (blocks > 0) {
+ /* Set buffers for key, cipher text, and plain text */
+ buf[0].BufferType = DataBuffer;
+ buf[0].TheAddress = (Address)aes->key;
+ buf[0].Length = keySz;
+
+ buf[1].BufferType = DataBuffer;
+ buf[1].TheAddress = (Address)aes->reg;
+ buf[1].Length = AES_BLOCK_SIZE;
+
+ buf[2].BufferType = DataBuffer;
+ buf[2].TheAddress = (Address)in;
+ buf[2].Length = blocks * AES_BLOCK_SIZE;
+
+ buf[3].BufferType = DataBuffer | LastBuffer;
+ buf[3].TheAddress = (Address)out;
+ buf[3].Length = blocks * AES_BLOCK_SIZE;
+
+ arg[0] = CAAM_ENC;
+ arg[1] = keySz;
+ arg[2] = blocks * AES_BLOCK_SIZE;
+
+ if ((ret = wc_caamAddAndWait(buf, arg, CAAM_AESCTR)) != 0) {
+ WOLFSSL_MSG("Error with CAAM AES CTR encrypt");
+ return ret;
+ }
+
+ out += blocks * AES_BLOCK_SIZE;
+ in += blocks * AES_BLOCK_SIZE;
+ sz -= blocks * AES_BLOCK_SIZE;
+ }
+
+ if (sz) {
+ wc_AesEncryptDirect(aes, (byte*)aes->tmp, (byte*)aes->reg);
+ IncrementAesCounter((byte*)aes->reg);
+
+ aes->left = AES_BLOCK_SIZE;
+ tmp = (byte*)aes->tmp;
+
+ while (sz--) {
+ *(out++) = *(in++) ^ *(tmp++);
+ aes->left--;
+ }
+ }
+
+ return 0;
+}
+#endif
+
+
+/* AES-DIRECT */
+#if defined(WOLFSSL_AES_DIRECT) || defined(WOLFSSL_AES_COUNTER)
+void wc_AesEncryptDirect(Aes* aes, byte* out, const byte* in)
+{
+ Buffer buf[3];
+ word32 arg[4];
+ word32 keySz;
+
+ if (aes == NULL || out == NULL || in == NULL) {
+ /* return BAD_FUNC_ARG; */
+ return;
+ }
+
+ if (wc_AesGetKeySize(aes, &keySz) != 0) {
+ /* return BAD_FUNC_ARG; */
+ return;
+ }
+
+ /* Set buffers for key, cipher text, and plain text */
+ buf[0].BufferType = DataBuffer;
+ buf[0].TheAddress = (Address)aes->key;
+ buf[0].Length = keySz;
+
+ buf[1].BufferType = DataBuffer;
+ buf[1].TheAddress = (Address)in;
+ buf[1].Length = AES_BLOCK_SIZE;
+
+ buf[2].BufferType = DataBuffer | LastBuffer;
+ buf[2].TheAddress = (Address)out;
+ buf[2].Length = AES_BLOCK_SIZE;
+
+ arg[0] = CAAM_ENC;
+ arg[1] = keySz;
+ arg[2] = AES_BLOCK_SIZE;
+
+ if (wc_caamAddAndWait(buf, arg, CAAM_AESECB) != 0) {
+ WOLFSSL_MSG("Error with CAAM AES direct encrypt");
+ }
+}
+
+
+void wc_AesDecryptDirect(Aes* aes, byte* out, const byte* in)
+{
+ Buffer buf[3];
+ word32 arg[4];
+ word32 keySz;
+
+ if (aes == NULL || out == NULL || in == NULL) {
+ /* return BAD_FUNC_ARG; */
+ return;
+ }
+
+ if (wc_AesGetKeySize(aes, &keySz) != 0) {
+ /* return BAD_FUNC_ARG; */
+ return;
+ }
+
+ /* Set buffers for key, cipher text, and plain text */
+ buf[0].BufferType = DataBuffer;
+ buf[0].TheAddress = (Address)aes->key;
+ buf[0].Length = keySz;
+
+ buf[1].BufferType = DataBuffer;
+ buf[1].TheAddress = (Address)in;
+ buf[1].Length = AES_BLOCK_SIZE;
+
+ buf[2].BufferType = DataBuffer | LastBuffer;
+ buf[2].TheAddress = (Address)out;
+ buf[2].Length = AES_BLOCK_SIZE;
+
+ arg[0] = CAAM_DEC;
+ arg[1] = keySz;
+ arg[2] = AES_BLOCK_SIZE;
+
+ if (wc_caamAddAndWait(buf, arg, CAAM_AESECB) != 0) {
+ WOLFSSL_MSG("Error with CAAM AES direct decrypt");
+ }
+}
+
+
+int wc_AesSetKeyDirect(Aes* aes, const byte* key, word32 len,
+ const byte* iv, int dir)
+{
+ return wc_AesSetKey(aes, key, len, iv, dir);
+}
+#endif
+
+#ifdef HAVE_AESCCM
+int wc_AesCcmEncrypt(Aes* aes, byte* out,
+ const byte* in, word32 inSz,
+ const byte* nonce, word32 nonceSz,
+ byte* authTag, word32 authTagSz,
+ const byte* authIn, word32 authInSz)
+{
+ Buffer buf[5];
+ word32 arg[4];
+ word32 keySz;
+ word32 i;
+ byte B0Ctr0[AES_BLOCK_SIZE + AES_BLOCK_SIZE];
+ int lenSz;
+ byte mask = 0xFF;
+ const word32 wordSz = (word32)sizeof(word32);
+ int ret;
+
+ /* sanity check on arguments */
+ if (aes == NULL || out == NULL || in == NULL || nonce == NULL
+ || authTag == NULL || nonceSz < 7 || nonceSz > 13 ||
+ authTagSz > AES_BLOCK_SIZE)
+ return BAD_FUNC_ARG;
+
+ if (wc_AesGetKeySize(aes, &keySz) != 0) {
+ return BAD_FUNC_ARG;
+ }
+
+ /* set up B0 and CTR0 similar to how wolfcrypt/src/aes.c does */
+ XMEMCPY(B0Ctr0+1, nonce, nonceSz);
+ XMEMCPY(B0Ctr0+AES_BLOCK_SIZE+1, nonce, nonceSz);
+ lenSz = AES_BLOCK_SIZE - 1 - (byte)nonceSz;
+ B0Ctr0[0] = (authInSz > 0 ? 64 : 0)
+ + (8 * (((byte)authTagSz - 2) / 2))
+ + (lenSz - 1);
+ for (i = 0; i < lenSz; i++) {
+ if (mask && i >= wordSz)
+ mask = 0x00;
+ B0Ctr0[AES_BLOCK_SIZE - 1 - i] = (inSz >> ((8 * i) & mask)) & mask;
+ B0Ctr0[AES_BLOCK_SIZE + AES_BLOCK_SIZE - 1 - i] = 0;
+ }
+ B0Ctr0[AES_BLOCK_SIZE] = lenSz - 1;
+
+ /* Set buffers for key, cipher text, and plain text */
+ buf[0].BufferType = DataBuffer;
+ buf[0].TheAddress = (Address)aes->key;
+ buf[0].Length = keySz;
+
+ buf[1].BufferType = DataBuffer;
+ buf[1].TheAddress = (Address)B0Ctr0;
+ buf[1].Length = AES_BLOCK_SIZE + AES_BLOCK_SIZE;
+
+ buf[2].BufferType = DataBuffer;
+ buf[2].TheAddress = (Address)authIn;
+ buf[2].Length = authInSz;
+
+ buf[3].BufferType = DataBuffer;
+ buf[3].TheAddress = (Address)in;
+ buf[3].Length = inSz;
+
+ buf[4].BufferType = DataBuffer | LastBuffer;
+ buf[4].TheAddress = (Address)out;
+ buf[4].Length = inSz;
+
+ arg[0] = CAAM_ENC;
+ arg[1] = keySz;
+ arg[2] = inSz;
+ arg[3] = authInSz;
+
+ if ((ret = wc_caamAddAndWait(buf, arg, CAAM_AESCCM)) != 0) {
+ WOLFSSL_MSG("Error with CAAM AES-CCM encrypt");
+ return ret;
+ }
+
+ XMEMCPY(authTag, B0Ctr0, authTagSz);
+ return 0;
+}
+
+
+#ifdef HAVE_AES_DECRYPT
+int wc_AesCcmDecrypt(Aes* aes, byte* out,
+ const byte* in, word32 inSz,
+ const byte* nonce, word32 nonceSz,
+ const byte* authTag, word32 authTagSz,
+ const byte* authIn, word32 authInSz)
+{
+ Buffer buf[5];
+ word32 arg[4];
+ word32 keySz;
+ word32 i;
+ byte B0Ctr0[AES_BLOCK_SIZE + AES_BLOCK_SIZE];
+ byte tag[AES_BLOCK_SIZE];
+ int lenSz;
+ byte mask = 0xFF;
+ const word32 wordSz = (word32)sizeof(word32);
+ int ret;
+
+ /* sanity check on arguments */
+ if (aes == NULL || out == NULL || in == NULL || nonce == NULL
+ || authTag == NULL || nonceSz < 7 || nonceSz > 13 ||
+ authTagSz > AES_BLOCK_SIZE)
+ return BAD_FUNC_ARG;
+
+ if (wc_AesGetKeySize(aes, &keySz) != 0) {
+ return BAD_FUNC_ARG;
+ }
+
+ /* set up B0 and CTR0 similar to how wolfcrypt/src/aes.c does */
+ XMEMCPY(B0Ctr0+1, nonce, nonceSz);
+ XMEMCPY(B0Ctr0+AES_BLOCK_SIZE+1, nonce, nonceSz);
+ lenSz = AES_BLOCK_SIZE - 1 - (byte)nonceSz;
+ B0Ctr0[0] = (authInSz > 0 ? 64 : 0)
+ + (8 * (((byte)authTagSz - 2) / 2))
+ + (lenSz - 1);
+ for (i = 0; i < lenSz; i++) {
+ if (mask && i >= wordSz)
+ mask = 0x00;
+ B0Ctr0[AES_BLOCK_SIZE - 1 - i] = (inSz >> ((8 * i) & mask)) & mask;
+ B0Ctr0[AES_BLOCK_SIZE + AES_BLOCK_SIZE - 1 - i] = 0;
+ }
+ B0Ctr0[AES_BLOCK_SIZE] = lenSz - 1;
+ wc_AesEncryptDirect(aes, tag, B0Ctr0 + AES_BLOCK_SIZE);
+
+ /* Set buffers for key, cipher text, and plain text */
+ buf[0].BufferType = DataBuffer;
+ buf[0].TheAddress = (Address)aes->key;
+ buf[0].Length = keySz;
+
+ buf[1].BufferType = DataBuffer;
+ buf[1].TheAddress = (Address)B0Ctr0;
+ buf[1].Length = AES_BLOCK_SIZE + AES_BLOCK_SIZE;
+
+ buf[2].BufferType = DataBuffer;
+ buf[2].TheAddress = (Address)authIn;
+ buf[2].Length = authInSz;
+
+ buf[3].BufferType = DataBuffer;
+ buf[3].TheAddress = (Address)in;
+ buf[3].Length = inSz;
+
+ buf[4].BufferType = DataBuffer | LastBuffer;
+ buf[4].TheAddress = (Address)out;
+ buf[4].Length = inSz;
+
+ arg[0] = CAAM_DEC;
+ arg[1] = keySz;
+ arg[2] = inSz;
+ arg[3] = authInSz;
+
+ if ((ret = wc_caamAddAndWait(buf, arg, CAAM_AESCCM)) != 0) {
+ WOLFSSL_MSG("Error with CAAM AES-CCM derypt");
+ return ret;
+ }
+
+ xorbuf(tag, B0Ctr0, authTagSz);
+ if (ConstantCompare(tag, authTag, authTagSz) != 0) {
+ /* If the authTag check fails, don't keep the decrypted data.
+ * Unfortunately, you need the decrypted data to calculate the
+ * check value. */
+ XMEMSET(out, 0, inSz);
+ ret = AES_CCM_AUTH_E;
+ }
+
+ ForceZero(tag, AES_BLOCK_SIZE);
+ ForceZero(B0Ctr0, AES_BLOCK_SIZE * 2);
+
+ return ret;
+
+}
+#endif /* HAVE_AES_DECRYPT */
+#endif /* HAVE_AESCCM */
+
+#endif /* WOLFSSL_IMX6_CAAM && !NO_AES */
+
diff --git a/wolfcrypt/src/port/caam/caam_doc.pdf b/wolfcrypt/src/port/caam/caam_doc.pdf
new file mode 100644
index 0000000..8213634
--- /dev/null
+++ b/wolfcrypt/src/port/caam/caam_doc.pdf
Binary files differ
diff --git a/wolfcrypt/src/port/caam/caam_driver.c b/wolfcrypt/src/port/caam/caam_driver.c
new file mode 100644
index 0000000..5d44f2d
--- /dev/null
+++ b/wolfcrypt/src/port/caam/caam_driver.c
@@ -0,0 +1,1713 @@
+/* caam_driver.c
+ *
+ * Copyright (C) 2006-2020 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 2 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
+ */
+
+#if defined(__INTEGRITY) || defined(INTEGRITY)
+
+/* build into Integrity kernel */
+#include <bsp.h>
+#include "wolfssl/wolfcrypt/port/caam/caam_driver.h"
+
+#define CAAM_READ(reg) *(volatile unsigned int*)(reg)
+#define CAAM_WRITE(reg, in) *(volatile unsigned int*)(reg) = (in);
+
+#define DESC_COUNT 1
+#define MAX_BUF 20
+#define BUFFER_COUNT (MAX_BUF * DESC_COUNT)
+
+/* CAAM descriptors can only be 64 unsigned ints */
+#define MAX_DESC_SZ 64
+
+/* 64 byte buffer for when data crosses a page boundary */
+#define ALIGN_BUF 16
+
+/* MAX_CTX is 64 bytes (sha512 digest) + 8 bytes (CAAM length value) */
+#define MAX_CTX 18
+
+#define MIN_READ_REG 0xF2100000
+#define MAX_READ_REG 0XF2110000
+
+struct JobRing {
+ Address JobIn;
+ Address JobOut;
+ Address Desc;
+ Value page; /* page allocation for descriptor to use */
+};
+
+struct buffer {
+ Address data;
+ Address dataSz;
+};
+
+/* CAAM descriptor */
+struct DescStruct {
+ struct IORequestStruct TheIORequest;
+ struct CAAM_DEVICE* caam;
+ struct buffer buf[MAX_BUF]; /* buffers holding data input address */
+ UINT4 desc[MAX_DESC_SZ]; /* max size of 64 word32 */
+ UINT4 aadSzBuf[4]; /* Formatted AAD size for CCM */
+ UINT4 alignBuf[ALIGN_BUF]; /* 64 byte buffer for non page
+ align */
+ UINT4 iv[MAX_CTX]; /* AES IV and also hash state */
+ UINT4 ctxBuf[MAX_CTX]; /* key */
+ Address output; /* address to output buffer */
+ Address ctxOut; /* address to update buffer holding state */
+ Value alignIdx;/* index for align buffer */
+ Value idx; /* index for descriptor buffer */
+ Value headIdx; /* for first portion of descriptor buffer */
+ Value lastIdx; /* for last portion of descriptor buffer */
+ Value outputIdx; /* idx to output buffer in "buf" */
+ Value inputSz; /* size of input buffer */
+ Value ctxSz; /* size of CTX/Key buffer */
+ Value aadSz; /* AAD size for CCM */
+ Value lastFifo;
+ Value type;
+ Value state;
+ Value DescriptorCount;
+ Boolean running; /* True if building/running descriptor is
+ in process */
+};
+
+struct CAAM_DEVICE {
+ struct IODeviceVectorStruct caamVector;
+ struct IODescriptorStruct IODescriptorArray[BUFFER_COUNT];
+ struct DescStruct DescArray[DESC_COUNT];
+ volatile Value InterruptStatus;
+ CALL HandleInterruptCall;
+ struct JobRing ring;
+};
+
+#define DRIVER_NAME "wolfSSL_CAAM_Driver"
+
+static struct CAAM_DEVICE caam;
+
+/******************************************************************************
+ Internal CAAM Job Ring and partition functions
+ ****************************************************************************/
+
+/* flush job ring and reset */
+static Error caamReset(void)
+{
+ int t = 100000; /* time out counter for flushing job ring */
+
+ /* make sure interrupts are masked in JRCFGR0_LS register */
+ CAAM_WRITE(CAAM_BASE | 0x1054, CAAM_READ(CAAM_BASE | 0x1054) | 1);
+
+ /* flush and reset job rings using JRCR0 register */
+ CAAM_WRITE(CAAM_BASE | 0x106C, 1);
+
+ /* check register JRINTR for if halt is in progress */
+ while (t > 0 && ((CAAM_READ(CAAM_BASE | 0x104C) & 0x4) == 0x4)) t--;
+ if (t == 0) {
+ /*unrecoverable failure, the job ring is locked, up hard reset needed*/
+ return NotRestartable;
+ }
+
+ /* now that flush has been done restart the job ring */
+ t = 100000;
+ CAAM_WRITE(CAAM_BASE | 0x106C, 1);
+ while (t > 0 && ((CAAM_READ(CAAM_BASE | 0x106C) & 1) == 1)) t--;
+ if (t == 0) {
+ /*unrecoverable failure, reset bit did not return to 0 */
+ return NotRestartable;
+ }
+
+ /* reset most registers and state machines in CAAM using MCFGR register
+ also reset DMA */
+ CAAM_WRITE(CAAM_BASE | 0x0004, 0x90000000);
+
+ return Success;
+}
+
+/* returns MemoryMapMayNotBeEmpty if page/par is already owned
+ * returns Success on success
+ * all other returns is an error state
+ */
+static Error caamCreatePartition(unsigned char page, unsigned char par)
+{
+ /* check ownership of partition */
+ if ((CAAM_READ(CAAM_BASE | 0x1FBC) & (0x3 << (par * 2))) > 0) {
+ return MemoryMapMayNotBeEmpty;
+ }
+
+ /* set generic all access permissions, gets reset later */
+ CAAM_WRITE(CAAM_BASE | (0x1108 + (par * 16)), 0xF);
+ CAAM_WRITE(CAAM_BASE | (0x110C + (par * 16)), 0xF);
+ CAAM_WRITE(CAAM_BASE | (0x1104 + (par * 16)), 0xFF);
+
+ /* check ownership of page */
+ CAAM_WRITE(CAAM_BASE | 0x10F4, (page << 16) | 0x5);
+ /* wait for inquiry cmd to complete */
+ while ((CAAM_READ(CAAM_BASE | 0x10FC) & 0x0000C000) > 0 &&
+ (CAAM_READ(CAAM_BASE | 0x10FC) & 0x00003000) == 0) {
+ }
+ if ((CAAM_READ(CAAM_BASE | 0x10FC) & 0x000000C0) == 0xC0) {
+ /* owns the page can dealloc it */
+ CAAM_WRITE(CAAM_BASE | 0x10F4, (page << 16) | 0x2);
+ while ((CAAM_READ(CAAM_BASE | 0x10FC) & 0x0000C000) > 0 &&
+ (CAAM_READ(CAAM_BASE | 0x10FC) & 0x00003000) == 0) {}
+ if ((CAAM_READ(CAAM_BASE | 0x10FC) & 0x00003000) > 0) {
+ /* error while deallocating page */
+ return MemoryMapMayNotBeEmpty; /* PSP set on page or is unavailable */
+ }
+ }
+ else {
+ /* check if owned by someone else */
+ if ((CAAM_READ(CAAM_BASE | 0x10FC) & 0x000000C0) != 0) {
+ return MemoryMapMayNotBeEmpty;
+ }
+ }
+
+ /* allocate page to partition */
+ CAAM_WRITE(CAAM_BASE | 0x10F4, (page << 16) | (par << 8) | 0x1);
+ /* wait for alloc cmd to complete */
+ while ((CAAM_READ(CAAM_BASE | 0x10FC) & 0x0000C000) > 0 &&
+ (CAAM_READ(CAAM_BASE | 0x10FC) & 0x00003000) == 0) {
+ }
+
+ if ((CAAM_READ(CAAM_BASE | 0x10FC) & 0x00003000) > 0) {
+ return MemoryOperationNotPerformed;
+ }
+
+ /* double check ownership now of page */
+ CAAM_WRITE(CAAM_BASE | 0x10F4, (page << 16) | 0x5);
+ /* wait for inquiry cmd to complete */
+ while ((CAAM_READ(CAAM_BASE | 0x10FC) & 0x0000C000) > 0 &&
+ (CAAM_READ(CAAM_BASE | 0x10FC) & 0x00003000) == 0) {
+ }
+ if ((CAAM_READ(CAAM_BASE | 0x10FC) & 0x0000000F) == 0 ||
+ (CAAM_READ(CAAM_BASE | 0x10FC) & 0x00003000) > 0) {
+ /* page not owned */
+ return MemoryOperationNotPerformed;
+ }
+
+ return Success;
+}
+
+
+/* Gets the status of a job. Returns Waiting if no output jobs ready to be
+ * read.
+ * If no jobs are done then return Waiting
+ * If jobs are done but does not match desc then return NoActivityReady
+ * Status holds the error values if any */
+static Error caamGetJob(struct CAAM_DEVICE* dev, UINT4* status)
+{
+ UINT4 reg = CAAM_READ(CAAM_BASE | 0x1044); /* JRSTAR0 status */
+ if (status) {
+ *status = 0;
+ }
+
+ /* check for DECO, CCB, and Job Ring error state JRSTAR0 register */
+ if (((reg & 0xF0000000) == 0x20000000) || /* CCB error */
+ ((reg & 0xF0000000) == 0x40000000)|| /* DECO error */
+ ((reg & 0xF0000000) == 0x60000000)) { /* Job Ring error */
+
+ if ((reg & 0x0000000F) > 0) {
+ *status = reg;
+ return Failure;
+ }
+ }
+
+ /* Check number of done jobs in output list */
+ reg = CAAM_READ(CAAM_BASE | 0x103C);
+ if ((reg & 0x000003FF) > 0) {
+ UINT4* out = (UINT4*)(dev->ring.JobOut);
+ if (status) {
+ *status = out[1];
+ }
+
+ if ((dev->ring.Desc ^ 0xF0000000) != out[0]) {
+ db_printf("CAAM job completed vs expected mismatch");
+ return NoActivityReady;
+ }
+
+ if (out[1] > 0) {
+ return Failure;
+ }
+
+ /* increment jobs removed */
+ CAAM_WRITE(CAAM_BASE | 0x1034, 1);
+ }
+ else {
+ /* check if the CAAM is idle and not processing any descriptors */
+ if ((CAAM_READ(CAAM_BASE | 0x0FD4) & 0x00000002) == 2 /* idle */
+ && (CAAM_READ(CAAM_BASE | 0x0FD4) & 0x00000001) == 0) {
+ return NoActivityReady;
+ }
+
+ return Waiting;
+ }
+
+ return Success;
+}
+
+
+/* Initialize CAAM RNG
+ * returns 0 on success */
+static int caamInitRng(struct CAAM_DEVICE* dev)
+{
+ UINT4 reg, status;
+ int ret = 0;
+
+ /* Set up use of the TRNG for seeding wolfSSL HASH-DRBG */
+ CAAM_WRITE(CAAM_RTMCTL, CAAM_PRGM);
+ CAAM_WRITE(CAAM_RTMCTL, CAAM_READ(CAAM_RTMCTL) | 0x40); /* reset */
+
+ /* Set up reading from TRNG */
+ CAAM_WRITE(CAAM_RTMCTL, CAAM_READ(CAAM_RTMCTL) | CAAM_TRNG);
+
+ /* Set up delay for TRNG @TODO Optimizations?
+ * Shift left with RTSDCTL because 0-15 is for sample number
+ * Also setting the max and min frequencies */
+ CAAM_WRITE(CAAM_RTSDCTL, (CAAM_ENT_DLY << 16) | 0x09C4);
+ CAAM_WRITE(CAAM_RTFRQMIN, CAAM_ENT_DLY >> 1); /* 1/2 */
+ CAAM_WRITE(CAAM_RTFRQMAX, CAAM_ENT_DLY << 3); /* up to 8x */
+
+ /* Set back to run mode and clear RTMCL error bit */
+ reg = CAAM_READ(CAAM_RTMCTL) ^ CAAM_PRGM;
+
+ CAAM_WRITE(CAAM_RTMCTL, reg);
+ reg = CAAM_READ(CAAM_RTMCTL);
+ reg |= CAAM_CTLERR;
+ CAAM_WRITE(CAAM_RTMCTL, reg);
+
+ /* check input slot is available and then add */
+ if (CAAM_READ(CAAM_BASE | 0x1014) > 0) {
+ UINT4* in = (UINT4*)dev->ring.JobIn;
+
+ memcpy((unsigned char*)dev->ring.Desc, (unsigned char*)wc_rng_start,
+ sizeof(wc_rng_start));
+
+ in[0] = dev->ring.Desc ^ 0xF0000000; /* physical address */
+ CAAM_WRITE(CAAM_IRJAR0, 0x00000001);
+ }
+ else {
+ return Waiting;
+ }
+
+ do {
+ ret = caamGetJob(dev, &status);
+ /* @TODO use a better way to chill out CPU. */
+ } while (ret == Waiting);
+
+ return ret;
+}
+
+
+static Error caamDoJob(struct DescStruct* desc)
+{
+ Error ret;
+ UINT4 status;
+
+ /* clear and set desc size */
+ desc->desc[0] &= 0xFFFFFF80;
+ desc->desc[0] += desc->idx;
+
+ /* check input slot is available and then add */
+ if (CAAM_READ(CAAM_BASE | 0x1014) > 0) {
+ UINT4* in = (UINT4*)desc->caam->ring.JobIn;
+
+ memcpy((unsigned char*)desc->caam->ring.Desc, (unsigned char*)desc->desc,
+ (desc->idx + 1) * sizeof(UINT4));
+
+ in[0] = desc->caam->ring.Desc ^ 0xF0000000; /* physical address */
+ CAAM_WRITE(CAAM_IRJAR0, 0x00000001);
+ }
+ else {
+ return Waiting;
+ }
+
+ do {
+ ret = caamGetJob(desc->caam, &status);
+ /* @TODO use a better way to chill out CPU. */
+ } while (ret == Waiting);
+
+ if (status != 0 || ret != Success) {
+ #if 0
+ /* Used during testing to print out descriptor */
+ {
+ char msg[2048];
+ char* pt = msg;
+ int z;
+
+ memset(msg, 0, sizeof(msg));
+ for (z = 0; z < desc->idx; z++) {
+ snprintf(pt, sizeof(msg) - (z * 21), "desc[%d] = 0x%8.8x, ",
+ z, desc->desc[z]);
+ pt += 21;
+ }
+ snprintf(pt, sizeof(msg) - (z * 21), "status = 0x%8.8x\n", status);
+ if (desc->buf[0].data != 0) { /* for testing */
+ memcpy((char*)desc->buf[0].data, msg, sizeof(msg));
+ }
+ }
+ #endif
+
+
+ /* try to reset after error */
+ caamReset();
+ return ret;
+ }
+
+ return Success;
+}
+
+
+/* handle input or output buffers
+ * NOTES: if sz == 0 then read all the rest of the buffers available
+ * when align == 1 then there is no alignment constraints
+ *
+ * returns the data size in bytes on success. With failure a negative value is
+ * returned.
+ */
+static int caamAddIO(struct DescStruct* desc, UINT4 options, UINT4 sz,
+ UINT4 align, UINT4* idx)
+{
+ int i, outSz = 0;
+
+ if (align == 0) {
+ return -1; /* programming error */
+ }
+
+ for (i = *idx; i < desc->DescriptorCount; i++) {
+ /* input must be a multiple of "align" bytes */
+ struct buffer* buf = &desc->buf[i];
+ int blocks = buf->dataSz / align;
+ Address data = buf->data;
+ Address dataSz = buf->dataSz;
+
+ if (outSz >= sz && sz != 0) {
+ break;
+ }
+
+ if (dataSz % align > 0) {
+ /* store potential overlap */
+ int tmpSz = dataSz % align;
+ int add = (tmpSz < (align - desc->alignIdx)) ? tmpSz :
+ align - desc->alignIdx;
+ unsigned char* local = (unsigned char*)desc->alignBuf;
+
+ /* if already something in the buffer then add from front */
+ if (desc->alignIdx > 0) {
+ memcpy((unsigned char*)&local[desc->alignIdx],
+ (unsigned char*)data, add);
+ data += add;
+ }
+ else {
+ memcpy((unsigned char*)&local[desc->alignIdx],
+ (unsigned char*)data + (blocks * align), add);
+ }
+ dataSz -= add;
+ desc->alignIdx += add;
+ }
+
+ if (desc->alignIdx == align) {
+ desc->lastFifo = desc->idx;
+ if (desc->idx + 2 > MAX_DESC_SZ) {
+ return -1;
+ }
+ desc->desc[desc->idx++] = options + desc->alignIdx;
+ desc->desc[desc->idx++] = BSP_VirtualToPhysical(desc->alignBuf);
+ ASP_FlushCaches((Address)desc->alignBuf, desc->alignIdx);
+ outSz += desc->alignIdx;
+ }
+
+ if (blocks > 0) {
+ desc->lastFifo = desc->idx;
+ if (desc->idx + 2 > MAX_DESC_SZ) {
+ return -1;
+ }
+ desc->desc[desc->idx++] = options + (blocks * align);
+ desc->desc[desc->idx++] = BSP_VirtualToPhysical(data);
+ outSz += (blocks * align);
+
+ /* only one buffer available for align cases so exit here and make
+ a new descriptor after running current one */
+ if (desc->alignIdx == align) {
+ desc->alignIdx = 0;
+ i++; /* start at next buffer */
+ break;
+ }
+ }
+ }
+
+ *idx = i;
+ return outSz;
+}
+
+
+/******************************************************************************
+ IODevice Register Read and Write
+ ****************************************************************************/
+
+static Error caamReadRegister(IODeviceVector ioCaam, Value reg, Value *out)
+{
+ if (reg < MIN_READ_REG || reg > MAX_READ_REG) {
+ return IllegalRegisterNumber;
+ }
+
+ switch (reg) {
+ case CAAM_STATUS:
+ case CAAM_VERSION_MS:
+ case CAAM_VERSION_LS:
+ case CAMM_SUPPORT_MS:
+ case CAMM_SUPPORT_LS:
+ case CAAM_RTMCTL:
+ *out = CAAM_READ(reg);
+ break;
+
+ default:
+ return IllegalRegisterNumber;
+ }
+
+ (void)ioCaam;
+ return Success;
+}
+
+
+static Error caamWriteRegister(IODeviceVector ioCaam, Value reg, Value in)
+{
+ /* Should be no need for writes */
+ return OperationNotAllowedOnTheUniversalIODevice;
+}
+
+
+/******************************************************************************
+ CAAM Blob Operations
+ ****************************************************************************/
+
+/* limit on size due to size of job ring being 64 word32's */
+static Error caamBlob(struct DescStruct* desc)
+{
+ Error err;
+ UINT4 keyType = 0x00000C08; /* default red */
+ UINT4 i = 0;
+ int sz = 0, ret;
+
+ if (desc->idx + 3 > MAX_DESC_SZ) {
+ return Failure;
+ }
+
+ /*default to Red Key type, with offset of 12 and 8 byte load to context 2*/
+ desc->desc[desc->idx++] = (CAAM_LOAD_CTX | CAAM_CLASS2 | CAAM_IMM | keyType);
+
+ /* add key modifier */
+ if (i < desc->DescriptorCount) {
+ UINT4* pt;
+ Address data = desc->buf[i].data;
+ Address dataSz = desc->buf[i].dataSz;
+
+ pt = (UINT4*)data;
+ if (dataSz < 8) { /* expecting 8 bytes for key modifier*/
+ return TooManyBuffers;
+ }
+ desc->desc[desc->idx++] = pt[0];
+ desc->desc[desc->idx++] = pt[1];
+ }
+
+ /* add input */
+ while (sz < desc->inputSz && i < desc->DescriptorCount) {
+ ret = caamAddIO(desc, CAAM_SEQI, desc->inputSz - sz, 1, &i);
+ if (ret < 0) { /* handle error case */
+ return TooManyBuffers;
+ }
+ sz += ret;
+ }
+ desc->outputIdx = i;
+
+ /* add output */
+ if (caamAddIO(desc, CAAM_SEQO, 0, 1, &i) < 0) {
+ return TooManyBuffers;
+ }
+
+ if (desc->idx + 1 > MAX_DESC_SZ) {
+ return Failure;
+ }
+ desc->desc[desc->idx++] = CAAM_OP | CAAM_OPID_BLOB | desc->type;
+
+ if ((err = caamDoJob(desc)) != Success) {
+ return err;
+ }
+
+ /* flush output buffers */
+ for (i = desc->outputIdx; i < desc->DescriptorCount; i++) {
+ ASP_FlushCaches(desc->buf[i].data, desc->buf[i].dataSz);
+ }
+
+ return Success;
+}
+
+
+/******************************************************************************
+ CAAM AES Operations
+ ****************************************************************************/
+
+/* returns amount written on success and negative value in error case.
+ * Is different from caamAddIO in that it only adds a single input buffer
+ * rather than multiple ones.
+ */
+static int caamAesInput(struct DescStruct* desc, UINT4* idx, int align,
+ UINT4 totalSz)
+{
+ int sz;
+ UINT4 i = *idx;
+
+ /* handle alignment constraints on input */
+ if (desc->alignIdx > 0) {
+ sz = desc->alignIdx;
+
+ /* if there is more input buffers then add part of it */
+ if (i < desc->outputIdx && i < desc->DescriptorCount) {
+ sz = align - desc->alignIdx;
+ sz = (sz <= desc->buf[i].dataSz) ? sz : desc->buf[i].dataSz;
+ memcpy((unsigned char*)(desc->alignBuf) + desc->alignIdx,
+ (unsigned char*)(desc->buf[i].data), sz);
+
+ desc->buf[i].dataSz -= sz;
+ desc->buf[i].data += sz;
+ sz += desc->alignIdx;
+ }
+
+ if (desc->idx + 2 > MAX_DESC_SZ) {
+ return -1;
+ }
+ ASP_FlushCaches((Address)desc->alignBuf, sz);
+ desc->desc[desc->idx++] = (CAAM_FIFO_L | FIFOL_TYPE_LC1 |
+ CAAM_CLASS1 | FIFOL_TYPE_MSG) + sz;
+ desc->desc[desc->idx++] = BSP_VirtualToPhysical(desc->alignBuf);
+ desc->alignIdx = 0;
+ }
+ else {
+ sz = desc->buf[i].dataSz;
+ if ((totalSz + sz) == desc->inputSz) { /* not an issue on final */
+ align = 1;
+ }
+
+ desc->alignIdx = sz % align;
+ if (desc->alignIdx != 0) {
+ sz -= desc->alignIdx;
+ memcpy((unsigned char*)desc->alignBuf,
+ (unsigned char*)(desc->buf[i].data) + sz,
+ desc->alignIdx);
+ }
+
+ if (desc->idx + 2 > MAX_DESC_SZ) {
+ return -1;
+ }
+ desc->desc[desc->idx++] = (CAAM_FIFO_L | FIFOL_TYPE_LC1 |
+ CAAM_CLASS1 | FIFOL_TYPE_MSG) + sz;
+ desc->desc[desc->idx++] = BSP_VirtualToPhysical(desc->buf[i].data);
+ i++;
+ }
+
+ *idx = i;
+ return sz;
+}
+
+
+/* returns enum Success on success, all other return values should be
+ * considered an error.
+ *
+ * ofst is the amount of leftover buffer from previous calls
+ * inputSz is the amount of input in bytes that is being matched to output
+ */
+static Error caamAesOutput(struct DescStruct* desc, int* ofst, UINT4 inputSz)
+{
+ int offset = *ofst;
+
+ if (desc->output != 0 && offset > 0 && inputSz > 0) {
+ UINT4 addSz;
+
+ /* handle potential leftovers */
+ addSz = (inputSz >= offset) ? offset : inputSz;
+
+ inputSz -= addSz;
+ desc->desc[desc->idx++] = CAAM_FIFO_S | FIFOS_TYPE_MSG + addSz;
+ if (inputSz > 0) { /* check if expecting more output */
+ desc->desc[desc->idx - 1] |= CAAM_FIFOS_CONT;
+ }
+ desc->desc[desc->idx++] = BSP_VirtualToPhysical(desc->output);
+
+ if (addSz == offset) {
+ /* reset */
+ desc->output = 0;
+ offset = 0;
+ }
+ else {
+ offset -= addSz;
+ desc->output += addSz;
+
+ if (offset < 0) {
+ return TransferFailed;
+ }
+ }
+ }
+
+ for (; desc->lastIdx < desc->DescriptorCount; desc->lastIdx++) {
+ struct buffer* buf = &desc->buf[desc->lastIdx];
+
+ if (inputSz > 0) {
+ int tmp;
+
+ if (buf->dataSz <= inputSz) {
+ tmp = buf->dataSz;
+ }
+ else {
+ offset = buf->dataSz - inputSz;
+ tmp = inputSz;
+ desc->output = buf->data + tmp;
+ }
+ inputSz -= tmp;
+ if (desc->idx + 2 > MAX_DESC_SZ) {
+ return TransferFailed;
+ }
+ desc->desc[desc->idx++] = CAAM_FIFO_S | FIFOS_TYPE_MSG + tmp;
+ if (inputSz > 0) { /* check if expecting more output */
+ desc->desc[desc->idx - 1] |= CAAM_FIFOS_CONT;
+ }
+ desc->desc[desc->idx++] = BSP_VirtualToPhysical(buf->data);
+ }
+ else {
+ break;
+ }
+ }
+
+ *ofst = offset;
+ return Success;
+}
+
+
+/* check size of output and get starting buffer for it */
+static Error caamAesOutSz(struct DescStruct* desc, UINT4 i)
+{
+ int sz = 0;
+
+ for (desc->outputIdx = i; desc->outputIdx < desc->DescriptorCount &&
+ sz < desc->inputSz; desc->outputIdx++) {
+ sz += desc->buf[desc->outputIdx].dataSz;
+ }
+ desc->lastIdx = desc->outputIdx;
+
+ /* make certain that output size is same as input */
+ sz = 0;
+ for (; desc->lastIdx < desc->DescriptorCount; desc->lastIdx++) {
+ sz += desc->buf[desc->lastIdx].dataSz;
+ }
+ if (sz != desc->inputSz) {
+ return SizeIsTooLarge;
+ }
+ desc->lastIdx = desc->outputIdx;
+
+ return Success;
+}
+
+
+/* AES operations follow the buffer sequence of KEY -> (IV) -> Input -> Output
+ */
+static Error caamAes(struct DescStruct* desc)
+{
+ struct buffer* ctx[3];
+ struct buffer* iv[3];
+ Value ofst = 0;
+ Error err;
+ UINT4 i, totalSz = 0;
+ int ctxIdx = 0;
+ int ivIdx = 0;
+ int offset = 0;
+ int align = 1;
+ int sz = 0;
+
+ int ctxSz = desc->ctxSz;
+
+ if (desc->state != CAAM_ENC && desc->state != CAAM_DEC) {
+ return IllegalStatusNumber;
+ }
+
+ if (ctxSz != 16 && ctxSz != 24 && ctxSz != 32) {
+ return ArgumentError;
+ }
+
+ /* get key */
+ for (i = 0; i < desc->DescriptorCount; i++) {
+ struct buffer* buf = &desc->buf[i];
+ unsigned char* local = (unsigned char*)desc->ctxBuf;
+
+ if (sz < ctxSz && sz < (MAX_CTX * sizeof(UINT4))) {
+ ctx[ctxIdx] = buf;
+ sz += buf->dataSz;
+
+ memcpy((unsigned char*)&local[offset],
+ (unsigned char*)ctx[ctxIdx]->data, ctx[ctxIdx]->dataSz);
+ offset += ctx[ctxIdx]->dataSz;
+ ctxIdx++;
+ }
+ else {
+ break;
+ }
+ }
+
+ /* sanity checks on size of key */
+ if (sz > ctxSz) {
+ return SizeIsTooLarge;
+ }
+ if (ctxSz > (MAX_CTX * sizeof(UINT4)) - 16) {
+ return ArgumentError;
+ }
+
+ /* Flush cache of ctx buffer then :
+ Add KEY Load command 0x0220000X
+ Add address to read key from 0xXXXXXXXX */
+ ASP_FlushCaches((Address)desc->ctxBuf, ctxSz);
+ if (desc->idx + 2 > MAX_DESC_SZ) {
+ return TransferFailed;
+ }
+ desc->desc[desc->idx++] = (CAAM_KEY | CAAM_CLASS1 | CAAM_NWB) + ctxSz;
+ desc->desc[desc->idx++] = BSP_VirtualToPhysical(desc->ctxBuf);
+
+ /* get IV if needed by algorithm */
+ switch (desc->type) {
+ case CAAM_AESECB:
+ break;
+
+ case CAAM_AESCTR:
+ ofst = 0x00001000;
+ /* fall through because states are the same only the offset changes */
+
+ case CAAM_AESCBC:
+ {
+ int maxSz = 16; /* default to CBC/CTR max size */
+
+ sz = 0;
+ offset = 0;
+ for (; i < desc->DescriptorCount; i++) {
+ struct buffer* buf = &desc->buf[i];
+ unsigned char* local = (unsigned char*)desc->iv;
+
+ if (sz < maxSz) {
+ iv[ivIdx] = buf;
+
+ if (buf->dataSz + sz > maxSz) {
+ return SizeIsTooLarge;
+ }
+
+ sz += buf->dataSz;
+ memcpy((unsigned char*)&local[offset],
+ (unsigned char*)iv[ivIdx]->data, iv[ivIdx]->dataSz);
+ offset += iv[ivIdx]->dataSz;
+ ivIdx++;
+ }
+ else {
+ break;
+ }
+ }
+
+ if (sz != maxSz) {
+ /* invalid IV size */
+ return SizeIsTooLarge;
+ }
+
+ ASP_FlushCaches((Address)desc->iv, maxSz);
+ if (desc->idx + 2 > MAX_DESC_SZ) {
+ return TransferFailed;
+ }
+ desc->desc[desc->idx++] = (CAAM_LOAD_CTX | CAAM_CLASS1 | ofst) + maxSz;
+ desc->desc[desc->idx++] = BSP_VirtualToPhysical(desc->iv);
+ }
+ break;
+
+ default:
+ return OperationNotImplemented;
+ }
+
+ /* write operation */
+ if (desc->idx + 1 > MAX_DESC_SZ) {
+ return TransferFailed;
+ }
+ desc->desc[desc->idx++] = CAAM_OP | CAAM_CLASS1 | desc->type |
+ CAAM_ALG_UPDATE | desc->state;
+
+ /* find output buffers */
+ if (caamAesOutSz(desc, i) != Success) {
+ return SizeIsTooLarge;
+ }
+
+ /* set alignment constraints */
+ if (desc->type == CAAM_AESCBC || desc->type == CAAM_AESECB) {
+ align = 16;
+ }
+
+ /* indefinite loop for input/output buffers */
+ desc->headIdx = desc->idx;
+ desc->output = 0;
+ offset = 0; /* store left over amount for output buffer */
+ do {
+ desc->idx = desc->headIdx; /* reset for each loop */
+
+ /* add a single input buffer (multiple ones was giving deco watch dog
+ * time out errors on the FIFO load of 1c.
+ * @TODO this could be a place for optimization if more data could be
+ * loaded in at one time */
+ if ((sz = caamAesInput(desc, &i, align, totalSz)) < 0) {
+ return TransferFailed;
+ }
+ totalSz += sz;
+
+ if (caamAesOutput(desc, &offset, sz) != Success) {
+ return TransferFailed;
+ }
+
+ /* store updated IV */
+ if (ivIdx > 0) {
+ if (desc->idx + 2 > MAX_DESC_SZ) {
+ return TransferFailed;
+ }
+ desc->desc[desc->idx++] = CAAM_STORE_CTX | CAAM_CLASS1 | ofst | 16;
+ desc->desc[desc->idx++] = BSP_VirtualToPhysical((Address)desc->iv);
+ }
+
+ if ((err = caamDoJob(desc)) != Success) {
+ return err;
+ }
+ ASP_FlushCaches((Address)desc->iv, 16);
+ } while (desc->lastIdx < desc->DescriptorCount || offset > 0);
+
+ /* flush output buffers */
+ for (i = desc->outputIdx; i < desc->lastIdx; i++) {
+ ASP_FlushCaches(desc->buf[i].data, desc->buf[i].dataSz);
+ }
+
+ /* handle case with IV */
+ if (ivIdx > 0) {
+ unsigned char* pt = (unsigned char*)desc->iv;
+ ASP_FlushCaches((Address)pt, 16);
+ for (i = 0; i < ivIdx; i++) {
+ memcpy((unsigned char*)iv[i]->data, pt, iv[i]->dataSz);
+ pt += iv[i]->dataSz;
+ ASP_FlushCaches(iv[i]->data, iv[i]->dataSz);
+ }
+ }
+
+ return Success;
+}
+
+
+/******************************************************************************
+ CAAM AEAD Operations
+ ****************************************************************************/
+
+/* AEAD operations follow the buffer sequence of KEY -> (IV or B0 | CTR0) -> (AD)
+ * -> Input -> Output
+ *
+ */
+static Error caamAead(struct DescStruct* desc)
+{
+ struct buffer* ctx[3];
+ struct buffer* iv[3];
+ Value ofst = 0;
+ UINT4 state = CAAM_ALG_INIT;
+ UINT4 totalSz = 0;
+ Error err;
+ UINT4 i;
+ int ctxIdx = 0;
+ int ivIdx = 0;
+ int offset = 0;
+ int sz = 0;
+ int ivSz = 32; /* size of B0 | CTR0 for CCM mode */
+ int ctxSz = desc->ctxSz;
+ int align = 16; /* input should be multiples of 16 bytes unless is final */
+ int opIdx;
+
+ if (desc->state != CAAM_ENC && desc->state != CAAM_DEC) {
+ return IllegalStatusNumber;
+ }
+
+ /* sanity check is valid AES key size */
+ if (ctxSz != 16 && ctxSz != 24 && ctxSz != 32) {
+ return ArgumentError;
+ }
+
+ /* get key */
+ for (i = 0; i < desc->DescriptorCount; i++) {
+ struct buffer* buf = &desc->buf[i];
+ unsigned char* local = (unsigned char*)desc->ctxBuf;
+
+ if (sz < ctxSz && sz < (MAX_CTX * sizeof(UINT4))) {
+ ctx[ctxIdx] = buf;
+ sz += buf->dataSz;
+
+ memcpy((unsigned char*)&local[offset],
+ (unsigned char*)ctx[ctxIdx]->data, ctx[ctxIdx]->dataSz);
+ offset += ctx[ctxIdx]->dataSz;
+ ctxIdx++;
+ }
+ else {
+ break;
+ }
+ }
+
+ /* sanity checks on size of key */
+ if (sz > ctxSz) {
+ return SizeIsTooLarge;
+ }
+
+ /* Flush cache of ctx buffer then :
+ Add KEY Load command 0x0220000X
+ Add address to read key from 0xXXXXXXXX */
+ ASP_FlushCaches((Address)desc->ctxBuf, ctxSz);
+ if (desc->idx + 2 > MAX_DESC_SZ) {
+ return TransferFailed;
+ }
+ desc->desc[desc->idx++] = (CAAM_KEY | CAAM_CLASS1 | CAAM_NWB) + ctxSz;
+ desc->desc[desc->idx++] = BSP_VirtualToPhysical(desc->ctxBuf);
+
+ desc->headIdx = desc->idx;
+ desc->output = 0;
+ offset = 0; /* store left over amount for output buffer */
+ do {
+ desc->idx = desc->headIdx; /* reset for each loop */
+
+ /* write operation */
+ if (desc->idx + 1 > MAX_DESC_SZ) {
+ return TransferFailed;
+ }
+ opIdx = desc->idx;
+ desc->desc[desc->idx++] = CAAM_OP | CAAM_CLASS1 | state | desc->type |
+ desc->state;
+
+ /* get IV if needed by algorithm */
+ switch (desc->type) {
+ case CAAM_AESCCM:
+ if ((state & CAAM_ALG_INIT) == CAAM_ALG_INIT) {
+ sz = 0;
+ offset = 0;
+ for (; i < desc->DescriptorCount; i++) {
+ struct buffer* buf = &desc->buf[i];
+ unsigned char* local = (unsigned char*)desc->iv;
+
+ if (sz < ivSz) {
+ iv[ivIdx] = buf;
+
+ if (buf->dataSz + sz > ivSz) {
+ return SizeIsTooLarge;
+ }
+
+ sz += buf->dataSz;
+ memcpy((unsigned char*)&local[offset],
+ (unsigned char*)iv[ivIdx]->data, iv[ivIdx]->dataSz);
+ offset += iv[ivIdx]->dataSz;
+ ivIdx++;
+ }
+ else {
+ break;
+ }
+ }
+
+ if (sz != ivSz) {
+ /* invalid IV size */
+ return SizeIsTooLarge;
+ }
+ offset = 0;
+ }
+
+ ASP_FlushCaches((Address)desc->iv, ivSz);
+ if (desc->idx + 2 > MAX_DESC_SZ) {
+ return TransferFailed;
+ }
+ desc->desc[desc->idx++] = (CAAM_LOAD_CTX | CAAM_CLASS1 | ofst)
+ + ivSz;
+ desc->desc[desc->idx++] = BSP_VirtualToPhysical(desc->iv);
+ break;
+
+ default:
+ return OperationNotImplemented;
+ }
+
+
+ /********* handle AAD -- is only done with Init **********************/
+ if ((state & CAAM_ALG_INIT) == CAAM_ALG_INIT) {
+ if ((desc->type == CAAM_AESCCM) && (desc->aadSz > 0)) {
+ /* set formatted AAD buffer size for CCM */
+ ASP_FlushCaches((Address)desc->aadSzBuf, sizeof(desc->aadSzBuf));
+ desc->desc[desc->idx++] = CAAM_FIFO_L | CAAM_CLASS1 |
+ FIFOL_TYPE_AAD + desc->aadSz;
+ desc->desc[desc->idx++] = BSP_VirtualToPhysical(desc->aadSzBuf);
+
+ /* now set aadSz to unformatted version for getting buffers */
+ if (desc->aadSz == 2) {
+ unsigned char* pt = (unsigned char*)desc->aadSzBuf;
+ desc->aadSz = (((UINT4)pt[0] & 0xFF) << 8) |
+ ((UINT4)pt[1] & 0xFF);
+ }
+ else {
+ unsigned char* pt = (unsigned char*)desc->aadSzBuf;
+ desc->aadSz = (((UINT4)pt[2] & 0xFF) << 24) |
+ (((UINT4)pt[3] & 0xFF) << 16) |
+ (((UINT4)pt[4] & 0xFF) << 8) |
+ ((UINT4)pt[5] & 0xFF);
+ }
+ }
+
+ /* get additional data buffers */
+ if (desc->aadSz > 0) {
+ sz = 0;
+ for (; i < desc->DescriptorCount; i++) {
+ struct buffer* buf = &desc->buf[i];
+ if (sz < desc->aadSz) {
+ if (desc->idx + 2 > MAX_DESC_SZ) {
+ return TransferFailed;
+ }
+ desc->lastFifo = desc->idx;
+ desc->desc[desc->idx++] = CAAM_FIFO_L | CAAM_CLASS1 |
+ FIFOL_TYPE_AAD + buf->dataSz;
+ desc->desc[desc->idx++] = BSP_VirtualToPhysical(buf->data);
+ sz += buf->dataSz;
+ }
+ else {
+ break;
+ }
+ }
+
+ /* flush AAD from FIFO and pad it to 16 byte block */
+ desc->desc[desc->lastFifo] |= FIFOL_TYPE_FC1;
+ }
+
+ /* find output buffers */
+ if (caamAesOutSz(desc, i) != Success) {
+ return SizeIsTooLarge;
+ }
+ }
+
+ /* handle alignment constraints on input */
+ if ((sz = caamAesInput(desc, &i, align, totalSz)) < 0) {
+ return TransferFailed;
+ }
+ totalSz += sz;
+
+ /* handle output buffers */
+ if (caamAesOutput(desc, &offset, sz) != Success) {
+ return TransferFailed;
+ }
+
+ /* store updated IV, if is last then set offset and final for MAC */
+ if ((desc->lastIdx == desc->DescriptorCount) && (offset == 0)) {
+ ivSz = 16;
+ if (desc->state == CAAM_ENC) {
+ ofst = 32 << 8; /* offset is in 15-8 bits */
+ }
+ else {
+ ofst = 0;
+ }
+ desc->desc[opIdx] |= CAAM_ALG_FINAL;
+ }
+ else {
+ /* if not final then store and use ctr and encrypted ctr from
+ context dword 2,3 and 4,5. Also store MAC and AAD info from
+ context dword 6. */
+ ivSz = 56;
+ ofst = 0;
+ }
+
+ if (desc->idx + 2 > MAX_DESC_SZ) {
+ return TransferFailed;
+ }
+ desc->desc[desc->idx++] = CAAM_STORE_CTX | CAAM_CLASS1 | ofst | ivSz;
+ desc->desc[desc->idx++] = BSP_VirtualToPhysical((Address)desc->iv);
+
+ if ((err = caamDoJob(desc)) != Success) {
+ return err;
+ }
+ state = CAAM_ALG_UPDATE;
+ } while (desc->lastIdx < desc->DescriptorCount || offset > 0);
+
+ /* flush output buffers */
+ for (i = desc->outputIdx; i < desc->lastIdx; i++) {
+ ASP_FlushCaches(desc->buf[i].data, desc->buf[i].dataSz);
+ }
+
+ /* handle case with IV (This is also the output of MAC with AES-CCM) */
+ if (ivIdx > 0) {
+ unsigned char* pt = (unsigned char*)desc->iv;
+ ASP_FlushCaches((Address)pt, ivSz);
+ for (i = 0; i < ivIdx; i++) {
+ memcpy((unsigned char*)iv[i]->data, pt, iv[i]->dataSz);
+ pt += iv[i]->dataSz;
+ ASP_FlushCaches(iv[i]->data, iv[i]->dataSz);
+ }
+ }
+
+ return Success;
+}
+
+
+/******************************************************************************
+ CAAM SHA Operations
+ ****************************************************************************/
+static int shaSize(struct DescStruct* desc)
+{
+ /* sanity check on dataSz for context */
+ switch (desc->type) {
+ case CAAM_MD5:
+ return CAAM_MD5_CTXSZ;
+
+ case CAAM_SHA:
+ return CAAM_SHA_CTXSZ;
+
+ case CAAM_SHA224:
+ return CAAM_SHA224_CTXSZ;
+
+ case CAAM_SHA256:
+ return CAAM_SHA256_CTXSZ;
+
+ case CAAM_SHA384:
+ return CAAM_SHA384_CTXSZ;
+
+ case CAAM_SHA512:
+ return CAAM_SHA512_CTXSZ;
+
+ default:
+ return 0;
+ }
+}
+
+/* SHA operations
+ * start: the index to start traversing through buffers. It's needed to allow
+ * for HMAC to reuse this code.
+ *
+ * return Success on success. All other return values are considered a fail
+ * case.
+ */
+static Error caamSha(struct DescStruct* desc, int start)
+{
+ struct buffer* ctx[3];
+ Error err;
+ UINT4 i;
+ int sz = 0;
+ int ctxIdx = 0;
+ int offset = 0;
+
+ int ctxSz = shaSize(desc);
+
+ /* get context */
+ for (i = start; i < desc->DescriptorCount; i++) {
+ struct buffer* buf = &desc->buf[i];
+ unsigned char* local = (unsigned char*)desc->iv;
+
+ if (sz < ctxSz && sz < (MAX_CTX * sizeof(UINT4))) {
+ ctx[ctxIdx] = buf;
+ sz += buf->dataSz;
+
+ if (ctx[ctxIdx]->dataSz + offset > (MAX_CTX * sizeof(UINT4))) {
+ return SizeIsTooLarge;
+ }
+ memcpy((unsigned char*)&local[offset], (unsigned char*)ctx[ctxIdx]->data,
+ ctx[ctxIdx]->dataSz);
+ offset += ctx[ctxIdx]->dataSz;
+ ctxIdx++;
+ }
+ else {
+ break;
+ }
+ }
+ if (sz > ctxSz || ctxSz > (MAX_CTX * sizeof(UINT4))) {
+ return SizeIsTooLarge;
+ }
+
+ ASP_FlushCaches((Address)desc->iv, ctxSz);
+ /*Manage Context (current digest + 8 byte running message length)*/
+ if ((desc->state & CAAM_ALG_INIT) != CAAM_ALG_INIT) {
+ /* don't load into the class 2 context register on inti.
+ Found that loading in caused context to not get set. */
+ if (desc->idx + 2 > MAX_DESC_SZ) {
+ return TransferFailed;
+ }
+ desc->desc[desc->idx++] = (CAAM_LOAD_CTX | CAAM_CLASS2) + ctxSz;
+ desc->desc[desc->idx++] = BSP_VirtualToPhysical((Address)desc->iv);
+ }
+
+ /* add operation command */
+ desc->desc[desc->idx++] = CAAM_OP | CAAM_CLASS2 | desc->state |
+ desc->type;
+
+ /* Check case where there is no input.
+ In all cases the FIFO Load should be flushed. */
+ if (i == desc->DescriptorCount) {
+ desc->lastFifo = desc->idx;
+ if (desc->idx + 1 > MAX_DESC_SZ) {
+ return TransferFailed;
+ }
+ desc->desc[desc->idx++] = CAAM_FIFO_L | CAAM_CLASS2 |
+ FIFOL_TYPE_MSG | CAAM_IMM;
+ }
+
+ /* save index for looping over input */
+ desc->headIdx = desc->idx;
+ do {
+ desc->idx = desc->headIdx; /* reset for each loop */
+ if (i < desc->DescriptorCount) {
+ /* input must be a multiple of 64 bytes unless in final call */
+ if (((desc->state & CAAM_ALG_FINAL) == CAAM_ALG_FINAL)) {
+ if (caamAddIO(desc, (CAAM_FIFO_L | CAAM_CLASS2 |
+ FIFOL_TYPE_MSG), 0, 1, &i) < 0) {
+ return TooManyBuffers;
+ }
+ }
+ else {
+ if (caamAddIO(desc, (CAAM_FIFO_L | CAAM_CLASS2 |
+ FIFOL_TYPE_MSG), 0, 64, &i) < 0) {
+ return TooManyBuffers;
+ }
+ }
+ }
+
+ desc->desc[desc->lastFifo] |= FIFOL_TYPE_LC2;
+
+ /* set context out */
+ if (desc->idx + 2 > MAX_DESC_SZ) {
+ return TransferFailed;
+ }
+ desc->desc[desc->idx++] = CAAM_STORE_CTX | CAAM_CLASS2 + ctxSz;
+ desc->desc[desc->idx++] = BSP_VirtualToPhysical(desc->iv);
+
+ if ((err = caamDoJob(desc)) != Success) {
+ return err;
+ }
+ /* flush context output for each loop */
+ ASP_FlushCaches((Address)desc->iv, ctxSz);
+ } while (i < desc->DescriptorCount);
+
+ /* store context to buffers */
+ {
+ unsigned char* pt = (unsigned char*)desc->iv;
+ for (i = 0; i < ctxIdx; i++) {
+ memcpy((unsigned char*)ctx[i]->data, pt, ctx[i]->dataSz);
+ pt += ctx[i]->dataSz;
+ ASP_FlushCaches(ctx[i]->data, ctx[i]->dataSz);
+ }
+ }
+
+ return Success;
+}
+
+
+/******************************************************************************
+ CAAM TRNG Operations
+ ****************************************************************************/
+
+/* If Entropy is not ready then return Waiting */
+static Error caamRng(struct DescStruct* desc)
+{
+ int sz = 0;
+ int i;
+
+ Address reg; /* RTENT reg to read */
+ int ofst = sizeof(UINT4);
+
+
+ /* Check ENT_VAL bit to make sure entropy is ready */
+ if ((CAAM_READ(CAAM_RTMCTL) & CAAM_ENTVAL) !=
+ CAAM_ENTVAL) {
+ return Waiting;
+ }
+
+ /* check state of TRNG */
+ if ((CAAM_READ(CAAM_RTSTATUS) & 0x0000FFFF) > 0) {
+ return Failure;
+ }
+
+ /* read entropy from RTENT registers */
+ reg = CAAM_RTENT0;
+
+ for (i = 0; i < desc->DescriptorCount; i++) {
+ struct buffer* buf = &desc->buf[i];
+ unsigned char* local = (unsigned char*)buf->data;
+ sz = buf->dataSz;
+
+ while (sz > 3 && reg <= CAAM_RTENT11) {
+ *((UINT4*)local) = CAAM_READ(reg);
+ reg += ofst;
+ local += ofst;
+ sz -= ofst;
+ }
+
+ if (reg > CAAM_RTENT11 && sz > 0) {
+ return SizeIsTooLarge;
+ }
+
+ /* handle non word32 size amount left over */
+ if (sz > 0) {
+ UINT4 tmp = CAAM_READ(reg);
+ memcpy(local, (unsigned char*)&tmp, sz);
+ }
+
+ ASP_FlushCaches(buf->data, buf->dataSz);
+ }
+
+
+ /* read RTENT11 to trigger new entropy generation */
+ if (reg != CAAM_RTENT11) {
+ CAAM_READ(CAAM_RTENT11);
+ }
+
+ return Success;
+}
+
+
+/******************************************************************************
+ IODevice Start, Transfer and Finish Buffer
+ ****************************************************************************/
+/* args[0] holds the state such as encrypt/decrypt or init/update/final
+ * args[1] holds the ctx/key size
+ * args[2] holds the input size
+ * args[3] dependent on algo (such as AAD size with AES-CCM) */
+static Error caamTransferStart(IODeviceVector ioCaam,
+ Value type, const volatile Value args[4])
+{
+ struct CAAM_DEVICE* local = (struct CAAM_DEVICE*)ioCaam;
+ struct DescStruct* desc;
+
+ /* currently only one desc is available for use */
+ desc = &local->DescArray[0];
+
+ /* check if the desc is idle before using */
+ if (GetIORequestStatus((IORequest)desc) != IdleIORequest) {
+ return ResourceNotAvailable;
+ }
+
+ desc->idx = 0;
+ desc->output = 0;
+ desc->ctxOut = 0;
+ desc->outputIdx = 0;
+ desc->alignIdx = 0;
+ desc->lastFifo = 0;
+ desc->state = args[0];
+ desc->ctxSz = args[1];
+ desc->inputSz = args[2];
+ desc->aadSz = 0;
+ desc->desc[desc->idx++] = CAAM_HEAD; /* later will put size to header*/
+
+ switch (type) {
+ case CAAM_AESECB:
+ case CAAM_AESCBC:
+ if (desc->inputSz % 16 != 0) {
+ return ArgumentError;
+ }
+ /* fall through to break */
+ case CAAM_AESCTR:
+ break;
+
+ case CAAM_AESCCM:
+ memset((unsigned char*)desc->aadSzBuf, 0, sizeof(desc->aadSzBuf));
+ if (args[3] > 0) {
+ /* encode the length in */
+ if (args[3] <= 0xFEFF) {
+ unsigned char* pt = (unsigned char*)desc->aadSzBuf;
+ desc->aadSz = 2;
+ pt[0] = ((args[3] & 0xFF00) >> 8);
+ pt[1] = (args[3] & 0x00FF);
+ }
+ else if (args[3] <= 0xFFFFFFFF) {
+ unsigned char* pt = (unsigned char*)desc->aadSzBuf;
+ desc->aadSz = 6;
+ pt[0] = 0xFF; pt[1] = 0xFE;
+ pt[2] = ((args[3] & 0xFF000000) >> 24);
+ pt[3] = ((args[3] & 0x00FF0000) >> 16);
+ pt[4] = ((args[3] & 0x0000FF00) >> 8);
+ pt[5] = (args[3] & 0x000000FF);
+ }
+ }
+ break;
+
+ case CAAM_MD5:
+ case CAAM_SHA:
+ case CAAM_SHA224:
+ case CAAM_SHA256:
+ case CAAM_SHA384:
+ case CAAM_SHA512:
+ break;
+
+ case CAAM_BLOB_ENCAP:
+ case CAAM_BLOB_DECAP:
+ break;
+
+ case CAAM_ENTROPY:
+ break;
+
+ default:
+ /* unknown type */
+ return UsageNotSupported;
+ }
+
+ desc->DescriptorCount = 0;
+ desc->type = type;
+ desc->running = true;
+ StartIORequest((IORequest)desc);
+
+ /* For now only require READ permissions */
+ SetIORequestBufferPermissions((IORequest)desc, MEMORY_READ);
+ return Success;
+}
+
+
+static Error caamTransferBuffer(IODeviceVector TheIODeviceVector,
+ IORequest req, IODescriptor NewIODescriptor,
+ Address data, Address dataSz)
+{
+ struct DescStruct* desc = (struct DescStruct*)req;
+ Error err;
+
+ switch (desc->type) {
+ case CAAM_AESECB:
+ case CAAM_AESCTR:
+ case CAAM_AESCBC:
+ case CAAM_AESCCM:
+
+ case CAAM_MD5:
+ case CAAM_SHA:
+ case CAAM_SHA224:
+ case CAAM_SHA256:
+ case CAAM_SHA384:
+ case CAAM_SHA512:
+
+ case CAAM_BLOB_ENCAP:
+ case CAAM_BLOB_DECAP:
+ case CAAM_ENTROPY:
+ { /* set buffer for transfer finish */
+ struct buffer* buf;
+ if (desc->DescriptorCount >= MAX_BUF) {
+ return TooManyBuffers;
+ }
+ buf = &desc->buf[desc->DescriptorCount];
+ buf->data = data;
+ buf->dataSz = dataSz;
+ }
+ err = Success;
+ break;
+
+ default:
+ err = UsageNotSupported;
+ }
+
+ if (err != Success) {
+ desc->running = false;
+ DismissIORequest(req);
+ return err;
+ }
+
+ desc->DescriptorCount++;
+ return Success;
+}
+
+
+static Error caamTransferFinish(IODeviceVector ioCaam, IORequest req)
+{
+ struct DescStruct* desc = (struct DescStruct*)req;
+ Error ret;
+
+ /* construct desc */
+ switch (desc->type) {
+ case CAAM_AESECB:
+ case CAAM_AESCTR:
+ case CAAM_AESCBC:
+ ret = caamAes(desc);
+ break;
+
+ case CAAM_AESCCM:
+ ret = caamAead(desc);
+ break;
+
+ case CAAM_MD5:
+ case CAAM_SHA:
+ case CAAM_SHA224:
+ case CAAM_SHA256:
+ case CAAM_SHA384:
+ case CAAM_SHA512:
+ ret = caamSha(desc, 0);
+ break;
+
+ case CAAM_ENTROPY:
+ ret = caamRng(desc);
+ break;
+
+ case CAAM_BLOB_ENCAP:
+ case CAAM_BLOB_DECAP:
+ ret = caamBlob(desc);
+ break;
+
+ default:
+ ret = UsageNotSupported;
+ }
+
+ desc->running = false;
+ DismissIORequest(req);
+ return ret;
+}
+
+
+/******************************************************************************
+ IODevice Interrupt and Init
+ ****************************************************************************/
+
+static Error caamTransferWrite(IODeviceVector ioCaam,
+ IORequest req, Value dataSz, const volatile Value *data)
+{
+ DismissIORequest(req);
+ return UsageNotSupported;
+}
+
+
+static void caamTransferAbort(IODeviceVector ioCaam, IORequest req)
+{
+ DismissIORequest(req);
+}
+
+
+static void caamTransferRecall(IODeviceVector ioCaam, IODescriptor req)
+{
+
+}
+
+
+static void HandleInterrupt(Address id)
+{
+ struct CAAM_DEVICE* local = (struct CAAM_DEVICE*)id;
+ Value InterruptStatus = INTERRUPT_AtomicWrite(&local->InterruptStatus, 0);
+ int i;
+
+ /* Loop through descriptors and try to dismiss them */
+ for (i = 0; i < DESC_COUNT; i++) {
+ struct DescStruct* desc = &local->DescArray[i];
+ if (InterruptStatus & (1 << i)) {
+ desc->running = false;
+ if (GetIORequestStatus((IORequest)desc) == IORequestSuspended) {
+ ContinueIORequest((IORequest)desc);
+ }
+ else {
+ DismissIORequest((IORequest)desc);
+ }
+ }
+ }
+}
+
+
+static Error caamCreate(IODeviceVector ioCaam)
+{
+ return Success;
+}
+
+
+void InitCAAM(void)
+{
+ /* get IO vector and set it up */
+ IODeviceVector ioCaam = &caam.caamVector;
+ unsigned int reg;
+ int i;
+ Error ret;
+
+
+ ioCaam->Create = &caamCreate;
+ ioCaam->ReadRegister = &caamReadRegister;
+ ioCaam->WriteRegister = &caamWriteRegister;
+
+ ioCaam->TransferStart = &caamTransferStart;
+ ioCaam->TransferBuffer = &caamTransferBuffer;
+ ioCaam->TransferWrite = &caamTransferWrite;
+ ioCaam->TransferFinish = &caamTransferFinish;
+ ioCaam->TransferAbort = &caamTransferAbort;
+ ioCaam->TransferRecall = &caamTransferRecall;
+#ifdef HARDWARE_CACHE_COHERENCY
+ ioCaam->IOSynchronizationNotRequired = 1;
+#endif
+
+ RegisterIODeviceVector(ioCaam, DRIVER_NAME);
+ RequestIOTerminationTask(ioCaam, 10);
+
+ /* Initialize descriptors */
+ for (i = 0; i < BUFFER_COUNT; i++) {
+ InitializeIODescriptor(ioCaam, &caam.IODescriptorArray[i]);
+ }
+
+ /* Initialize Descriptors */
+ for (i = 0; i < DESC_COUNT; i++) {
+ InitializeIORequest(ioCaam, &caam.DescArray[i].TheIORequest,
+ IOREQUEST_STANDARD);
+ caam.DescArray[i].running = false;
+ caam.DescArray[i].caam = &caam;
+ }
+
+
+ /* call interrupt to make IORequests available */
+ caam.InterruptStatus = 0;
+ INTERRUPT_InitCall(&caam.HandleInterruptCall,
+ &HandleInterrupt, "Start up CAAM IORequest");
+
+ /* set clock speed for CAAM. Setting it here to allow for restricting
+ access */
+ #define REGS_CCM_BASE (0xf20c4000)
+ #define HW_CCM_CCGR0_ADDR (0xf20c4068)
+ #define CG(x) (3 << (x*2))
+
+ reg = CG(6) | CG(5) | CG(4);
+ *(volatile unsigned int*)HW_CCM_CCGR0_ADDR =
+ *(volatile unsigned int*)HW_CCM_CCGR0_ADDR | reg;
+
+ /* set up job ring */
+
+ /* @TODO create partition in physical memory for job rings
+ current partition security is set to the default */
+ for (i = 1; i < CAAM_PAGE_MAX; i++) {
+ ret = caamCreatePartition(i, i);
+ if (ret == 0) {
+ break;
+ }
+
+ if (ret != MemoryMapMayNotBeEmpty) {
+ INTERRUPT_Panic();
+ }
+ }
+
+ if (ret != 0) {
+ INTERRUPT_Panic();
+ }
+
+ caam.ring.page = i;
+ caam.ring.JobIn = (CAAM_PAGE + (i << 12));
+ caam.ring.JobOut = caam.ring.JobIn + 16;
+ caam.ring.Desc = caam.ring.JobOut + 16;
+
+ /* set physical address of job rings */
+ CAAM_WRITE(CAAM_IRBAR0, caam.ring.JobIn ^ 0xF0000000);
+ CAAM_WRITE(CAAM_ORBAR0, caam.ring.JobOut ^ 0xF0000000);
+
+ /* Initialize job ring sizes to 1 */
+ CAAM_WRITE(CAAM_IRSR0, 1);
+ CAAM_WRITE(CAAM_ORSR0, 1);
+
+ /* set DECO watchdog to time out and flush jobs that cause the DECO to hang */
+ CAAM_WRITE((CAAM_BASE | 0x0004), CAAM_READ(CAAM_BASE | 0x0004) | 0x40000000);
+
+ /* start up RNG if not already started */
+ if (caamInitRng(&caam) != 0) {
+ INTERRUPT_Panic();
+ }
+}
+
+void (*__ghsentry_bspuserinit_InitCAAM)(void) = &InitCAAM;
+
+#endif /* INTEGRITY */
diff --git a/wolfcrypt/src/port/caam/caam_init.c b/wolfcrypt/src/port/caam/caam_init.c
new file mode 100644
index 0000000..014341c
--- /dev/null
+++ b/wolfcrypt/src/port/caam/caam_init.c
@@ -0,0 +1,289 @@
+/* caam_init.c
+ *
+ * Copyright (C) 2006-2020 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 2 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/settings.h>
+
+#if defined(WOLFSSL_IMX6_CAAM) || defined(WOLFSSL_IMX6_CAAM_RNG) || \
+ defined(WOLFSSL_IMX6_CAAM_BLOB)
+
+#include <wolfssl/wolfcrypt/logging.h>
+#include <wolfssl/wolfcrypt/error-crypt.h>
+#include <wolfssl/wolfcrypt/port/caam/wolfcaam.h>
+
+#define WC_CAAM_BLOB_SZ 48
+
+#ifndef WC_CAAM_PASSWORD
+ #define WC_CAAM_PASSWORD "!systempassword"
+#endif
+
+#if defined(__INTEGRITY) || defined(INTEGRITY)
+ #include <INTEGRITY.h>
+ #include <wolfssl/wolfcrypt/port/caam/caam_driver.h>
+ static IODevice caam = NULLIODevice;
+#endif
+
+#if defined(WOLFSSL_CAAM_PRINT) || defined(WOLFSSL_CAAM_DEBUG)
+#include <stdio.h>
+#include <wolfssl/version.h>
+
+static void wc_caamBanner(void)
+{
+ printf("********* wolfSSL Version %s : Printing Out CAAM Information ********\n",
+ LIBWOLFSSL_VERSION_STRING);
+ printf("CAAM Status [0x%8.8x] = 0x%8.8x\n",
+ CAAM_STATUS, WC_CAAM_READ(CAAM_STATUS));
+ printf("CAAM Version MS Register [0x%8.8x] = 0x%8.8x\n",
+ CAAM_VERSION_MS, WC_CAAM_READ(CAAM_VERSION_MS));
+ printf("CAAM Version LS Register [0x%8.8x] = 0x%8.8x\n",
+ CAAM_VERSION_LS, WC_CAAM_READ(CAAM_VERSION_LS));
+ printf("CAAM Support MS Register [0x%8.8x] = 0x%8.8x\n",
+ CAMM_SUPPORT_MS, WC_CAAM_READ(CAMM_SUPPORT_MS));
+ printf("CAAM Support LS [0x%8.8x] = 0x%8.8x\n",
+ CAMM_SUPPORT_LS, WC_CAAM_READ(CAMM_SUPPORT_LS));
+ printf("********************************************************************\n\n");
+}
+#endif
+
+
+/* Allow runtime setting for CAAM IODevice in case user wants to use password
+ * at run time.
+ *
+ * returns 0 on success
+ *
+ * NOTE this is how IODevice is defined in INTEGRITY "typedef struct
+ * IODeviceStruct *IODevice;"
+ */
+int wc_caamSetResource(IODevice ioDev)
+{
+ WOLFSSL_MSG("Setting CAAM driver");
+ caam = ioDev;
+
+ return 0;
+}
+
+/* Check hardware support
+ *
+ * returns 0 on success
+ */
+int wc_caamInit(void)
+{
+ int ret;
+ word32 reg;
+
+ /* get the driver up */
+ if (caam == NULLIODevice) {
+ WOLFSSL_MSG("Starting CAAM driver");
+ if ((ret = (int)RequestResource((Object *)&caam, "wolfSSL_CAAM_Driver",
+ WC_CAAM_PASSWORD)) != (int)Success) {
+ WOLFSSL_MSG("Unable to get the CAAM IODevice, check password?");
+ WOLFSSL_LEAVE("wc_caamInit: error from driver = ", ret);
+ ret = 0; /* not a hard failure because user can set resource */
+ }
+ }
+
+#if defined(WOLFSSL_CAAM_PRINT) || defined(WOLFSSL_CAAM_DEBUG)
+ /* print out CAAM version/info and wolfSSL version */
+ wc_caamBanner();
+#endif
+
+ /* check that for implemented modules
+ * bits 0-3 AES, 4-7 DES, 12-15 Hashing , 16-19 RNG */
+ reg = WC_CAAM_READ(CAMM_SUPPORT_LS);
+
+ #ifndef WC_NO_RNG
+ if (((reg & 0x000F0000) >> 16) > 0) {
+ WOLFSSL_MSG("Found CAAM RNG hardware module");
+ if ((WC_CAAM_READ(CAAM_RTMCTL) & 0x40000001) != 0x40000001) {
+ WOLFSSL_MSG("Error CAAM RNG has not been set up");
+ }
+ }
+ #endif
+
+ #ifndef NO_SHA256
+ if ((reg & 0x0000F000) > 0) {
+ WOLFSSL_MSG("Found CAAM MDHA module");
+ }
+ else {
+ WOLFSSL_MSG("Hashing not supported by CAAM");
+ return WC_HW_E;
+ }
+ #endif
+
+ #ifndef NO_AES
+ if ((reg & 0x0000000F) > 0) {
+ WOLFSSL_MSG("Found CAAM AES module");
+ }
+ else {
+ WOLFSSL_MSG("AES not supported by CAAM");
+ return WC_HW_E;
+ }
+ #endif
+
+ (void)ret;
+ return 0;
+}
+
+
+int wc_caamFree(void)
+{
+ return 0;
+}
+
+
+word32 wc_caamReadRegister(word32 reg)
+{
+ Value out = 0;
+
+ if (caam == NULLIODevice) {
+ WOLFSSL_MSG("Error CAAM IODevice not found! Bad password?");
+ return 0;
+ }
+
+ if (ReadIODeviceRegister(caam, reg, &out) != Success) {
+ WOLFSSL_MSG("Error reading register\n");
+ }
+
+ return (word32)out;
+}
+
+void wc_caamWriteRegister(word32 reg, word32 value)
+{
+ if (caam == NULLIODevice) {
+ WOLFSSL_MSG("Error CAAM IODevice not found! Bad password?");
+ return;
+ }
+
+ if (WriteIODeviceRegister(caam, reg, value) != Success) {
+ WOLFSSL_MSG("Error writing to register\n");
+ }
+}
+
+
+/* return 0 on success and WC_HW_E on failure. Can also return WC_HW_WAIT_E
+ * in the case that the driver is waiting for a resource or RAN_BLOCK_E if
+ * waiting for entropy. */
+int wc_caamAddAndWait(Buffer* buf, word32 arg[4], word32 type)
+{
+ int ret;
+ if (caam == NULLIODevice) {
+ WOLFSSL_MSG("Error CAAM IODevice not found! Bad password?");
+ return WC_HW_E;
+ }
+
+ if ((ret = SynchronousSendIORequest(caam, type, (const Value*)arg, buf))
+ != Success) {
+ #if defined(WOLFSSL_CAAM_PRINT) || defined(WOLFSSL_CAAM_DEBUG)
+ printf("ret of SynchronousSendIORequest = %d type = %d\n", ret, type);
+ #endif
+
+ /* if waiting for resource or RNG return waiting */
+ if (ret == Waiting) {
+ WOLFSSL_MSG("Waiting on entropy from driver");
+ return RAN_BLOCK_E;
+ }
+
+ if (ret == ResourceNotAvailable) {
+ WOLFSSL_MSG("Waiting on CAAM driver");
+ return WC_HW_WAIT_E;
+ }
+
+ return WC_HW_E;
+ }
+
+ (void)ret;
+ return 0;
+}
+
+
+int wc_caamCreateBlob(byte* data, word32 dataSz, byte* out, word32* outSz)
+{
+ Buffer in[3];
+ word32 arg[4];
+ int ret;
+ word32 local[2] = {0,0};
+
+ if (data == NULL || out == NULL || outSz == NULL ||
+ *outSz < dataSz + WC_CAAM_BLOB_SZ) {
+ return BAD_FUNC_ARG;
+ }
+
+ in[0].BufferType = DataBuffer;
+ in[0].TheAddress = (Address)local;
+ in[0].Length = sizeof(local);
+
+ in[1].BufferType = DataBuffer;
+ in[1].TheAddress = (Address)data;
+ in[1].Length = dataSz;
+
+ in[2].BufferType = DataBuffer | LastBuffer;
+ in[2].TheAddress = (Address)out;
+ in[2].Length = dataSz + WC_CAAM_BLOB_SZ;
+
+ arg[2] = dataSz;
+
+ if ((ret = wc_caamAddAndWait(in, arg, CAAM_BLOB_ENCAP)) != 0) {
+ WOLFSSL_MSG("Error with CAAM blob create");
+ return ret;
+ }
+
+ *outSz = dataSz + WC_CAAM_BLOB_SZ;
+ return 0;
+}
+
+
+int wc_caamOpenBlob(byte* data, word32 dataSz, byte* out, word32* outSz)
+{
+ Buffer in[3];
+ word32 arg[4];
+ int ret;
+ word32 local[2] = {0,0};
+
+ if (data == NULL || out == NULL || outSz == NULL ||
+ *outSz < dataSz - WC_CAAM_BLOB_SZ) {
+ return BAD_FUNC_ARG;
+ }
+
+ in[0].BufferType = DataBuffer;
+ in[0].TheAddress = (Address)local;
+ in[0].Length = sizeof(local);
+
+ in[0].BufferType = DataBuffer;
+ in[0].TheAddress = (Address)data;
+ in[0].Length = dataSz;
+
+ in[1].BufferType = DataBuffer | LastBuffer;
+ in[1].TheAddress = (Address)out;
+ in[1].Length = dataSz - WC_CAAM_BLOB_SZ;
+
+ arg[2] = dataSz;
+
+ if ((ret = wc_caamAddAndWait(in, arg, CAAM_BLOB_DECAP)) != 0) {
+ WOLFSSL_MSG("Error with CAAM blob create");
+ return ret;
+ }
+
+ *outSz = dataSz - WC_CAAM_BLOB_SZ;
+ return 0;
+}
+
+#endif /* WOLFSSL_IMX6_CAAM */
+
diff --git a/wolfcrypt/src/port/caam/caam_sha.c b/wolfcrypt/src/port/caam/caam_sha.c
new file mode 100644
index 0000000..74d62fb
--- /dev/null
+++ b/wolfcrypt/src/port/caam/caam_sha.c
@@ -0,0 +1,397 @@
+/* caam_sha.c
+ *
+ * Copyright (C) 2006-2020 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 2 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/settings.h>
+
+#if defined(WOLFSSL_IMX6_CAAM) && !defined(NO_IMX6_CAAM_HASH)
+
+#include <wolfssl/wolfcrypt/logging.h>
+#include <wolfssl/wolfcrypt/error-crypt.h>
+
+#ifdef NO_INLINE
+ #include <wolfssl/wolfcrypt/misc.h>
+#else
+ #define WOLFSSL_MISC_INCLUDED
+ #include <wolfcrypt/src/misc.c>
+#endif
+
+
+#include <INTEGRITY.h>
+#include <wolfssl/wolfcrypt/port/caam/caam_driver.h>
+#include <wolfssl/wolfcrypt/port/caam/wolfcaam.h>
+
+#if defined(WOLFSSL_CAAM_DEBUG) || defined(WOLFSSL_CAAM_PRINT)
+#include <stdio.h>
+#endif
+
+#ifndef NO_SHA
+#include <wolfssl/wolfcrypt/sha.h>
+#endif
+
+#if !defined(NO_SHA256) || defined(WOLFSSL_SHA224)
+#include <wolfssl/wolfcrypt/sha256.h>
+#endif
+
+#if defined(WOLFSSL_SHA384) || defined(WOLFSSL_SHA512)
+#include <wolfssl/wolfcrypt/sha512.h>
+#endif
+
+#ifndef NO_MD5
+#include <wolfssl/wolfcrypt/md5.h>
+#endif
+
+/******************************************************************************
+ Common Code Between SHA Functions
+ ****************************************************************************/
+
+static int _InitSha(wc_Sha* sha, void* heap, int devId, word32 digestSz,
+ word32 type)
+{
+ Buffer buf[1];
+ word32 arg[4];
+ int ret;
+
+ (void)heap;
+ (void)devId;
+
+ if (sha == NULL) {
+ return BAD_FUNC_ARG;
+ }
+
+ XMEMSET(sha, 0, sizeof(Sha));
+
+ /* Set buffer for context */
+ buf[0].BufferType = DataBuffer | LastBuffer;
+ buf[0].TheAddress = (Address)sha->ctx;
+ buf[0].Length = digestSz + WC_CAAM_CTXLEN;
+ buf[0].Transferred = 0;
+
+ arg[0] = CAAM_ALG_INIT;
+ arg[1] = digestSz + WC_CAAM_CTXLEN;
+
+ if ((ret = wc_caamAddAndWait(buf, arg, type)) != 0) {
+ WOLFSSL_MSG("Error with CAAM SHA init");
+ return ret;
+ }
+
+ return 0;
+}
+
+
+static int _ShaUpdate(wc_Sha* sha, const byte* data, word32 len, word32 digestSz,
+ word32 type)
+{
+ Buffer buf[2];
+ word32 arg[4];
+ int ret;
+ byte* local;
+
+ if (sha == NULL ||(data == NULL && len > 0)) {
+ return BAD_FUNC_ARG;
+ }
+
+ if (len == 0) return 0; /* nothing to do */
+
+ local = (byte*)sha->buffer;
+ /* check for filling out existing buffer */
+ if (sha->buffLen > 0) {
+ word32 add = min(len, WC_CAAM_HASH_BLOCK - sha->buffLen);
+ XMEMCPY(&local[sha->buffLen], data, add);
+
+ sha->buffLen += add;
+ data += add;
+ len -= add;
+
+ if (sha->buffLen == WC_CAAM_HASH_BLOCK) {
+ /* Set buffer for context */
+ buf[0].BufferType = DataBuffer;
+ buf[0].TheAddress = (Address)sha->ctx;
+ buf[0].Length = digestSz + WC_CAAM_CTXLEN;
+ buf[0].Transferred = 0;
+
+ /* data to update with */
+ buf[1].BufferType = DataBuffer | LastBuffer;
+ buf[1].TheAddress = (Address)sha->buffer;
+ buf[1].Length = sha->buffLen;
+ buf[1].Transferred = 0;
+
+ arg[0] = CAAM_ALG_UPDATE;
+ arg[1] = digestSz + WC_CAAM_CTXLEN;
+
+ if ((ret = wc_caamAddAndWait(buf, arg, type)) != 0) {
+ WOLFSSL_MSG("Error with CAAM SHA update");
+ return ret;
+ }
+ sha->buffLen = 0; /* cleared out buffer */
+ }
+ }
+
+ /* check if multiple full blocks can be done */
+ if (len >= WC_CAAM_HASH_BLOCK) {
+ word32 sz = len / WC_CAAM_HASH_BLOCK;
+ sz = sz * WC_CAAM_HASH_BLOCK;
+
+ /* Set buffer for context */
+ buf[0].BufferType = DataBuffer;
+ buf[0].TheAddress = (Address)sha->ctx;
+ buf[0].Length = digestSz + WC_CAAM_CTXLEN;
+ buf[0].Transferred = 0;
+
+ /* data to update with */
+ buf[1].BufferType = DataBuffer | LastBuffer;
+ buf[1].TheAddress = (Address)data;
+ buf[1].Length = sz;
+ buf[1].Transferred = 0;
+
+ arg[0] = CAAM_ALG_UPDATE;
+ arg[1] = digestSz + WC_CAAM_CTXLEN;
+
+ if ((ret = wc_caamAddAndWait(buf, arg, type)) != 0) {
+ WOLFSSL_MSG("Error with CAAM SHA update");
+ return ret;
+ }
+
+ len -= sz;
+ data += sz;
+ }
+
+ /* check for left overs */
+ if (len > 0) {
+ word32 add = min(len, WC_CAAM_HASH_BLOCK - sha->buffLen);
+ XMEMCPY(&local[sha->buffLen], data, add);
+ sha->buffLen += add;
+ }
+
+ return 0;
+}
+
+
+static int _ShaFinal(wc_Sha* sha, byte* out, word32 digestSz,
+ word32 type)
+{
+ Buffer buf[2];
+ word32 arg[4];
+ int ret;
+
+ if (sha == NULL || out == NULL) {
+ return BAD_FUNC_ARG;
+ }
+
+ /* Set buffer for context */
+ buf[0].BufferType = DataBuffer;
+ buf[0].TheAddress = (Address)sha->ctx;
+ buf[0].Length = digestSz + WC_CAAM_CTXLEN;
+ buf[0].Transferred = 0;
+
+ /* add any potential left overs */
+ buf[1].BufferType = DataBuffer | LastBuffer;
+ buf[1].TheAddress = (Address)sha->buffer;
+ buf[1].Length = sha->buffLen;
+ buf[1].Transferred = 0;
+
+ arg[0] = CAAM_ALG_FINAL;
+ arg[1] = digestSz + WC_CAAM_CTXLEN;
+
+ if ((ret = wc_caamAddAndWait(buf, arg, type)) != 0) {
+ WOLFSSL_MSG("Error with CAAM SHA init");
+ return ret;
+ }
+
+ return 0;
+}
+
+/******************************************************************************
+ MD5
+ ****************************************************************************/
+#if !defined(NO_MD5)
+int wc_InitMd5_ex(wc_Md5* sha, void* heap, int devId)
+{
+ return _InitSha(sha, heap, devId, MD5_DIGEST_SIZE, CAAM_MD5);
+}
+
+
+int wc_Md5Update(wc_Md5* sha, const byte* data, word32 len)
+{
+ return _ShaUpdate(sha, data, len, MD5_DIGEST_SIZE, CAAM_MD5);
+}
+
+
+int wc_Md5Final(wc_Md5* sha, byte* hash)
+{
+ int ret;
+ if ((ret = _ShaFinal(sha, hash, MD5_DIGEST_SIZE, CAAM_MD5)) != 0) {
+ return ret;
+ }
+
+ XMEMCPY(hash, (byte*)sha->ctx, MD5_DIGEST_SIZE);
+ return _InitSha(sha, NULL, 0, MD5_DIGEST_SIZE, CAAM_MD5);
+}
+#endif /* !NO_MD5 */
+
+
+/******************************************************************************
+ SHA 1
+ ****************************************************************************/
+#if !defined(NO_SHA)
+int wc_InitSha_ex(wc_Sha* sha, void* heap, int devId)
+{
+ return _InitSha(sha, heap, devId, SHA_DIGEST_SIZE, CAAM_SHA);
+}
+
+
+int wc_ShaUpdate(wc_Sha* sha, const byte* data, word32 len)
+{
+ return _ShaUpdate(sha, data, len, SHA_DIGEST_SIZE, CAAM_SHA);
+}
+
+
+int wc_ShaFinal(wc_Sha* sha, byte* out)
+{
+ int ret;
+ if ((ret = _ShaFinal(sha, out, SHA_DIGEST_SIZE, CAAM_SHA)) != 0) {
+ return ret;
+ }
+
+ XMEMCPY(out, (byte*)sha->ctx, SHA_DIGEST_SIZE);
+ return _InitSha(sha, NULL, 0, SHA_DIGEST_SIZE, CAAM_SHA);
+}
+#endif /* !NO_SHA */
+
+
+/******************************************************************************
+ SHA 224
+ ****************************************************************************/
+#ifdef WOLFSSL_SHA224
+int wc_InitSha224_ex(wc_Sha224* sha, void* heap, int devId)
+{
+ return _InitSha(sha, heap, devId, SHA256_DIGEST_SIZE, CAAM_SHA224);
+}
+
+
+int wc_Sha224Update(wc_Sha224* sha, const byte* data, word32 len)
+{
+ return _ShaUpdate(sha, data, len, SHA256_DIGEST_SIZE, CAAM_SHA224);
+}
+
+
+int wc_Sha224Final(wc_Sha224* sha, byte* out)
+{
+ int ret;
+ if ((ret = _ShaFinal(sha, out, SHA256_DIGEST_SIZE, CAAM_SHA224)) != 0) {
+ return ret;
+ }
+
+ XMEMCPY(out, (byte*)sha->ctx, SHA224_DIGEST_SIZE);
+ return _InitSha(sha, NULL, 0, SHA256_DIGEST_SIZE, CAAM_SHA224);
+}
+#endif /* WOLFSSL_SHA224 */
+
+
+/******************************************************************************
+ SHA 256
+ ****************************************************************************/
+#if !defined(NO_SHA256)
+int wc_InitSha256_ex(wc_Sha256* sha, void* heap, int devId)
+{
+ return _InitSha(sha, heap, devId, SHA256_DIGEST_SIZE, CAAM_SHA256);
+}
+
+
+int wc_Sha256Update(wc_Sha256* sha, const byte* data, word32 len)
+{
+ return _ShaUpdate(sha, data, len, SHA256_DIGEST_SIZE, CAAM_SHA256);
+}
+
+
+int wc_Sha256Final(wc_Sha256* sha, byte* out)
+{
+ int ret;
+ if ((ret = _ShaFinal(sha, out, SHA256_DIGEST_SIZE, CAAM_SHA256)) != 0) {
+ return ret;
+ }
+
+ XMEMCPY(out, (byte*)sha->ctx, SHA256_DIGEST_SIZE);
+ return _InitSha(sha, NULL, 0, SHA256_DIGEST_SIZE, CAAM_SHA256);
+}
+#endif /* !NO_SHA256 */
+
+
+/******************************************************************************
+ SHA 384
+ ****************************************************************************/
+#ifdef WOLFSSL_SHA384
+int wc_InitSha384_ex(wc_Sha384* sha, void* heap, int devId)
+{
+ return _InitSha(sha, heap, devId, SHA512_DIGEST_SIZE, CAAM_SHA384);
+}
+
+
+int wc_Sha384Update(wc_Sha384* sha, const byte* data, word32 len)
+{
+ return _ShaUpdate(sha, data, len, SHA512_DIGEST_SIZE, CAAM_SHA384);
+}
+
+
+int wc_Sha384Final(wc_Sha384* sha, byte* out)
+{
+ int ret;
+ if ((ret = _ShaFinal(sha, out, SHA512_DIGEST_SIZE, CAAM_SHA384)) != 0) {
+ return ret;
+ }
+
+ XMEMCPY(out, (byte*)sha->ctx, SHA384_DIGEST_SIZE);
+ return _InitSha(sha, NULL, 0, SHA512_DIGEST_SIZE, CAAM_SHA384);
+}
+#endif /* WOLFSSL_SHA384 */
+
+
+
+/******************************************************************************
+ SHA 512
+ ****************************************************************************/
+#ifdef WOLFSSL_SHA512
+int wc_InitSha512_ex(wc_Sha512* sha, void* heap, int devId)
+{
+ return _InitSha(sha, heap, devId, SHA512_DIGEST_SIZE, CAAM_SHA512);
+}
+
+
+int wc_Sha512Update(wc_Sha512* sha, const byte* data, word32 len)
+{
+ return _ShaUpdate(sha, data, len, SHA512_DIGEST_SIZE, CAAM_SHA512);
+}
+
+
+int wc_Sha512Final(wc_Sha512* sha, byte* out)
+{
+ int ret;
+ if ((ret = _ShaFinal(sha, out, SHA512_DIGEST_SIZE, CAAM_SHA512)) != 0) {
+ return ret;
+ }
+
+ XMEMCPY(out, (byte*)sha->ctx, SHA512_DIGEST_SIZE);
+ return _InitSha(sha, NULL, 0, SHA512_DIGEST_SIZE, CAAM_SHA512);
+}
+#endif /* WOLFSSL_SHA512 */
+
+#endif /* WOLFSSL_IMX6_CAAM */
+