#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#if (defined(__INTEGRITY) || defined(INTEGRITY)) || \
(defined(__QNX__) || defined(__QNXNTO__))
#if defined(__QNX__) || defined(__QNXNTO__)
#include <sys/mman.h>
#ifdef __aarch64__
#include <aarch64/inout.h>
#else
#include <hw/inout.h>
#endif
#include <sys/iofunc.h>
#include <sys/neutrino.h>
#include <wolfssl/wolfcrypt/port/caam/caam_qnx.h>
#endif
#include <wolfssl/wolfcrypt/port/caam/caam_driver.h>
#include <wolfssl/wolfcrypt/port/caam/caam_error.h>
#include <string.h>
struct JobRing {
CAAM_ADDRESS BaseAddr;
CAAM_ADDRESS JobIn;
CAAM_ADDRESS JobOut;
CAAM_ADDRESS Desc;
void* VirtualIn;
void* VirtualOut;
void* VirtualDesc;
Value page;
CAAM_MUTEX jr_lock;
};
struct CAAM_DEVICE {
#if defined(__INTEGRITY) || defined(INTEGRITY)
struct IODeviceVectorStruct caamVector;
struct IODescriptorStruct IODescriptorArray[BUFFER_COUNT];
struct DescStruct DescArray[DESC_COUNT];
volatile Value InterruptStatus;
CALL HandleInterruptCall;
#endif
struct JobRing ring;
CAAM_ADDRESS baseAddr;
unsigned short vrs;
};
#define DRIVER_NAME "wolfSSL_CAAM_Driver"
static struct CAAM_DEVICE caam;
Error caamAddJob(DESCSTRUCT* desc);
Error caamDoJob(DESCSTRUCT* desc);
#ifdef CAAM_DEBUG_MODE
static Error caamDebugDesc(struct DescStruct* desc)
{
int z;
int sz;
unsigned int flag = 0x20000000;
sz = desc->desc[0] & 0x0000007F;
CAAM_WRITE(CAAM_DECORR, 1);
printf("CAAM_DECORR = 0x%08X\n", CAAM_READ(CAAM_DECORR));
printf("STATUS : 0x%08X\n", CAAM_READ(CAAM_DOOPSTA_MS));
printf("CAAM STATUS : 0x%08X\n", CAAM_READ(0x0FD4));
printf("DECO DRG (bit 32 is valid -- running) : 0x%08X\n", CAAM_READ(0x8E04));
printf("Descriptor input :\n");
for (z = 0; z < sz; z = z + 1) {
CAAM_WRITE(CAAM_DODESB + (z*4), desc->desc[z]);
printf("\t0x%08X\n", desc->desc[z]);
}
printf("\n");
printf("command size = %d\n", sz);
if (sz > 4) {
flag |= 0x10000000;
}
CAAM_WRITE(CAAM_DODAR+4, desc->caam->ring.Desc);
CAAM_WRITE(CAAM_DOJQCR_MS, flag);
printf("CAAM STATUS : 0x%08X\n", CAAM_READ(0x0FD4));
printf("DECO DRG (bit 32 is valid -- running) : 0x%08X\n", CAAM_READ(0x8E04));
printf("DECO BUFFER [0x%08X]:\n", CAAM_READ(CAAM_DODAR+4));
printf("\tSTATUS : 0x%08X\n", CAAM_READ(CAAM_DOOPSTA_MS));
printf("\tJRSTAR_JR0 : 0x%08X\n", CAAM_READ(0x1044));
for (z = 0; z < sz; z = z + 1) {
printf("\t0x%08X\n", CAAM_READ(CAAM_DODESB + (z*4)));
}
printf("Next command to be executed = 0x%08X\n", CAAM_READ(0x8804));
printf("Desc = 0x%08X\n", desc->caam->ring.Desc);
printf("DECO BUFFER [0x%08X]:\n", CAAM_READ(CAAM_DODAR+4));
printf("\tSTATUS : 0x%08X\n", CAAM_READ(CAAM_DOOPSTA_MS));
printf("\tJRSTAR_JR0 : 0x%08X\n", CAAM_READ(0x1044));
for (z = 0; z < sz; z = z + 1) {
printf("\t0x%08X\n", CAAM_READ(CAAM_DODESB + (z*4)));
}
printf("Next command to be executed = 0x%08X\n", CAAM_READ(0x8804));
printf("CAAM STATUS : 0x%08X\n", CAAM_READ(0x0FD4));
while ((CAAM_READ(0x8E04) & 0x80000000U) != 0U) {
printf("DECO DRG (bit 32 is valid -- running) : 0x%08X\n",
CAAM_READ(0x8E04));
sleep(1);
}
CAAM_WRITE(CAAM_DECORR, 0);
printf("done with debug job\n");
return Success;
}
#endif
#if defined(WOLFSSL_CAAM_DEBUG) || defined(WOLFSSL_CAAM_PRINT)
static void printSecureMemoryInfo()
{
unsigned int SMVID_MS, SMVID_LS;
printf("SMSTA = 0x%08X\n", CAAM_READ(caam.ring.BaseAddr + 0x0FB4));
printf("SMPO = 0x%08X\n", CAAM_READ(caam.ring.BaseAddr + CAAM_SM_SMPO));
SMVID_MS = CAAM_READ(caam.ring.BaseAddr + CAAM_SM_SMVID_MS);
SMVID_LS = CAAM_READ(caam.ring.BaseAddr + CAAM_SM_SMVID_LS);
printf("\tNumber Partitions : %d\n", ((SMVID_MS >> 12) & 0xFU));
printf("\tNumber Pages : %d\n", (SMVID_MS & 0x3FFU));
printf("\tPage Size : 2^%d\n", ((SMVID_LS >> 16) & 0x7U));
}
#endif
static Error caamReset(void)
{
int t = 100000;
CAAM_WRITE(caam.ring.BaseAddr + JRCFGR_JR,
CAAM_READ(caam.ring.BaseAddr + JRCFGR_JR) | 1);
CAAM_WRITE(caam.ring.BaseAddr + JRCR_JR, 1);
while (t > 0 && ((CAAM_READ(caam.ring.BaseAddr + JRINTR_JR) & 0x4)
== 0x4)) {
t = t - 1;
}
if (t == 0) {
return -1;
}
t = 100000;
CAAM_WRITE(caam.ring.BaseAddr + JRCR_JR, 1);
while (t > 0 && ((CAAM_READ(caam.ring.BaseAddr + JRCR_JR) & 1) == 1)) {
t = t - 1;
}
if (t == 0) {
return -1;
}
if (caam.vrs < 9) {
CAAM_WRITE(caam.baseAddr + CAAM_RSTA, 0x90000000);
CAAM_WRITE(caam.baseAddr + CAAM_DRR, 1);
}
return Success;
}
static Error caamFreePage(unsigned int page)
{
CAAM_WRITE(caam.ring.BaseAddr + CAAM_SM_CMD, (page << 16U) | 0x2U);
while ((CAAM_READ(caam.ring.BaseAddr + CAAM_SM_STATUS) & 0x00004000) > 0 &&
(CAAM_READ(caam.ring.BaseAddr + CAAM_SM_STATUS) & 0x00003000) == 0) {
CAAM_CPU_CHILL();
}
if ((CAAM_READ(caam.ring.BaseAddr + CAAM_SM_STATUS) & 0x00003000) > 0) {
WOLFSSL_MSG("error while deallocating page");
return MemoryMapMayNotBeEmpty;
}
WOLFSSL_MSG("free'd page");
return Success;
}
Error caamFreePart(unsigned int part)
{
unsigned int status;
#if defined(WOLFSSL_CAAM_DEBUG) || defined(WOLFSSL_CAAM_PRINT)
printf("freeing partition %d\n", part);
#endif
CAAM_WRITE(caam.ring.BaseAddr + CAAM_SM_CMD, (part << 8U) | 0x3U);
status = CAAM_READ(caam.ring.BaseAddr + CAAM_SM_STATUS);
while (((status & 0x00004000U) > 0U) && ((status & 0x00003000U) == 0U)) {
CAAM_CPU_CHILL();
status = CAAM_READ(caam.ring.BaseAddr + CAAM_SM_STATUS);
}
if (((status & 0x00003000U) > 0U) || ((status & 0x0000C000U) > 0U)) {
WOLFSSL_MSG("error while deallocating partition");
return MemoryMapMayNotBeEmpty;
}
WOLFSSL_MSG("free'd partition");
return Success;
}
static Error caamFreeAllPart()
{
unsigned int SMPO;
unsigned int i;
WOLFSSL_MSG("Free all partitions");
SMPO = CAAM_READ(caam.ring.BaseAddr + CAAM_SM_SMPO);
for (i = 0; i < 15U; i = i + 1U) {
if ((SMPO & (0x3U << (i * 2U))) == (0x3U << (i * 2U))) {
caamFreePart(i);
}
}
return 0;
}
int caamFindUnusedPartition()
{
unsigned int SMPO;
unsigned int i;
int ret = -1;
SMPO = CAAM_READ(caam.ring.BaseAddr + CAAM_SM_SMPO);
for (i = 0; i < 15U; i = i + 1) {
if ((SMPO & (0x3U << (i * 2U))) == 0U) {
ret = (int)i;
break;
}
}
return ret;
}
static Error caamCreatePartition(unsigned int* page, unsigned int par,
unsigned int flag)
{
int testPage;
unsigned int status;
status = CAAM_READ(caam.ring.BaseAddr + CAAM_SM_SMPO);
if ((status & (0x3U << (par * 2))) > 0) {
if ((status & (0x3U << (par * 2))) == (0x3U << (par * 2))) {
WOLFSSL_MSG("we own this partition!");
}
else {
return MemoryMapMayNotBeEmpty;
}
}
CAAM_WRITE(caam.ring.BaseAddr + CAAM_SMAPR + (par * 16), flag);
for (testPage = 0; testPage < 16; testPage++) {
CAAM_WRITE(caam.ring.BaseAddr + CAAM_SM_CMD, (testPage << 16) | 0x5);
while ((CAAM_READ(caam.ring.BaseAddr + CAAM_SM_STATUS) & 0x00004000) > 0
&& (CAAM_READ(caam.ring.BaseAddr + CAAM_SM_STATUS) & 0x00003000)
== 0) {
CAAM_CPU_CHILL();
}
if ((CAAM_READ(caam.ring.BaseAddr + CAAM_SM_STATUS) & 0x000000C0) ==
0xC0) {
if (caamFreePage(testPage) != Success) {
continue;
}
}
else if ((CAAM_READ(caam.ring.BaseAddr + CAAM_SM_STATUS) & 0x000000C0)
== 0x00) {
WOLFSSL_MSG("testPage available and un-owned");
}
else {
WOLFSSL_MSG("we don't own the testPage...");
continue;
}
CAAM_WRITE(caam.ring.BaseAddr + CAAM_SM_CMD, (testPage << 16) |
(par << 8) | 0x1);
while ((CAAM_READ(caam.ring.BaseAddr + CAAM_SM_STATUS) & 0x00004000) > 0 &&
(CAAM_READ(caam.ring.BaseAddr + CAAM_SM_STATUS) & 0x00003000) == 0) {
CAAM_CPU_CHILL();
}
break;
}
if (testPage == 16)
return -1;
*page=testPage;
return Success;
}
CAAM_ADDRESS caamGetPartition(unsigned int part, int partSz, unsigned int flag)
{
int err;
(void)flag;
err = caamCreatePartition(&part, part, CAAM_SM_CSP | CAAM_SM_SMAP_LOCK |
CAAM_SM_CSP | CAAM_SM_ALL_RW);
if (err != Success) {
WOLFSSL_MSG("Error creating partitions for secure ecc key");
return 0;
}
return (CAAM_ADDRESS)(CAAM_PAGE + (part << 12));
}
static Error caamGetJob(struct CAAM_DEVICE* dev, unsigned int* status)
{
CAAM_ADDRESS baseAddr;
unsigned int reg;
if (status) {
*status = 0;
}
baseAddr = caam.ring.BaseAddr;
#ifdef CAAM_DEBUG_MODE
(void)dev;
return Success;
#endif
reg = CAAM_READ(baseAddr + CAAM_ORJAR);
#if defined(WOLFSSL_CAAM_DEBUG) || defined(WOLFSSL_CAAM_PRINT)
printf("number of jobs in output list = 0x%08X\n", reg);
#endif
if ((reg & 0x000003FF) > 0) {
unsigned int *pt;
if (CAAM_ADR_SYNC(caam.ring.VirtualOut, (2 * CAAM_JOBRING_SIZE *
sizeof(unsigned int))) != 0) {
return -1;
}
pt = (unsigned int*)caam.ring.VirtualOut;
if (pt[0] != (unsigned int)caam.ring.Desc) {
#if defined(WOLFSSL_CAAM_DEBUG) || defined(WOLFSSL_CAAM_PRINT)
printf("Job found %08X does not match expected job %08X\n",
pt[0], (unsigned int)caam.ring.Desc);
#endif
return -1;
}
*status = pt[1];
#if defined(WOLFSSL_CAAM_DEBUG) || defined(WOLFSSL_CAAM_PRINT)
printf("\tjob 0x%08X done - result 0x%08X\n", pt[0], pt[1]);
printf("removing job from list\n");
fflush(stdout);
#endif
CAAM_WRITE(baseAddr + CAAM_ORJRR, 1);
}
else {
if ((CAAM_READ(baseAddr + 0x0FD4) & 0x00000002) == 2
&& (CAAM_READ(baseAddr + 0x0FD4) & 0x00000001) == 0) {
WOLFSSL_MSG("caam is idle.....");
return NoActivityReady;
}
return CAAM_WAITING;
}
(void)dev;
CAAM_WRITE(baseAddr + JRCFGR_JR, 0);
if (*status == 0) {
return Success;
}
return Failure;
}
#define WC_RNG_START_SIZE 6
static unsigned int wc_rng_start[WC_RNG_START_SIZE] = {
CAAM_HEAD | 0x00000006,
CAAM_OP | CAAM_CLASS1 | CAAM_RNG | 0x00000004,
CAAM_JUMP | 0x02000001,
CAAM_LOAD | 0x00880004,
0x00000001,
CAAM_OP | CAAM_CLASS1 | CAAM_RNG | 0x00001000
};
int caamInitRng(struct CAAM_DEVICE* dev);
int caamInitRng(struct CAAM_DEVICE* dev)
{
DESCSTRUCT desc;
unsigned int reg, entropy_delay;
int ret = 0, i;
memset(&desc, 0, sizeof(DESCSTRUCT));
desc.desc[desc.idx++] = CAAM_HEAD;
for (i = 1; i < WC_RNG_START_SIZE; i++) {
desc.desc[desc.idx++] = wc_rng_start[i];
}
desc.caam = dev;
for (entropy_delay = CAAM_ENT_DLY; entropy_delay <= CAAM_ENT_DLY_MAX;
entropy_delay = entropy_delay + CAAM_ENT_DLY_INCREMENT) {
CAAM_WRITE(caam.baseAddr + CAAM_RTMCTL, CAAM_PRGM);
CAAM_WRITE(caam.baseAddr + CAAM_RTMCTL,
CAAM_READ(caam.baseAddr + CAAM_RTMCTL) | CAAM_RTMCTL_RESET);
CAAM_WRITE(caam.baseAddr + CAAM_RTMCTL,
CAAM_READ(caam.baseAddr + CAAM_RTMCTL) | CAAM_TRNG);
CAAM_WRITE(caam.baseAddr + CAAM_RTSDCTL,
(entropy_delay << 16) | CAAM_ENT_SAMPLE);
CAAM_WRITE(caam.baseAddr + CAAM_RTFRQMIN,
entropy_delay >> CAAM_ENT_MINSHIFT);
CAAM_WRITE(caam.baseAddr + CAAM_RTFRQMAX,
entropy_delay << CAAM_ENT_MAXSHIFT);
#ifdef WOLFSSL_CAAM_PRINT
printf("Attempt with entropy delay set to %d\n", entropy_delay);
printf("Min delay of %d and max of %d\n",
entropy_delay >> CAAM_ENT_MINSHIFT,
entropy_delay << CAAM_ENT_MAXSHIFT);
#endif
reg = CAAM_READ(caam.baseAddr + CAAM_RTMCTL) & (~CAAM_PRGM);
CAAM_WRITE(caam.baseAddr + CAAM_RTMCTL, reg);
reg = CAAM_READ(caam.baseAddr + CAAM_RTMCTL);
reg |= CAAM_CTLERR;
CAAM_WRITE(caam.baseAddr + CAAM_RTMCTL, reg);
reg = CAAM_READ(caam.baseAddr + CAAM_RDSTA);
if (((reg >> 16) & 0xF) > 0) {
WOLFSSL_MSG("RNG is in error state, resetting");
caamReset();
}
if (reg & (1U << 30)) {
WOLFSSL_MSG("JKDKEK rng was setup using a non deterministic key");
return 0;
}
do {
ret = caamDoJob(&desc);
} while (ret == CAAM_WAITING);
if (ret == Success) {
WOLFSSL_MSG("Init RNG success");
break;
}
WOLFSSL_MSG("Increasing entropy delay");
}
if (ret == Success)
return 0;
return -1;
}
Error caamAddJob(DESCSTRUCT* desc)
{
CAAM_ADDRESS baseAddr;
desc->desc[0] &= 0xFFFFFF80;
desc->desc[0] += desc->idx + (desc->startIdx << 16);
CAAM_LOCK_MUTEX(&caam.ring.jr_lock);
baseAddr = caam.ring.BaseAddr;
if (CAAM_READ(baseAddr + CAAM_IRSAR_JR) > 0) {
int i;
unsigned int *pt;
pt = (unsigned int*)caam.ring.VirtualDesc;
#if defined(WOLFSSL_CAAM_PRINT)
printf("Number of input ring slots available is %d\n",
CAAM_READ(baseAddr + CAAM_IRSAR_JR));
printf("Doing Job :\n");
#endif
for (i = 0; i < desc->idx; i = i + 1) {
pt[i] = desc->desc[i];
#if defined(WOLFSSL_CAAM_PRINT)
printf("\tCMD %02d [%p] = 0x%08X\n", i+1, pt + i,
desc->desc[i]);
#endif
}
pt = (unsigned int*)caam.ring.VirtualIn;
pt[0] = (unsigned int)caam.ring.Desc;
if (CAAM_ADR_SYNC(caam.ring.VirtualIn,
(CAAM_JOBRING_SIZE * sizeof(unsigned int)) +
(desc->idx * sizeof(unsigned int))) != 0) {
CAAM_UNLOCK_MUTEX(&caam.ring.jr_lock);
return -1;
}
#ifdef CAAM_DEBUG_MODE
caamDebugDesc(desc);
#else
#if defined(WOLFSSL_CAAM_DEBUG) || defined(WOLFSSL_CAAM_PRINT)
printf("started job 0x%08X done\n", (unsigned int)caam.ring.Desc);
#endif
CAAM_WRITE(baseAddr + CAAM_IRJAR0, 0x00000001);
#endif
}
else {
CAAM_UNLOCK_MUTEX(&caam.ring.jr_lock);
return CAAM_WAITING;
}
CAAM_UNLOCK_MUTEX(&caam.ring.jr_lock);
return Success;
}
Error caamDoJob(DESCSTRUCT* desc)
{
Error ret;
unsigned int status;
ret = caamAddJob(desc);
if (ret != Success) {
return ret;
}
do {
ret = caamGetJob(desc->caam, &status);
CAAM_CPU_CHILL();
} while (ret == CAAM_WAITING);
#if defined(WOLFSSL_CAAM_DEBUG) || defined(WOLFSSL_CAAM_PRINT)
printf("job status = 0x%08X, ret = %d\n", status, ret);
#endif
if (status != 0 || ret != Success) {
if (caamParseJRError(CAAM_READ(caam.ring.BaseAddr + JRINTR_JR)) != 0) {
caamReset();
}
caamParseError(status);
return ret;
}
return Success;
}
int caamBlob(DESCSTRUCT* desc)
{
void *vaddrOut, *vaddr, *keymod;
Error err;
unsigned int keyType = 0x00000C08;
unsigned int i = 0;
int inputSz;
int outputSz;
if (desc->idx + 3 > MAX_DESC_SZ) {
return Failure;
}
if (desc->state) {
WOLFSSL_MSG("making a black blob");
keyType = 0x00000010;
}
desc->desc[desc->idx++] = (CAAM_LOAD_CTX | CAAM_CLASS2 | keyType);
keymod = CAAM_ADR_MAP(desc->buf[i].data, desc->buf[i].dataSz, 1);
desc->desc[desc->idx++] = CAAM_ADR_TO_PHYSICAL(keymod, desc->buf[i].dataSz);
i++;
inputSz = desc->buf[i].dataSz;
if (desc->state && (desc->type == CAAM_BLOB_ENCAP)) {
inputSz += BLACK_KEY_MAC_SZ;
}
vaddr = CAAM_ADR_MAP(desc->buf[i].data, inputSz, 1);
desc->desc[desc->idx++] = CAAM_SEQI + desc->buf[i].dataSz;
desc->desc[desc->idx++] = CAAM_ADR_TO_PHYSICAL(vaddr, inputSz);
i++;
desc->outputIdx = i;
outputSz = desc->buf[i].dataSz;
if (desc->state && (desc->type == CAAM_BLOB_DECAP)) {
outputSz += BLACK_KEY_MAC_SZ;
}
vaddrOut = CAAM_ADR_MAP(desc->buf[i].data, outputSz, 0);
desc->desc[desc->idx++] = CAAM_SEQO + desc->buf[i].dataSz;
desc->desc[desc->idx++] = CAAM_ADR_TO_PHYSICAL(vaddrOut, outputSz);
if (desc->idx + 1 > MAX_DESC_SZ) {
return Failure;
}
desc->desc[desc->idx] = CAAM_OP | CAAM_OPID_BLOB | desc->type;
if (desc->state) {
desc->desc[desc->idx] |= 0x104;
}
desc->idx++;
do {
err = caamDoJob(desc);
} while (err == CAAM_WAITING);
CAAM_ADR_UNMAP(keymod, desc->buf[0].data, desc->buf[0].dataSz, 0);
CAAM_ADR_UNMAP(vaddr, desc->buf[1].data, inputSz, 0);
CAAM_ADR_UNMAP(vaddrOut, desc->buf[2].data, outputSz, 1);
return err;
}
static void caamAddFIFOLPhy(DESCSTRUCT* desc, unsigned int in, int inSz,
unsigned int flush)
{
if (inSz > 0xFFFF) {
desc->desc[desc->idx++] = (CAAM_FIFO_L | flush | FIFOS_EXT |
CAAM_CLASS1 | FIFOL_TYPE_MSG);
desc->desc[desc->idx++] = in;
desc->desc[desc->idx++] = inSz;
}
else {
desc->desc[desc->idx++] = (CAAM_FIFO_L | flush |
CAAM_CLASS1 | FIFOL_TYPE_MSG) + inSz;
desc->desc[desc->idx++] = in;
}
}
static void caamAddFIFOL(DESCSTRUCT* desc, void* in, int inSz,
unsigned int flush)
{
caamAddFIFOLPhy(desc, CAAM_ADR_TO_PHYSICAL(in, inSz), inSz, flush);
}
static void caamAddFIFOSPhy(DESCSTRUCT* desc, unsigned int out, int outSz)
{
if (outSz > 0xFFFF) {
desc->desc[desc->idx++] = CAAM_FIFO_S | FIFOS_TYPE_MSG | FIFOS_EXT;
desc->desc[desc->idx++] = out;
desc->desc[desc->idx++] = outSz;
}
else {
desc->desc[desc->idx++] = (CAAM_FIFO_S | FIFOS_TYPE_MSG) + outSz;
desc->desc[desc->idx++] = out;
}
}
static void caamAddFIFOS(DESCSTRUCT* desc, void* out, int outSz)
{
caamAddFIFOSPhy(desc, CAAM_ADR_TO_PHYSICAL(out, outSz), outSz);
}
int caamAesCmac(DESCSTRUCT* desc, int sz, unsigned int args[4])
{
Error err;
unsigned int keySz;
unsigned int macSz = 0;
void *vaddr[4] = {0};
unsigned int vidx = 0;
unsigned int ctx;
unsigned int isBlackKey;
int i;
isBlackKey = args[2];
keySz = args[1];
vaddr[vidx] = CAAM_ADR_MAP(desc->buf[1].data, desc->buf[1].dataSz, 1);
ctx = CAAM_ADR_TO_PHYSICAL(vaddr[vidx], desc->buf[1].dataSz);
vidx++;
desc->desc[desc->idx] = (CAAM_KEY | CAAM_CLASS1 | CAAM_NWB) + keySz;
if (isBlackKey) {
desc->desc[desc->idx] |= CAAM_LOAD_BLACK_KEY;
macSz = BLACK_KEY_MAC_SZ;
}
desc->idx++;
vaddr[vidx] = CAAM_ADR_MAP(desc->buf[0].data, desc->buf[0].dataSz + macSz, 1);
desc->desc[desc->idx++] = CAAM_ADR_TO_PHYSICAL(vaddr[vidx],
desc->buf[0].dataSz + macSz);
DEBUG_PRINT_ARRAY(vaddr[vidx], keySz, "AES CMAC Key");
vidx++;
if ((desc->state & CAAM_ALG_INIT) == 0) {
int ofst = 0;
desc->desc[desc->idx++] = (CAAM_LOAD_CTX | CAAM_CLASS1 | ofst) +
desc->buf[1].dataSz;
desc->desc[desc->idx++] = ctx;
DEBUG_PRINT_ARRAY(vaddr[0], 32, "AES CMAC CTX");
}
desc->desc[desc->idx++] = CAAM_OP | CAAM_CLASS1 | desc->type | desc->state;
for (i = 2; i < sz; i = i + 1) {
desc->desc[desc->idx] = (CAAM_FIFO_L | CAAM_CLASS1 | FIFOL_TYPE_MSG)
+ desc->buf[i].dataSz;
if (i+1 == sz) {
desc->desc[desc->idx] |= FIFOL_TYPE_LC1;
}
desc->idx++;
vaddr[vidx] = CAAM_ADR_MAP(desc->buf[i].data, desc->buf[i].dataSz, 1);
desc->desc[desc->idx++] = CAAM_ADR_TO_PHYSICAL(vaddr[vidx],
desc->buf[i].dataSz);
DEBUG_PRINT_ARRAY(vaddr[vidx], desc->buf[i].dataSz, "AES CMAC Input");
vidx++;
}
if (sz == 2) {
desc->desc[desc->idx++] = CAAM_FIFO_L | FIFOL_TYPE_LC1 | CAAM_CLASS1 |
FIFOL_TYPE_MSG;
vaddr[vidx] = CAAM_ADR_MAP(0, 0, 0);
desc->desc[desc->idx++] = CAAM_ADR_TO_PHYSICAL(vaddr[vidx], 0);
vidx++;
}
desc->desc[desc->idx++] = CAAM_STORE_CTX | CAAM_CLASS1 | 32;
desc->desc[desc->idx++] = ctx;
do {
err = caamDoJob(desc);
} while (err == CAAM_WAITING);
DEBUG_PRINT_ARRAY(vaddr[0], 32, "AES CMAC CTX");
vidx = 0;
CAAM_ADR_UNMAP(vaddr[vidx++], desc->buf[1].data, desc->buf[1].dataSz, 1);
CAAM_ADR_UNMAP(vaddr[vidx++], desc->buf[0].data, desc->buf[0].dataSz + macSz, 0);
if (sz == 2) {
CAAM_ADR_UNMAP(vaddr[vidx], 0, 0, 0);
}
else {
for (i = 2; i < sz; i = i + 1) {
CAAM_ADR_UNMAP(vaddr[vidx++], desc->buf[i].data,
desc->buf[i].dataSz, 0);
}
}
return err;
}
int caamAead(DESCSTRUCT* desc, CAAM_BUFFER* buf, unsigned int args[4])
{
int fifol = 0;
Value ofst = 0;
Error err;
int ivSz = 0;
void *iv, *key, *in, *out, *tag;
int keySz;
int tagSz;
int inSz;
int outSz;
int idx = 0;
void* aadCtxBuf = NULL;
int state = CAAM_ALG_INITF;
unsigned int aadSz;
if (desc->state != CAAM_ENC && desc->state != CAAM_DEC) {
return CAAM_ARGS_E;
}
keySz = buf[idx].Length;
if (keySz != 16 && keySz != 24 && keySz != 32) {
WOLFSSL_MSG("Bad AES key size found");
return CAAM_ARGS_E;
}
aadSz = (args[0] >> 16) & 0xFFFF;
key = (void*)buf[idx].TheAddress;
desc->desc[desc->idx++] = (CAAM_KEY | CAAM_CLASS1 | CAAM_NWB) + keySz;
desc->desc[desc->idx++] = CAAM_ADR_TO_PHYSICAL(key, keySz);
DEBUG_PRINT_ARRAY(key, keySz, "AES AEAD Key");
idx++;
desc->desc[desc->idx] = CAAM_OP | CAAM_CLASS1 | desc->type |
state | desc->state;
if (desc->state == CAAM_DEC) {
desc->desc[desc->idx] |= CAAM_ALG_IVC;
}
desc->idx++;
switch (desc->type) {
case CAAM_AESGCM:
{
ivSz = buf[idx].Length;
iv = (void*)buf[idx].TheAddress;
fifol = desc->idx;
desc->desc[desc->idx++] = (CAAM_FIFO_L | CAAM_CLASS1 |
FIFOL_TYPE_FC1 | FIFOL_TYPE_IV) + ivSz;
desc->desc[desc->idx++] = CAAM_ADR_TO_PHYSICAL(iv, ivSz);
idx++;
}
break;
case CAAM_AESCCM:
{
ivSz = buf[idx].Length;
iv = (void*)buf[idx].TheAddress;
desc->desc[desc->idx++] = (CAAM_LOAD_CTX | CAAM_CLASS1 | ofst) +
ivSz;
desc->desc[desc->idx++] = CAAM_ADR_TO_PHYSICAL(iv, ivSz);
idx++;
}
break;
default:
WOLFSSL_MSG("Mode of AES not implemented");
return CAAM_ARGS_E;
}
DEBUG_PRINT_ARRAY(iv, ivSz, "AES AEAD IV");
inSz = buf[idx].Length;
in = (void*)buf[idx].TheAddress;
DEBUG_PRINT_ARRAY(in, inSz, "AES AEAD Input");
idx++;
outSz = buf[idx].Length;
out = (void*)buf[idx].TheAddress;
idx++;
tagSz = buf[idx].Length;
tag = (void*)buf[idx].TheAddress;
idx++;
if (aadSz > 0) {
if (desc->type == CAAM_AESCCM) {
unsigned char* pt;
aadCtxBuf = CAAM_ADR_MAP(0, 4, 0);
pt = (unsigned char*)aadCtxBuf;
memset(pt, 0, 4);
if (aadSz <= 0xFEFF) {
pt[0] = (aadSz & 0xFF00) >> 8;
pt[1] = (aadSz & 0x00FF);
desc->desc[desc->idx++] = (CAAM_FIFO_L | CAAM_CLASS1 |
FIFOL_TYPE_AAD) + 2;
}
else {
pt[0] = (aadSz >> 24) & 0xFF;
pt[1] = (aadSz >> 16) & 0xFF;
pt[2] = (aadSz >> 8 ) & 0xFF;
pt[3] = aadSz & 0xFF;
fifol = desc->idx;
desc->desc[desc->idx++] = (CAAM_FIFO_L | CAAM_CLASS1 |
FIFOL_TYPE_AAD) + 4;
}
desc->desc[desc->idx++] = CAAM_ADR_TO_PHYSICAL(aadCtxBuf, 4);
CAAM_ADR_SYNC(aadCtxBuf, 4);
}
fifol = desc->idx;
desc->desc[desc->idx++] = (CAAM_FIFO_L | CAAM_CLASS1 | FIFOL_TYPE_FC1 |
FIFOL_TYPE_AAD) + aadSz;
desc->desc[desc->idx++] = CAAM_ADR_TO_PHYSICAL((void*)buf[idx].TheAddress,
buf[idx].Length);
DEBUG_PRINT_ARRAY((void*)buf[idx].TheAddress, aadSz, "AES AEAD AAD");
idx++;
}
if (outSz > 0) {
caamAddFIFOS(desc, out, outSz);
}
if (inSz > 0) {
fifol = desc->idx;
caamAddFIFOL(desc, in, inSz, FIFOL_TYPE_FC1);
}
if (desc->state == CAAM_DEC) {
fifol = desc->idx;
desc->desc[desc->idx++] = (CAAM_FIFO_L | FIFOL_TYPE_FC1 |
CAAM_CLASS1 | FIFOL_TYPE_IVC) + tagSz;
desc->desc[desc->idx++] = CAAM_ADR_TO_PHYSICAL(tag, tagSz);
}
desc->desc[fifol] &= ~FIFOL_TYPE_FC1;
desc->desc[fifol] |= FIFOL_TYPE_LC1;
if (desc->state == CAAM_ENC) {
switch (desc->type) {
case CAAM_AESGCM:
desc->desc[desc->idx++] = CAAM_STORE_CTX | CAAM_CLASS1 | tagSz;
desc->desc[desc->idx++] = CAAM_ADR_TO_PHYSICAL(tag, tagSz);
break;
case CAAM_AESCCM:
desc->desc[desc->idx++] = CAAM_STORE_CTX | CAAM_CLASS1 |
(32 << 8) | tagSz;
desc->desc[desc->idx++] = CAAM_ADR_TO_PHYSICAL(tag, tagSz);
break;
}
}
do {
err = caamDoJob(desc);
} while (err == CAAM_WAITING);
if (aadCtxBuf != NULL)
CAAM_ADR_UNMAP(aadCtxBuf, 0, 4, 0);
DEBUG_PRINT_ARRAY(tag, tagSz, "AES AEAD Tag Out");
DEBUG_PRINT_ARRAY(out, outSz, "AES AEAD Output");
return err;
}
static int caamAesInternal(DESCSTRUCT* desc,
unsigned int keyPhy, int keySz,
unsigned int ivPhy, int ivSz,
unsigned int inPhy, int inSz,
unsigned int outPhy, int outSz)
{
Value ofst = 0;
Error err;
int state = CAAM_ALG_UPDATE;
if (desc->state != CAAM_ENC && desc->state != CAAM_DEC) {
return CAAM_ARGS_E;
}
if (keySz != 16 && keySz != 24 && keySz != 32) {
WOLFSSL_MSG("Bad AES key size found");
return CAAM_ARGS_E;
}
desc->desc[desc->idx++] = (CAAM_KEY | CAAM_CLASS1 | CAAM_NWB) + keySz;
desc->desc[desc->idx++] = keyPhy;
switch (desc->type) {
case CAAM_AESECB:
break;
case CAAM_AESCTR:
ofst = 0x00001000;
case CAAM_AESCBC:
{
int maxSz = 16;
if (ivSz != maxSz) {
WOLFSSL_MSG("Invalid AES-CBC IV size\n");
return CAAM_ARGS_E;
}
desc->desc[desc->idx++] = (CAAM_LOAD_CTX | CAAM_CLASS1 | ofst) +
maxSz;
desc->desc[desc->idx++] = ivPhy;
}
break;
default:
WOLFSSL_MSG("Mode of AES not implemented");
return CAAM_ARGS_E;
}
desc->desc[desc->idx++] = CAAM_OP | CAAM_CLASS1 | desc->type |
state | desc->state;
caamAddFIFOLPhy(desc, inPhy, inSz, FIFOL_TYPE_LC1);
caamAddFIFOSPhy(desc, outPhy, outSz);
switch (desc->type) {
case CAAM_AESCBC:
case CAAM_AESCTR:
if (ivSz > 0) {
desc->desc[desc->idx++] = CAAM_STORE_CTX | CAAM_CLASS1 | ofst | 16;
desc->desc[desc->idx++] = ivPhy;
}
break;
}
do {
err = caamDoJob(desc);
} while (err == CAAM_WAITING);
return err;
}
int caamAes(DESCSTRUCT* desc, CAAM_BUFFER* buf, unsigned int args[4])
{
void *iv = NULL, *key, *in, *out;
int ivSz = 0, keySz, inSz, outSz;
int idx = 0;
unsigned int keyPhy = 0, inPhy = 0, outPhy = 0, ivPhy = 0;
key = (void*)buf[idx].TheAddress;
keySz = buf[idx].Length;
keyPhy = CAAM_ADR_TO_PHYSICAL(key, keySz);
idx++;
switch (desc->type) {
case CAAM_AESECB:
break;
case CAAM_AESCTR:
case CAAM_AESCBC:
{
ivSz = buf[idx].Length;
iv = (void*)buf[idx].TheAddress;
ivPhy = CAAM_ADR_TO_PHYSICAL(iv, ivSz);
idx++;
}
break;
default:
WOLFSSL_MSG("Mode of AES not implemented");
return CAAM_ARGS_E;
}
inSz = buf[idx].Length;
in = (void*)buf[idx].TheAddress;
inPhy = CAAM_ADR_TO_PHYSICAL(in, inSz);
idx++;
outSz = buf[idx].Length;
out = (void*)buf[idx].TheAddress;
outPhy = CAAM_ADR_TO_PHYSICAL(out, outSz);
idx++;
return caamAesInternal(desc, keyPhy, keySz, ivPhy, ivSz, inPhy, inSz,
outPhy, outSz);
}
int caamAesCombined(DESCSTRUCT* desc, CAAM_BUFFER* buf, unsigned int args[4],
unsigned int phyMem)
{
int idx = 0;
unsigned int keyPhy;
int keySz, inSz, ivSz = 0, outSz;
void* pt;
keySz = buf[idx].Length;
pt = (void*)buf[idx].TheAddress;
idx++;
switch (desc->type) {
case CAAM_AESECB:
break;
case CAAM_AESCTR:
case CAAM_AESCBC:
{
ivSz = buf[idx].Length;
idx++;
}
break;
default:
WOLFSSL_MSG("Mode of AES not implemented");
return CAAM_ARGS_E;
}
inSz = buf[idx].Length;
idx++;
outSz = buf[idx].Length;
idx++;
if (phyMem != 0) {
keyPhy = phyMem;
}
else {
keyPhy = CAAM_ADR_TO_PHYSICAL(pt, keySz + inSz + ivSz + outSz);
}
return caamAesInternal(desc, keyPhy, keySz,
keyPhy + keySz + inSz,ivSz,
keyPhy + keySz, inSz,
keyPhy + keySz + inSz + ivSz, outSz);
}
int caamECDSAMake(DESCSTRUCT* desc, CAAM_BUFFER* buf, unsigned int args[4])
{
Error err;
unsigned int part = 0;
unsigned int isBlackKey = 0;
unsigned int pdECDSEL = 0;
unsigned int phys;
void *vaddr[2];
if (args != NULL) {
isBlackKey = args[0];
pdECDSEL = args[1];
}
vaddr[0] = NULL;
vaddr[1] = NULL;
desc->desc[desc->idx++] = pdECDSEL;
if (isBlackKey == CAAM_BLACK_KEY_SM) {
unsigned char* pt;
part = caamFindUnusedPartition();
if ((int)part < 0) {
WOLFSSL_MSG("error finding an unused partition for new key");
return -1;
}
err = caamCreatePartition(&part, part, CAAM_SM_CSP | CAAM_SM_SMAP_LOCK |
CAAM_SM_CSP | CAAM_SM_ALL_RW);
if (err != Success) {
WOLFSSL_MSG("error creating partition for secure ecc key");
return -1;
}
phys = (CAAM_PAGE + (part << 12));
pt = (unsigned char*)buf[0].TheAddress;
pt[0] = (phys >> 24) & 0xFF;
pt[1] = (phys >> 16) & 0xFF;
pt[2] = (phys >> 8) & 0xFF;
pt[3] = (phys) & 0xFF;
desc->desc[desc->idx++] = phys;
}
else {
vaddr[0] = CAAM_ADR_MAP(0, buf[0].Length, 0);
desc->desc[desc->idx++] = CAAM_ADR_TO_PHYSICAL(vaddr[0], buf[0].Length);
}
vaddr[1] = CAAM_ADR_MAP(0, buf[1].Length, 0);
desc->desc[desc->idx++] = CAAM_ADR_TO_PHYSICAL(vaddr[1], buf[1].Length);
desc->startIdx = desc->idx;
desc->desc[desc->idx] = CAAM_OP | CAAM_PROT_UNIDI | desc->type;
if (isBlackKey == CAAM_BLACK_KEY_SM || isBlackKey == CAAM_BLACK_KEY_CCM) {
desc->desc[desc->idx] |= CAAM_PKHA_ENC_PRI_AESCCM;
}
if (isBlackKey == CAAM_BLACK_KEY_ECB) {
desc->desc[desc->idx] |= CAAM_PKHA_ENC_PRI_AESECB;
}
desc->desc[desc->idx++] |= CAAM_PKHA_ECC;
do {
err = caamDoJob(desc);
} while (err == CAAM_WAITING);
if (isBlackKey == CAAM_BLACK_KEY_SM) {
if (err != Success)
caamFreePart(part);
else
args[2] = part;
}
else {
CAAM_ADR_UNMAP(vaddr[0], buf[0].TheAddress, buf[0].Length, 1);
}
CAAM_ADR_UNMAP(vaddr[1], buf[1].TheAddress, buf[1].Length, 1);
return err;
}
int caamECDSAVerify(DESCSTRUCT* desc, CAAM_BUFFER* buf, int sz,
unsigned int args[4])
{
unsigned int isBlackKey = 0;
unsigned int pdECDSEL = 0;
unsigned int msgSz = 0;
unsigned int vidx = 0;
unsigned int L;
int i = 0;
Error err;
void *vaddr[MAX_ECDSA_VERIFY_ADDR];
if (args != NULL) {
isBlackKey = args[0];
pdECDSEL = args[1];
msgSz = args[2];
}
if (sz > MAX_ECDSA_VERIFY_ADDR) {
return -1;
}
if (pdECDSEL == 0) {
return -1;
}
else {
L = args[3];
desc->desc[desc->idx++] = pdECDSEL;
}
if (isBlackKey != CAAM_BLACK_KEY_SM) {
vaddr[vidx] = CAAM_ADR_MAP(desc->buf[i].data, desc->buf[i].dataSz, 1);
desc->desc[desc->idx++] = CAAM_ADR_TO_PHYSICAL(vaddr[vidx],
desc->buf[i].dataSz);
vidx = vidx + 1;
}
else {
desc->desc[desc->idx++] = desc->buf[i].data;
}
i = i + 1;
vaddr[vidx] = CAAM_ADR_MAP(desc->buf[i].data, desc->buf[i].dataSz, 1);
desc->desc[desc->idx++] = CAAM_ADR_TO_PHYSICAL(vaddr[vidx],
desc->buf[i].dataSz);
vidx = vidx + 1; i = i + 1;
vaddr[vidx] = CAAM_ADR_MAP(desc->buf[i].data, desc->buf[i].dataSz, 1);
desc->desc[desc->idx++] = CAAM_ADR_TO_PHYSICAL(vaddr[vidx],
desc->buf[i].dataSz);
vidx = vidx + 1; i = i + 1;
vaddr[vidx] = CAAM_ADR_MAP(desc->buf[i].data, desc->buf[i].dataSz, 1);
desc->desc[desc->idx++] = CAAM_ADR_TO_PHYSICAL(vaddr[vidx],
desc->buf[i].dataSz);
vidx = vidx + 1; i = i + 1;
vaddr[vidx] = CAAM_ADR_MAP(0, 2*L, 0);
desc->desc[desc->idx++] = CAAM_ADR_TO_PHYSICAL(vaddr[vidx], 2*L);
if (msgSz > 0) {
desc->desc[desc->idx++] = msgSz;
}
desc->startIdx = desc->idx;
desc->desc[desc->idx] = CAAM_OP | CAAM_PROT_UNIDI | desc->type;
if (msgSz > 0) {
desc->desc[desc->idx] |= CAAM_ECDSA_MESREP_HASHED;
}
desc->desc[desc->idx++] |= CAAM_PKHA_ECC;
do {
err = caamDoJob(desc);
} while (err == CAAM_WAITING);
vidx = 0; i = 0;
if (!isBlackKey) {
CAAM_ADR_UNMAP(vaddr[vidx++], desc->buf[i].data, desc->buf[i].dataSz, 0);
}
i = i + 1;
CAAM_ADR_UNMAP(vaddr[vidx++], desc->buf[i].data, desc->buf[i].dataSz, 0);
i = i + 1;
CAAM_ADR_UNMAP(vaddr[vidx++], desc->buf[i].data, desc->buf[i].dataSz, 0);
i = i + 1;
CAAM_ADR_UNMAP(vaddr[vidx++], desc->buf[i].data, desc->buf[i].dataSz, 0);
i = i + 1;
CAAM_ADR_UNMAP(vaddr[vidx++], 0, 2*L, 0);
return err;
}
int caamECDSASign(DESCSTRUCT* desc, int sz, unsigned int args[4])
{
Error err;
unsigned int isBlackKey = 0;
unsigned int pdECDSEL = 0;
unsigned int msgSz = 0;
unsigned int vidx = 0;
int i = 0;
void *vaddr[MAX_ECDSA_SIGN_ADDR];
if ((args == NULL) || (sz > MAX_ECDSA_SIGN_ADDR)) {
return -1;
}
isBlackKey = args[0];
pdECDSEL = args[1];
msgSz = args[2];
if (pdECDSEL == 0) {
return -1;
}
desc->desc[desc->idx++] = pdECDSEL;
if (isBlackKey != CAAM_BLACK_KEY_SM) {
vaddr[vidx] = CAAM_ADR_MAP(desc->buf[i].data, desc->buf[i].dataSz, 1);
desc->desc[desc->idx++] = CAAM_ADR_TO_PHYSICAL(vaddr[vidx],
desc->buf[i].dataSz);
#if 0 #endif
vidx++;
}
else {
desc->desc[desc->idx++] = desc->buf[i].data;
}
i++;
for (; i < sz; i = i + 1) {
vaddr[vidx] = CAAM_ADR_MAP(desc->buf[i].data, desc->buf[i].dataSz, 1);
#if 0 #endif
desc->desc[desc->idx++] = CAAM_ADR_TO_PHYSICAL(vaddr[vidx],
desc->buf[i].dataSz);
vidx++;
}
desc->desc[desc->idx++] = msgSz;
desc->startIdx = desc->idx;
desc->desc[desc->idx] = CAAM_OP | CAAM_PROT_UNIDI | desc->type;
if (isBlackKey == CAAM_BLACK_KEY_SM || isBlackKey == CAAM_BLACK_KEY_CCM) {
desc->desc[desc->idx] |= CAAM_PKHA_ENC_PRI_AESCCM;
}
if (isBlackKey == CAAM_BLACK_KEY_ECB) {
desc->desc[desc->idx] |= CAAM_PKHA_ENC_PRI_AESECB;
}
desc->desc[desc->idx++] |= CAAM_ECDSA_MESREP_HASHED | CAAM_PKHA_ECC;
do {
err = caamDoJob(desc);
} while (err == CAAM_WAITING);
vidx = 0; i = 0;
if (isBlackKey != CAAM_BLACK_KEY_SM) {
CAAM_ADR_UNMAP(vaddr[vidx++], desc->buf[i].data, desc->buf[i].dataSz, 0);
}
i++;
CAAM_ADR_UNMAP(vaddr[vidx++], desc->buf[i].data, desc->buf[i].dataSz, 0); i++;
CAAM_ADR_UNMAP(vaddr[vidx++], desc->buf[i].data, desc->buf[i].dataSz, 1); i++;
CAAM_ADR_UNMAP(vaddr[vidx++], desc->buf[i].data, desc->buf[i].dataSz, 1); i++;
return err;
}
int caamECDSA_ECDH(DESCSTRUCT* desc, int sz, unsigned int args[4])
{
Error err;
unsigned int isBlackKey = 0;
unsigned int peerBlackKey = 0;
unsigned int pdECDSEL = 0;
unsigned int vidx = 0;
int i = 0;
void* vaddr[sz];
if (args != NULL) {
isBlackKey = args[0];
peerBlackKey = args[1];
pdECDSEL = args[2];
}
if (pdECDSEL == 0) {
return -1;
}
else {
desc->desc[desc->idx++] = pdECDSEL;
}
if (peerBlackKey != CAAM_BLACK_KEY_SM) {
vaddr[vidx] = CAAM_ADR_MAP(desc->buf[i].data, desc->buf[i].dataSz, 1);
desc->desc[desc->idx++] = CAAM_ADR_TO_PHYSICAL(vaddr[vidx],
desc->buf[i].dataSz);
DEBUG_PRINT_ARRAY((void*)desc->buf[i].data, desc->buf[i].dataSz,
"ECDH Public Key");
vidx++;
}
else {
desc->desc[desc->idx++] = desc->buf[i].data;
}
i++;
if (isBlackKey != CAAM_BLACK_KEY_SM) {
if (isBlackKey == CAAM_BLACK_KEY_CCM) {
vaddr[vidx] = CAAM_ADR_MAP(desc->buf[i].data, desc->buf[i].dataSz +
BLACK_KEY_MAC_SZ, 1);
desc->desc[desc->idx++] = CAAM_ADR_TO_PHYSICAL(vaddr[vidx],
desc->buf[i].dataSz + BLACK_KEY_MAC_SZ);
DEBUG_PRINT_ARRAY((void*)desc->buf[i].data, desc->buf[i].dataSz +
BLACK_KEY_MAC_SZ, "ECDH Private Key w/CCM ");
}
else {
vaddr[vidx] = CAAM_ADR_MAP(desc->buf[i].data, desc->buf[i].dataSz, 1);
desc->desc[desc->idx++] = CAAM_ADR_TO_PHYSICAL(vaddr[vidx],
desc->buf[i].dataSz);
DEBUG_PRINT_ARRAY((void*)desc->buf[i].data, desc->buf[i].dataSz,
"ECDH Private Key");
}
vidx++;
}
else {
desc->desc[desc->idx++] = desc->buf[i].data;
}
i++;
vaddr[vidx] = CAAM_ADR_MAP(desc->buf[i].data, desc->buf[i].dataSz, 1);
desc->desc[desc->idx++] = CAAM_ADR_TO_PHYSICAL(vaddr[vidx],
desc->buf[i].dataSz);
i++; vidx++;
desc->startIdx = desc->idx;
desc->desc[desc->idx] = CAAM_OP | CAAM_PROT_UNIDI | desc->type;
if (isBlackKey == CAAM_BLACK_KEY_SM || isBlackKey == CAAM_BLACK_KEY_CCM) {
desc->desc[desc->idx] |= CAAM_PKHA_ENC_PRI_AESCCM;
}
if (isBlackKey == CAAM_BLACK_KEY_ECB) {
desc->desc[desc->idx] |= CAAM_PKHA_ENC_PRI_AESECB;
}
desc->desc[desc->idx++] |= CAAM_PKHA_ECC;
do {
err = caamDoJob(desc);
} while (err == CAAM_WAITING);
vidx = 0; i = 0;
if (pdECDSEL == 0) {
CAAM_ADR_UNMAP(vaddr[vidx], desc->buf[i].data, desc->buf[i].dataSz, 0);
vidx++; i++;
}
if (peerBlackKey != 1) {
CAAM_ADR_UNMAP(vaddr[vidx], desc->buf[i].data, desc->buf[i].dataSz, 0);
vidx++;
}
i++;
if (isBlackKey != CAAM_BLACK_KEY_SM) {
CAAM_ADR_UNMAP(vaddr[vidx], desc->buf[i].data, desc->buf[i].dataSz, 0);
vidx++;
}
i++;
CAAM_ADR_UNMAP(vaddr[vidx], desc->buf[i].data, desc->buf[i].dataSz, 1);
vidx++; i++;
if (pdECDSEL == 0) {
CAAM_ADR_UNMAP(vaddr[vidx], desc->buf[i].data, desc->buf[i].dataSz, 0);
vidx++; i++;
}
return err;
}
static int caamTRNG(unsigned char *out, int outSz)
{
int sz = 0;
CAAM_ADDRESS reg;
unsigned char* local;
int ofst = sizeof(unsigned int);
if ((CAAM_READ(caam.baseAddr + CAAM_RTMCTL) & CAAM_ENTVAL) != CAAM_ENTVAL) {
return CAAM_WAITING;
}
if ((CAAM_READ(caam.baseAddr + CAAM_RTSTATUS) & 0x0000FFFF) > 0) {
WOLFSSL_MSG("RNG in a bad state");
return Failure;
}
reg = caam.baseAddr + CAAM_RTENT0;
sz = outSz;
local = out;
while (sz > 3 && reg <= caam.baseAddr + CAAM_RTENT_MAX) {
unsigned int data = CAAM_READ(reg);
*((unsigned int*)local) = data;
reg += ofst;
local += ofst;
sz -= ofst;
}
if (reg > CAAM_RTENT_MAX && sz > 0) {
return -1;
}
if (sz > 0) {
unsigned int tmp = CAAM_READ(reg);
memcpy(local, (unsigned char*)&tmp, sz);
}
if (reg != CAAM_RTENT_MAX) {
CAAM_READ(caam.baseAddr + CAAM_RTENT_MAX);
}
return Success;
}
static int caamRNG(unsigned char *out, int outSz)
{
DESCSTRUCT desc;
int ret;
caamDescInit(&desc, 0, NULL, NULL, 0);
desc.desc[desc.idx++] = CAAM_OP | CAAM_CLASS1 | CAAM_RNG;
desc.desc[desc.idx++] = (CAAM_FIFO_S | FIFOS_TYPE_RNG) + outSz;
desc.desc[desc.idx++] = CAAM_ADR_TO_PHYSICAL(out, outSz);
do {
ret = caamDoJob(&desc);
} while (ret == CAAM_WAITING);
return ret;
}
int caamEntropy(unsigned char *out, int outSz)
{
if (caam.vrs < 9) {
return caamTRNG(out, outSz);
}
else {
return caamRNG(out, outSz);
}
}
int caamKeyCover(DESCSTRUCT* desc, int sz, unsigned int args[4])
{
Error err;
unsigned int vidx = 0;
int i = 0;
void* vaddr[2];
(void)args;
if (sz > 2) {
return -1;
}
desc->desc[desc->idx++] = (CAAM_KEY | CAAM_CLASS1) +
desc->buf[i].dataSz;
vaddr[vidx] = CAAM_ADR_MAP(desc->buf[i].data, desc->buf[i].dataSz, 1);
desc->desc[desc->idx++] = CAAM_ADR_TO_PHYSICAL(vaddr[vidx],
desc->buf[i].dataSz);
vidx++;
i++;
desc->desc[desc->idx++] = (CAAM_FIFO_S | CAAM_CLASS1 | args[0] |
desc->state) + desc->buf[i].dataSz;
vaddr[vidx] = CAAM_ADR_MAP(desc->buf[i].data, desc->buf[i].dataSz +
BLACK_KEY_MAC_SZ, 0);
desc->desc[desc->idx++] = CAAM_ADR_TO_PHYSICAL(vaddr[vidx],
desc->buf[i].dataSz + BLACK_KEY_MAC_SZ);
#if 0#endif
do {
err = caamDoJob(desc);
} while (err == CAAM_WAITING);
CAAM_ADR_UNMAP(vaddr[0], desc->buf[0].data, desc->buf[0].dataSz, 0);
CAAM_ADR_UNMAP(vaddr[1], desc->buf[1].data, desc->buf[1].dataSz +
BLACK_KEY_MAC_SZ, 1);
return err;
}
void caamDescInit(DESCSTRUCT* desc, int type, unsigned int args[4],
CAAM_BUFFER* buf, int sz)
{
int i;
desc->type = type;
desc->idx = 0;
desc->output = 0;
desc->ctxOut = 0;
desc->outputIdx = 0;
desc->alignIdx = 0;
desc->lastFifo = 0;
if (args == NULL) {
desc->state = 0;
desc->ctxSz = 0;
desc->inputSz = 0;
}
else {
desc->state = args[0] & 0xFFFF;
desc->ctxSz = args[1] & 0xFFFF;
desc->inputSz = args[2];
}
desc->aadSz = 0;
desc->DescriptorCount = sz;
desc->startIdx = 0;
desc->desc[desc->idx++] = CAAM_HEAD;
for (i = 0; i < sz; i = i + 1) {
desc->buf[i].data = buf[i].TheAddress;
desc->buf[i].dataSz = buf[i].Length;
}
}
static int SetupJobRing(struct JobRing* r)
{
CAAM_SET_JOBRING_ADDR(&r->BaseAddr, &r->JobIn, &r->VirtualIn);
r->Desc = r->JobIn + (CAAM_JOBRING_SIZE * sizeof(unsigned int));
r->JobOut = r->Desc + (CAAM_DESC_MAX * CAAM_JOBRING_SIZE);
CAAM_INIT_MUTEX(&caam.ring.jr_lock);
r->VirtualDesc = r->VirtualIn + (CAAM_JOBRING_SIZE * sizeof(unsigned int));
r->VirtualOut = r->VirtualDesc + (CAAM_DESC_MAX * CAAM_JOBRING_SIZE);
memset(r->VirtualIn, 0, CAAM_JOBRING_SIZE * sizeof(unsigned int));
memset(r->VirtualDesc, 0, CAAM_DESC_MAX * CAAM_JOBRING_SIZE);
memset(r->VirtualOut, 0, 2 * CAAM_JOBRING_SIZE * sizeof(unsigned int));
#if defined(WOLFSSL_CAAM_DEBUG) || defined(WOLFSSL_CAAM_PRINT)
printf("Setting JOB IN address 0x%08X, size %d\n",
(unsigned int)caam.ring.JobIn, CAAM_JOBRING_SIZE);
printf("Setting JOB OUT address 0x%08X, size %d\n",
(unsigned int)caam.ring.JobOut, CAAM_JOBRING_SIZE);
printf("Setting DESC 0x%08X\n", (unsigned int)caam.ring.Desc);
#endif
CAAM_WRITE(r->BaseAddr + CAAM_IRBAR0, r->JobIn);
CAAM_WRITE(r->BaseAddr + CAAM_ORBAR, r->JobOut);
CAAM_WRITE(r->BaseAddr + CAAM_IRSR0, CAAM_JOBRING_SIZE);
CAAM_WRITE(r->BaseAddr + CAAM_ORSR0, CAAM_JOBRING_SIZE);
if (((CAAM_READ(r->BaseAddr + CAAM_STATUS) & 0x00000001) != 0) &&
(CAAM_READ(r->BaseAddr + JRINTR_JR) != 0)) {
unsigned int reg;
#if defined(WOLFSSL_CAAM_DEBUG) || defined(WOLFSSL_CAAM_PRINT)
printf("Job ring is busy, trying to flush it\n");
#endif
CAAM_WRITE(r->BaseAddr + JRCR_JR, 0x2);
CAAM_WRITE(r->BaseAddr + JRCR_JR, 0x1);
do {
reg = CAAM_READ(r->BaseAddr + JRINTR_JR);
} while (!(reg & 0x8) && (reg != 0));
if (reg != 0) {
CAAM_WRITE(r->BaseAddr + JRCR_JR, 0x1);
}
}
return 0;
}
int InitCAAM(void)
{
Error ret;
#if defined(WOLFSSL_CAAM_PRINT)
printf("Using CAAM_BASE 0x%04X\n", CAAM_BASE);
#endif
ret = CAAM_SET_BASEADDR(&caam.baseAddr);
if (ret != 0) {
return ret;
}
#if defined(WOLFSSL_CAAM_PRINT)
printf("Using base address : 0x%04X\n", caam.baseAddr);
#endif
ret = SetupJobRing(&caam.ring);
if (ret != 0) {
WOLFSSL_MSG("Error initializing job ring");
INTERRUPT_Panic();
return ret;
}
#if defined(WOLFSSL_CAAM_PRINT)
printf("Using base ring address : 0x%04X\n", caam.ring.BaseAddr);
#endif
caam.vrs = CAAM_READ(caam.ring.BaseAddr + CAAM_CHA_CCBVID) >> 24;
#if defined(WOLFSSL_CAAM_DEBUG) || defined(WOLFSSL_CAAM_PRINT)
printf("CAAM version = %04X\n",
CAAM_READ(caam.ring.BaseAddr + CAAM_VERSION_MS) & 0xFFFF);
printf("CAAM era = %d\n", caam.vrs);
printf("RNG revision number = %08X\n",
CAAM_READ(caam.ring.BaseAddr + CAAM_CRNR_LS));
printSecureMemoryInfo();
{
unsigned int chaVerLS =
CAAM_READ(caam.ring.BaseAddr + CAAM_CHA_VERSION_LS);
printf("\nCHA support\n");
printf("CHA Version LS = %04X\n", chaVerLS);
if (!(chaVerLS & CAAM_AES_HIGH_PERFORMANCE)) {
printf("High Performance AES module not supported, NO AES-GCM/XTS\n");
}
if (chaVerLS & CAAM_AES_LOW_POWER) {
printf("Low Power AES module found\n");
}
printf("\n");
}
#endif
if (caam.vrs < 9) {
CAAM_WRITE(caam.baseAddr + CAAM_RSTA,
CAAM_READ(caam.baseAddr + CAAM_RSTA) | 0x40000000);
if (caamInitRng(&caam) != 0) {
WOLFSSL_MSG("Error initializing RNG");
INTERRUPT_Panic();
return -1;
}
}
WOLFSSL_MSG("Successfully initialized CAAM driver");
#if defined(WOLFSSL_CAAM_DEBUG) || defined(WOLFSSL_CAAM_PRINT)
fflush(stdout);
#endif
return 0;
}
int CleanupCAAM()
{
caamFreeAllPart();
CAAM_UNSET_JOBRING_ADDR(caam.ring.BaseAddr, caam.ring.JobIn,
caam.ring.VirtualIn);
CAAM_FREE_MUTEX(&caam.ring.jr_lock);
CAAM_UNSET_BASEADDR(caam.baseAddr);
return 0;
}
#endif