/* caam_driver.h
 *
 * Copyright (C) 2006-2022 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
 */

#ifndef CAAM_DRIVER_H
#define CAAM_DRIVER_H

#if (defined(__QNX__) || defined(__QNXNTO__))
    int InitCAAM(void);
    #include "caam_qnx.h"
#endif
#if (defined(__INTEGRITY) || defined(INTEGRITY))
    #define CAAM_BASE 0xf2100000
    #define CAAM_PAGE 0xf0100000
#endif

#ifdef WOLFSSL_CAAM_PRINT
    #include <stdio.h>
    #define WOLFSSL_MSG(in) printf("%s\n", (in))
    void DEBUG_PRINT_ARRAY(void* a, int aSz, char* str);
#else
    #define WOLFSSL_MSG(in)
    #define DEBUG_PRINT_ARRAY(a,aSz,str)
#endif

#define CAAM_PAGE_MAX 6

/* max size of 64 word32's */
#define CAAM_DESC_MAX 256

#ifndef CAAM_JOBRING_SIZE
#define CAAM_JOBRING_SIZE 1
#endif

/* black key stored in secure memory location */
#define CAAM_BLACK_KEY_SM 1

/* black key encrypted with AES-CCM (has MAC) */
#define CAAM_BLACK_KEY_CCM 2

/* black key encrypted with AES-ECB (no MAC) */
#define CAAM_BLACK_KEY_ECB 3

/******************************************************************************
  Basic Descriptors
  ****************************************************************************/

/* descriptor commands */
#define CAAM_KEY      0x00000000
#define CAAM_LOAD     0x10000000
#define CAAM_LOAD_CTX 0x10200000
#define CAAM_IMM      0x00800000
#define CAAM_FIFO_L   0x20000000
#define CAAM_FIFO_S   0x60000000
#define CAAM_FIFO_S_SKEY 0x60260000
#define CAAM_STORE       0x50000000
#define CAAM_STORE_CTX   0x50200000
#define CAAM_MOVE        0x78000000
#define CAAM_OP          0x80000000
#define CAAM_SIG         0x90000000
#define CAAM_JUMP        0xA0000000
#define CAAM_SEQI        0xF0000000/* SEQ in  */
#define CAAM_SEQO        0xF8000000/* SEQ out */
#define CAAM_HEAD        0xB0800000
#define CAAM_NWB         0x00200000

    /* PROTOCOL OPERATION command */
#define CAAM_PROT_UNIDI 0
#define CAAM_BLOB_ENCAP 0x07000000
#define CAAM_BLOB_DECAP 0x06000000
#define CAAM_PKHA_OP    0x01000000

#define CAAM_OPID_BLOB  0x000D0000

/* algorithms modes and types */
#define CAAM_CLASS1 0x02000000/* i.e. AES, PKHA */
#define CAAM_CLASS2 0x04000000/* i.e. hash algos */

#define CAAM_ENC    0x00000001
#define CAAM_DEC    0x00000000
#define CAAM_ALG_INIT   0x00000004
#define CAAM_ALG_INITF  0x0000000C
#define CAAM_ALG_UPDATE 0x00000000
#define CAAM_ALG_FINAL  0x00000008
#define CAAM_ALG_IVC    0x00000002

    /* AES 10h */
#define CAAM_AESCTR 0x00100000
#define CAAM_AESCBC 0x00100100
#define CAAM_AESECB 0x00100200
#define CAAM_AESCFB 0x00100300
#define CAAM_AESOFB 0x00100400
#define CAAM_CMAC   0x00100600
#define CAAM_AESCCM 0x00100800
#define CAAM_AESGCM 0x00100900

    /* HASH 40h */
#define CAAM_MD5    0x00400000
#define CAAM_SHA    0x00410000
#define CAAM_SHA224 0x00420000
#define CAAM_SHA256 0x00430000
#define CAAM_SHA384 0x00440000
#define CAAM_SHA512 0x00450000

    /* HMAC 40h + 10 AAI */
#define CAAM_HMAC_MD5    0x00400010
#define CAAM_HMAC_SHA    0x00410010
#define CAAM_HMAC_SHA224 0x00420010
#define CAAM_HMAC_SHA256 0x00430010
#define CAAM_HMAC_SHA384 0x00440010
#define CAAM_HMAC_SHA512 0x00450010

/* ECDSA ECDSEL (pre defined flags for ECDSA parameters i.e. order) */
#define CAAM_ECDSEL_SHIFT 7
#define CAAM_ECDSA_PD 0x00400000
#define CAAM_ECDSA_KEYGEN_PD 0x02000000
#define CAAM_ECDSA_P192 (0x00 << CAAM_ECDSEL_SHIFT)
#define CAAM_ECDSA_P224 (0x01 << CAAM_ECDSEL_SHIFT)
#define CAAM_ECDSA_P256 (0x02 << CAAM_ECDSEL_SHIFT)
#define CAAM_ECDSA_P384 (0x03 << CAAM_ECDSEL_SHIFT)
#define CAAM_ECDSA_P521 (0x04 << CAAM_ECDSEL_SHIFT)

#define CAAM_ECDSA_BRAINPOOL_P256 (0x0B << CAAM_ECDSEL_SHIFT)

    /* PKHA Operation ID ECDSA */
#define CAAM_ECDSA_KEYPAIR 0x00140000
#define CAAM_ECDSA_SIGN    0x00150000
#define CAAM_ECDSA_VERIFY  0x00160000
#define CAAM_ECDSA_ECDH    0x00170000

#define CAAM_ECDSA_MESREP_HASHED (0x10 << 7)

    /* key encryption bit */
#define CAAM_PKHA_ECC 0x00000002
#define CAAM_PKHA_ENC_PRI_AESECB 0x00000004
#define CAAM_PKHA_ENC_PRI_AESCCM (0x00000010 | CAAM_PKHA_ENC_PRI_AESECB)
#define CAAM_PKHA_NO_TIMING_RESISTANCE 0x40000000
#define CAAM_LOAD_BLACK_KEY 0x500000

    /* PKHA RSA */
#define CAAM_OPID_RSA_ENCRYPT 0x00180000
#define CAAM_OPID_RSA_DECRYPT 0x00190000


#define CAAM_MD5_CTXSZ (16 + 8)
#define CAAM_SHA_CTXSZ (20 + 8)
#define CAAM_SHA224_CTXSZ (32 + 8)
#define CAAM_SHA256_CTXSZ (32 + 8)
#define CAAM_SHA384_CTXSZ (64 + 8)
#define CAAM_SHA512_CTXSZ (64 + 8)

    /* RNG 50h */
#define CAAM_RNG 0x00500000

    /* Used to get raw entropy from TRNG */
#define CAAM_ENTROPY 0x00500001

#define FIFOL_TYPE_MSG 0x00100000
#define FIFOL_TYPE_IV  0x00200000
#define FIFOL_TYPE_IVC 0x00380000
#define FIFOL_TYPE_AAD 0x00300000
#define FIFOL_TYPE_FC1 0x00010000
#define FIFOL_TYPE_LC1 0x00020000
#define FIFOL_TYPE_LC2 0x00040000

#define FIFOS_TYPE_MSG 0x00300000
#define FIFOS_TYPE_RNG 0x00340000
#define FIFOS_EXT      0x00400000

/* continue bit set if more output is expected */
#define CAAM_FIFOS_CONT 0x00800000

#define CAAM_PAGE_SZ 4096

/* RNG Registers */
#define CAAM_RTMCTL      0X0600
#define CAAM_RTSDCTL     0X0610
#define CAAM_RTFRQMIN    0X0618
#define CAAM_RTFRQMAX    0X061C
#define CAAM_RDSTA       0X06C0
#define CAAM_RTSTATUS    0x063C
#define CAAM_RDINT0      0x06D0

/* each of the following 11 RTENT registers are an offset of 4 from RTENT0 */
#define CAAM_RTENT0      0x0640
#define CAAM_RTENT11     0x066C /* Max RTENT register */
#define CAAM_RTENT_MAX   0x067C

/* RNG Masks/Values */
#ifndef CAAM_ENT_DLY
    /* Less than half the default value to try and increase entropy collection.
     * Value is system clock cycles. */
    #define CAAM_ENT_DLY   1200
#endif
#ifndef CAAM_ENT_DLY_INCREMENT
    #define CAAM_ENT_DLY_INCREMENT 500
#endif
#ifndef CAAM_ENT_SAMPLE
    /* default sample value from reference manual */
    #define CAAM_ENT_SAMPLE 0x09C4
#endif
#ifndef CAAM_ENT_DLY_MAX
    #define CAAM_ENT_DLY_MAX 12000
#endif
#ifndef CAAM_ENT_MINSHIFT
    /* default to the minimum entropy delay of 1/4 */
    #define CAAM_ENT_MINSHIFT 2
#endif
#ifndef CAAM_ENT_MAXSHIFT
    /* default to the maximum entropy delay of 16 times */
    #define CAAM_ENT_MAXSHIFT 4
#endif

#define CAAM_PRGM      0x00010000 /* Set RTMCTL to program state */
#define CAAM_TRNG      0x00000020 /* Set TRNG access */
#define CAAM_RTMCTL_RESET 0x40    /* TRNG reset to defaults */
#define CAAM_CTLERR    0x00001000
#define CAAM_ENTVAL    0x00000400 /* checking RTMCTL for entropy ready */

/* Input Job Ring Registers */
#define CAAM_IRBAR0      0x0004
#define CAAM_IRSR0       0x000C
#define CAAM_IRJAR0      0x001C

#define CAAM_IRBAR2      0x3004
#define CAAM_IRSR2       0x300C
#define CAAM_IRJAR2      0x301C
#define CAAM_IRSAR_JR    0x0014

/* Output Job Ring Registers */
#define CAAM_ORBAR       0x0024
#define CAAM_ORSR0       0x002C
#define CAAM_ORJAR       0x003C
#define CAAM_ORJRR       0x0034

#define JRCFGR_JR        0x0054
#define JRCR_JR          0x006C

/* Status Registers */
#define CAAM_STATUS      0x0FD4
#define CAAM_CHA_VERSION_MS  0x0FE8
#define CAAM_CHA_VERSION_LS  0x0FEC
#define CAMM_CHA_SUPPORT_MS  0x0FF0
#define CAMM_CHA_SUPPORT_LS  0x0FF4
#define CAAM_VERSION_MS  0x0FF8
#define CAAM_VERSION_LS  0x0FFC
#define CAAM_CHA_CCBVID  0x0FE4

#define CAAM_SM_CMD  0x0BE4
#define CAAM_SM_SMPO 0x0FBC
#define CAAM_SMAPR   0x0A04
#define CAAM_SM_SMVID_MS 0x0FD8
#define CAAM_SM_SMVID_LS 0x0FDC
#define CAAM_SM_STATUS 0x0BEC
#define CAAM_SM_CSP   0x00008000
#define CAAM_SM_SMAP_LOCK 0x00002000
#define CAAM_SM_SMAG_LOCK 0x00001000
#define CAAM_SM_ALL_RW 0x000000FF

#define CAAM_C1DSR_LS    0x8014
#define CAAM_C1MR        0x8004
#define CAAM_RSTA        0x0004
#define CAAM_DRR         0x0124
#define CAAM_CRNR_LS     0x0FA4


/* output FIFO  is 16 entries deep and each entry has a two 4 byte registers */
#define CAAM_FIFOO_MS    0x87F0
#define CAAM_FIFOO_LS    0x87F4

/* input FIFO is 16 entries deep with each entry having two 4 byte registers
   All data written to it from IP bus should be in big endian format */
#define CAAM_FIFOI_LS    0x87E0

/* offset of 4 with range 0 .. 13 */
#define CAAM_CTX1        0x8100
#define CAAM_CTRIV       CAAM_CTX1 + 8 /* AES-CTR iv is in 2 and 3 */
#define CAAM_CBCIV       CAAM_CTX1     /* AES-CBC iv is in 1 and 2 */


    /* debugging registers */
#define CAAM_DECORR 0x009C /* used to set DECO into debug mode */
#define CAAM_DODJR  0x8E00 /* for hung operations */
#define CAAM_DOJQCR_MS 0x8800
#define CAAM_DOOPSTA_MS 0x8810 /* DECO operation status register */
#define CAAM_DODAR  0x8808 /* address of current descriptor */
#define CAAM_DODESB 0x8A00 /* 64 registers that hold the current descriptor buffer */

#define JRINTR_JR 0x004C

#define CAAM_SINGLE_STEP_MODE 0x40000000
#define CAAM_STEP 0x80000000

/* Port layer for CAAM driver, functions defined in caam_<env>.c */
unsigned int CAAM_READ(CAAM_ADDRESS reg);
void CAAM_WRITE(CAAM_ADDRESS reg, unsigned int in);
int CAAM_SET_BASEADDR(CAAM_ADDRESS* baseAddr);
void CAAM_UNSET_BASEADDR(CAAM_ADDRESS baseAddr);
void CAAM_UNSET_JOBRING_ADDR(CAAM_ADDRESS base, CAAM_ADDRESS ringInPhy,
    void* ringInVir);
int CAAM_SET_JOBRING_ADDR(CAAM_ADDRESS* base, CAAM_ADDRESS* ringInPhy,
    void** ringInVir);
CAAM_ADDRESS CAAM_ADR_TO_PHYSICAL(void* in, int inSz);
void* CAAM_ADR_MAP(CAAM_ADDRESS in, int inSz, unsigned char copy);
void CAAM_ADR_UNMAP(void* vaddr, CAAM_ADDRESS out, int outSz,
        unsigned char copy);
int CAAM_ADR_SYNC(void* vaddr, int sz);
CAAM_ADDRESS CAAM_ADR_TO_VIRTUAL(CAAM_ADDRESS in, int length);

#ifndef WOLFSSL_CAAM_BUFFER
#define WOLFSSL_CAAM_BUFFER
typedef struct CAAM_BUFFER {
    int BufferType;
    CAAM_ADDRESS TheAddress;
    int Length;
} CAAM_BUFFER;
#endif
unsigned int caamReadRegister(unsigned int reg);
void caamWriteRegister(unsigned int reg, unsigned int in);
int SynchronousSendRequest(int type, unsigned int args[4], CAAM_BUFFER *buf, int sz);
int CleanupCAAM(void);


/* Driver API that can be called by caam_<env>.c port layers */
typedef struct DESCSTRUCT DESCSTRUCT;

int caamKeyCover(DESCSTRUCT *desc, int sz, unsigned int args[4]);
int caamEntropy(unsigned char *out, int outSz);
int caamECDSA_ECDH(DESCSTRUCT *desc, int sz, unsigned int args[4]);
int caamECDSASign(DESCSTRUCT *desc, int sz, unsigned int args[4]);
int caamECDSAVerify(DESCSTRUCT *desc, CAAM_BUFFER *buf, int sz,
        unsigned int args[4]);
int caamECDSAMake(DESCSTRUCT *desc, CAAM_BUFFER *buf, unsigned int args[4]);


int caamAes(DESCSTRUCT* desc, CAAM_BUFFER* buf, unsigned int args[4]);
int caamAead(DESCSTRUCT* desc, CAAM_BUFFER* buf, unsigned int args[4]);
int caamAesCmac(DESCSTRUCT *desc, int sz, unsigned int args[4]);
int caamBlob(DESCSTRUCT *desc);

CAAM_ADDRESS caamGetPartition(unsigned int part, int partSz, unsigned int flag);
int caamFreePart(unsigned int part);
int caamFindUnusedPartition(void);



void caamDescInit(DESCSTRUCT* desc, int type, unsigned int args[4],
        CAAM_BUFFER* buf, int sz);


/* CAAM descriptor */
#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 CAAM_BASE
#define MAX_READ_REG (CAAM_BASE + 0x00010000)

struct buffer {
    CAAM_ADDRESS data;
    CAAM_ADDRESS dataSz;
};

struct DESCSTRUCT {
#if defined(__INTEGRITY) || defined(INTEGRITY)
    struct IORequestStruct TheIORequest;
#endif
    struct CAAM_DEVICE*    caam;
    struct buffer          buf[MAX_BUF]; /* buffers holding data input address */
    unsigned int           desc[MAX_DESC_SZ]; /* max size of 64 word32 */
    unsigned int           aadSzBuf[4];       /* Formatted AAD size for CCM */
    unsigned int           alignBuf[ALIGN_BUF]; /* 64 byte buffer for non page
                                                   align */
    unsigned int           iv[MAX_CTX]; /* AES IV and also hash state */
    unsigned int           ctxBuf[MAX_CTX]; /* key */
    CAAM_ADDRESS           output; /* address to output buffer */
    CAAM_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                  startIdx;  /* for telling header where to start */
    Value                  lastFifo;
    Value                  type;
    Value                  state;
    Value                  DescriptorCount;
    Boolean                running; /* True if building/running descriptor is
                                       in process */
};

/* wolfSSL specific flags */
#define CAAM_FIND_PART 0xFFFFFFFF
#define CAAM_GET_PART 0xFFFFFFFE
#define CAAM_FREE_PART 0xFFFFFFFD
#define CAAM_READ_PART 0xFFFFFFFC
#define CAAM_WRITE_PART 0xFFFFFFFB


#define MAX_ECDSA_VERIFY_ADDR 8
#define MAX_ECDSA_SIGN_ADDR 8
#define BLACK_KEY_MAC_SZ 16
#define BLACK_BLOB_KEYMOD_SZ 16
#define RED_BLOB_KEYMOD_SZ 8
#endif /* CAAM_DRIVER_H */
