Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:22:58

0001 /*
0002  * Copyright 2017-2019 NXP
0003  * All rights reserved.
0004  *
0005  *
0006  * SPDX-License-Identifier: BSD-3-Clause
0007  */
0008 
0009 #include "fsl_dcp.h"
0010 #if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
0011 #include "fsl_cache.h"
0012 #endif
0013 
0014 /*******************************************************************************
0015  * Definitions
0016  ******************************************************************************/
0017 
0018 /* Component ID definition, used by tools. */
0019 #ifndef FSL_COMPONENT_ID
0020 #define FSL_COMPONENT_ID "platform.drivers.dcp"
0021 #endif
0022 
0023 /*! Compile time sizeof() check */
0024 #define BUILD_ASSURE(condition, msg) extern int msg[1 - 2 * (!(condition))] __attribute__((unused))
0025 
0026 #define dcp_memcpy memcpy
0027 
0028 /*! Internal states of the HASH creation process */
0029 typedef enum _dcp_hash_algo_state
0030 {
0031     kDCP_StateHashInit = 1u, /*!< Init state. */
0032     kDCP_StateHashUpdate,    /*!< Update state. */
0033 } dcp_hash_algo_state_t;
0034 
0035 /*! multiple of 64-byte block represented as byte array of 32-bit words */
0036 typedef union _dcp_hash_block
0037 {
0038     uint32_t w[DCP_HASH_BLOCK_SIZE / 4]; /*!< array of 32-bit words */
0039     uint8_t b[DCP_HASH_BLOCK_SIZE];      /*!< byte array */
0040 } dcp_hash_block_t;
0041 
0042 /*! internal dcp_hash context structure */
0043 typedef struct _dcp_hash_ctx_internal
0044 {
0045     dcp_hash_block_t blk;        /*!< memory buffer. only full blocks are written to DCP during hash updates */
0046     size_t blksz;                /*!< number of valid bytes in memory buffer */
0047     dcp_hash_algo_t algo;        /*!< selected algorithm from the set of supported algorithms */
0048     dcp_hash_algo_state_t state; /*!< finite machine state of the hash software process */
0049     uint32_t fullMessageSize;    /*!< track message size */
0050     uint32_t ctrl0;              /*!< HASH_INIT and HASH_TERM flags */
0051     uint32_t runningHash[9];     /*!< running hash. up to SHA-256 plus size, that is 36 bytes. */
0052     dcp_handle_t *handle;
0053 } dcp_hash_ctx_internal_t;
0054 
0055 /*!< SHA-1/SHA-2 digest length in bytes  */
0056 enum _dcp_hash_digest_len
0057 {
0058     kDCP_OutLenSha1   = 20u,
0059     kDCP_OutLenSha256 = 32u,
0060     kDCP_OutLenCrc32  = 4u,
0061 };
0062 
0063 enum _dcp_work_packet_bit_definitions
0064 {
0065     kDCP_CONTROL0_DECR_SEMAPHOR      = 1u << 1,  /* DECR_SEMAPHOR */
0066     kDCP_CONTROL0_ENABLE_HASH        = 1u << 6,  /* ENABLE_HASH */
0067     kDCP_CONTROL0_HASH_INIT          = 1u << 12, /* HASH_INIT */
0068     kDCP_CONTROL0_HASH_TERM          = 1u << 13, /* HASH_TERM */
0069     kDCP_CONTROL1_HASH_SELECT_SHA256 = 2u << 16,
0070     kDCP_CONTROL1_HASH_SELECT_SHA1   = 0u << 16,
0071     kDCP_CONTROL1_HASH_SELECT_CRC32  = 1u << 16,
0072 };
0073 
0074 /*! 64-byte block represented as byte array of 16 32-bit words */
0075 typedef union _dcp_sha_block
0076 {
0077     uint32_t w[64 / 4]; /*!< array of 32-bit words */
0078     uint8_t b[64];      /*!< byte array */
0079 } dcp_sha_block_t;
0080 
0081 #if defined(DCP_HASH_CAVP_COMPATIBLE)
0082 /* result of sha1 hash for message with zero size */
0083 static uint8_t s_nullSha1[] = {0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55,
0084                                0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09};
0085 /* result of sha256 hash for message with zero size */
0086 static uint8_t s_nullSha256[] = {0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4,
0087                                  0xc8, 0x99, 0x6f, 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b,
0088                                  0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55};
0089 #endif /* DCP_HASH_CAVP_COMPATIBLE */
0090 
0091 /*******************************************************************************
0092  * Variables
0093  ******************************************************************************/
0094 AT_NONCACHEABLE_SECTION_INIT(static dcp_context_t s_dcpContextSwitchingBuffer);
0095 
0096 /*******************************************************************************
0097  * Code
0098  ******************************************************************************/
0099 
0100 static void dcp_reverse_and_copy(uint8_t *src, uint8_t *dest, size_t src_len)
0101 {
0102     for (uint32_t i = 0; i < src_len; i++)
0103     {
0104         dest[i] = src[src_len - 1U - i];
0105     }
0106 }
0107 
0108 #if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) && defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
0109 static inline uint32_t *DCP_FindCacheLine(uint8_t *dcpWorkExt)
0110 {
0111     while (0U != ((uint32_t)dcpWorkExt & ((uint32_t)FSL_FEATURE_L1DCACHE_LINESIZE_BYTE - 1U)))
0112     {
0113         dcpWorkExt++;
0114     }
0115     return (uint32_t *)(uint32_t)dcpWorkExt;
0116 }
0117 #endif
0118 
0119 static status_t dcp_get_channel_status(DCP_Type *base, dcp_channel_t channel)
0120 {
0121     uint32_t statReg = 0;
0122     uint32_t semaReg = 0;
0123     status_t status  = kStatus_Fail;
0124 
0125     switch (channel)
0126     {
0127         case kDCP_Channel0:
0128             statReg = base->CH0STAT;
0129             semaReg = base->CH0SEMA;
0130             break;
0131 
0132         case kDCP_Channel1:
0133             statReg = base->CH1STAT;
0134             semaReg = base->CH1SEMA;
0135             break;
0136 
0137         case kDCP_Channel2:
0138             statReg = base->CH2STAT;
0139             semaReg = base->CH2SEMA;
0140             break;
0141 
0142         case kDCP_Channel3:
0143             statReg = base->CH3STAT;
0144             semaReg = base->CH3SEMA;
0145             break;
0146 
0147         default:
0148             /* All the cases have been listed above, the default clause should not be reached. */
0149             break;
0150     }
0151 
0152     if (!((0U != (semaReg & DCP_CH0SEMA_VALUE_MASK)) || (0U != (statReg & DCP_CH0STAT_ERROR_CODE_MASK))))
0153     {
0154         status = kStatus_Success;
0155     }
0156 
0157     return status;
0158 }
0159 
0160 static void dcp_clear_status(DCP_Type *base)
0161 {
0162     volatile uint32_t *dcpStatClrPtr = (volatile uint32_t *)&base->STAT + 2u;
0163     *dcpStatClrPtr                   = 0xFFu;
0164 
0165     while ((base->STAT & 0xffu) != 0U)
0166     {
0167     }
0168 }
0169 
0170 static void dcp_clear_channel_status(DCP_Type *base, uint32_t mask)
0171 {
0172     volatile uint32_t *chStatClrPtr;
0173 
0174     if (0U != (mask & (uint32_t)kDCP_Channel0))
0175     {
0176         chStatClrPtr  = &base->CH0STAT_CLR;
0177         *chStatClrPtr = 0xFFu;
0178     }
0179     if (0U != (mask & (uint32_t)kDCP_Channel1))
0180     {
0181         chStatClrPtr  = &base->CH1STAT_CLR;
0182         *chStatClrPtr = 0xFFu;
0183     }
0184     if (0U != (mask & (uint32_t)kDCP_Channel2))
0185     {
0186         chStatClrPtr  = &base->CH2STAT_CLR;
0187         *chStatClrPtr = 0xFFu;
0188     }
0189     if (0U != (mask & (uint32_t)kDCP_Channel3))
0190     {
0191         chStatClrPtr  = &base->CH3STAT_CLR;
0192         *chStatClrPtr = 0xFFu;
0193     }
0194 }
0195 
0196 static status_t dcp_aes_set_sram_based_key(DCP_Type *base, dcp_handle_t *handle, const uint8_t *key)
0197 {
0198     base->KEY = DCP_KEY_INDEX(handle->keySlot) | DCP_KEY_SUBWORD(0);
0199     /* move the key by 32-bit words */
0200     int i          = 0;
0201     size_t keySize = 16u;
0202     while (keySize != 0U)
0203     {
0204         keySize -= sizeof(uint32_t);
0205         base->KEYDATA = ((uint32_t *)(uintptr_t)key)[i];
0206         i++;
0207     }
0208     return kStatus_Success;
0209 }
0210 
0211 /* Disable optimizations for GCC to prevent instruction reordering */
0212 #if defined(__GNUC__)
0213 #pragma GCC push_options
0214 #pragma GCC optimize("O0")
0215 #endif
0216 static status_t dcp_schedule_work(DCP_Type *base, dcp_handle_t *handle, dcp_work_packet_t *dcpPacket)
0217 {
0218     status_t status;
0219 
0220     /* check if our channel is active */
0221     if ((base->STAT & (uint32_t)handle->channel) != (uint32_t)handle->channel)
0222     {
0223         /* disable global interrupt */
0224         uint32_t currPriMask = DisableGlobalIRQ();
0225 
0226         /* re-check if our channel is still available */
0227         if ((base->STAT & (uint32_t)handle->channel) == 0U)
0228         {
0229             volatile uint32_t *cmdptr = NULL;
0230             volatile uint32_t *chsema = NULL;
0231 
0232             switch (handle->channel)
0233             {
0234                 case kDCP_Channel0:
0235                     cmdptr = &base->CH0CMDPTR;
0236                     chsema = &base->CH0SEMA;
0237                     break;
0238 
0239                 case kDCP_Channel1:
0240                     cmdptr = &base->CH1CMDPTR;
0241                     chsema = &base->CH1SEMA;
0242                     break;
0243 
0244                 case kDCP_Channel2:
0245                     cmdptr = &base->CH2CMDPTR;
0246                     chsema = &base->CH2SEMA;
0247                     break;
0248 
0249                 case kDCP_Channel3:
0250                     cmdptr = &base->CH3CMDPTR;
0251                     chsema = &base->CH3SEMA;
0252                     break;
0253 
0254                 default:
0255                     /* All the cases have been listed above, the default clause should not be reached. */
0256                     break;
0257             }
0258 
0259             if ((NULL != cmdptr) && (NULL != chsema))
0260             {
0261                 /* set out packet to DCP CMDPTR */
0262                 *cmdptr = (uint32_t)dcpPacket;
0263 
0264 #if defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
0265                 /* Clean DCACHE before sending DCP packet to engine */
0266                 DCACHE_CleanByRange((uint32_t)dcpPacket, sizeof(dcp_work_packet_t));
0267 #endif
0268                 /* Make sure that all data memory accesses are completed before starting of the job */
0269                 __DSB();
0270                 __ISB();
0271 
0272                 /* set the channel semaphore to start the job */
0273                 *chsema = 1u;
0274             }
0275 
0276             status = kStatus_Success;
0277         }
0278 
0279         else
0280         {
0281             status = (int32_t)kStatus_DCP_Again;
0282         }
0283         /* global interrupt enable */
0284         EnableGlobalIRQ(currPriMask);
0285     }
0286 
0287     else
0288     {
0289         return (int32_t)kStatus_DCP_Again;
0290     }
0291 
0292     return status;
0293 }
0294 #if defined(__GNUC__)
0295 #pragma GCC pop_options
0296 #endif
0297 
0298 /*!
0299  * brief Set AES key to dcp_handle_t struct and optionally to DCP.
0300  *
0301  * Sets the AES key for encryption/decryption with the dcp_handle_t structure.
0302  * The dcp_handle_t input argument specifies keySlot.
0303  * If the keySlot is kDCP_OtpKey, the function will check the OTP_KEY_READY bit and will return it's ready to use
0304  * status.
0305  * For other keySlot selections, the function will copy and hold the key in dcp_handle_t struct.
0306  * If the keySlot is one of the four DCP SRAM-based keys (one of kDCP_KeySlot0, kDCP_KeySlot1, kDCP_KeySlot2,
0307  * kDCP_KeySlot3),
0308  * this function will also load the supplied key to the specified keySlot in DCP.
0309  *
0310  * param   base DCP peripheral base address.
0311  * param   handle Handle used for the request.
0312  * param   key 0-mod-4 aligned pointer to AES key.
0313  * param   keySize AES key size in bytes. Shall equal 16.
0314  * return  status from set key operation
0315  */
0316 status_t DCP_AES_SetKey(DCP_Type *base, dcp_handle_t *handle, const uint8_t *key, size_t keySize)
0317 {
0318     status_t status = kStatus_Fail;
0319 
0320     if ((kDCP_OtpKey == handle->keySlot) || (kDCP_OtpUniqueKey == handle->keySlot))
0321     {
0322         /* for AES OTP and unique key, check and return read from fuses status */
0323         if ((base->STAT & DCP_STAT_OTP_KEY_READY_MASK) == DCP_STAT_OTP_KEY_READY_MASK)
0324         {
0325             status = kStatus_Success;
0326         }
0327     }
0328     else
0329     {
0330         /* only work with aligned key[] */
0331         if ((0x3U & (uintptr_t)key) != 0U)
0332         {
0333             return kStatus_InvalidArgument;
0334         }
0335 
0336         /* keySize must be 16. */
0337         if (keySize != 16U)
0338         {
0339             return kStatus_InvalidArgument;
0340         }
0341 
0342         /* move the key by 32-bit words */
0343         int i = 0;
0344         while (keySize != 0U)
0345         {
0346             keySize -= sizeof(uint32_t);
0347             handle->keyWord[i] = ((uint32_t *)(uintptr_t)key)[i];
0348             i++;
0349         }
0350 
0351         if (kDCP_PayloadKey != handle->keySlot)
0352         {
0353             /* move the key by 32-bit words to DCP SRAM-based key storage */
0354             status = dcp_aes_set_sram_based_key(base, handle, key);
0355         }
0356         else
0357         {
0358             /* for PAYLOAD_KEY, just return Ok status now */
0359             status = kStatus_Success;
0360         }
0361     }
0362 
0363     return status;
0364 }
0365 
0366 /*!
0367  * brief Encrypts AES on one or multiple 128-bit block(s).
0368  *
0369  * Encrypts AES.
0370  * The source plaintext and destination ciphertext can overlap in system memory.
0371  *
0372  * param base DCP peripheral base address
0373  * param handle Handle used for this request.
0374  * param plaintext Input plain text to encrypt
0375  * param[out] ciphertext Output cipher text
0376  * param size Size of input and output data in bytes. Must be multiple of 16 bytes.
0377  * return Status from encrypt operation
0378  */
0379 status_t DCP_AES_EncryptEcb(
0380     DCP_Type *base, dcp_handle_t *handle, const uint8_t *plaintext, uint8_t *ciphertext, size_t size)
0381 {
0382     status_t completionStatus = kStatus_Fail;
0383 
0384     /* Use extended  DCACHE line size aligned structure */
0385 #if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) && defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
0386     dcp_work_packet_t *dcpWork;
0387     uint8_t dcpWorkExt[sizeof(dcp_work_packet_t) + FSL_FEATURE_L1DCACHE_LINESIZE_BYTE] = {0U};
0388     dcpWork = (dcp_work_packet_t *)(uint32_t)DCP_FindCacheLine(dcpWorkExt);
0389 #else
0390     dcp_work_packet_t dcpWorkPacket = {0};
0391     dcp_work_packet_t *dcpWork      = &dcpWorkPacket;
0392 #endif
0393 
0394     do
0395     {
0396         completionStatus = DCP_AES_EncryptEcbNonBlocking(base, handle, dcpWork, plaintext, ciphertext, size);
0397     } while (completionStatus == (int32_t)kStatus_DCP_Again);
0398 
0399     if (completionStatus != kStatus_Success)
0400     {
0401         return completionStatus;
0402     }
0403 
0404     return DCP_WaitForChannelComplete(base, handle);
0405 }
0406 
0407 /*!
0408  * brief Encrypts AES using the ECB block mode.
0409  *
0410  * Puts AES ECB encrypt work packet to DCP channel.
0411  *
0412  * param base DCP peripheral base address
0413  * param handle Handle used for this request.
0414  * param[out] dcpPacket Memory for the DCP work packet.
0415  * param plaintext Input plain text to encrypt.
0416  * param[out] ciphertext Output cipher text
0417  * param size Size of input and output data in bytes. Must be multiple of 16 bytes.
0418  * return kStatus_Success The work packet has been scheduled at DCP channel.
0419  * return kStatus_DCP_Again The DCP channel is busy processing previous request.
0420  */
0421 status_t DCP_AES_EncryptEcbNonBlocking(DCP_Type *base,
0422                                        dcp_handle_t *handle,
0423                                        dcp_work_packet_t *dcpPacket,
0424                                        const uint8_t *plaintext,
0425                                        uint8_t *ciphertext,
0426                                        size_t size)
0427 {
0428     /* Size must be 16-byte multiple */
0429     if ((size < 16u) || (0U != (size % 16u)))
0430     {
0431         return kStatus_InvalidArgument;
0432     }
0433 
0434     dcpPacket->control0 =
0435         0x122u | (handle->swapConfig & 0xFC0000u); /* CIPHER_ENCRYPT | ENABLE_CIPHER | DECR_SEMAPHORE */
0436     dcpPacket->sourceBufferAddress      = (uint32_t)plaintext;
0437     dcpPacket->destinationBufferAddress = (uint32_t)ciphertext;
0438     dcpPacket->bufferSize               = (uint32_t)size;
0439 
0440     if (handle->keySlot == kDCP_OtpKey)
0441     {
0442         dcpPacket->control0 |= ((uint32_t)1u << 10);  /* OTP_KEY */
0443         dcpPacket->control1 = ((uint32_t)0xFFu << 8); /* KEY_SELECT = OTP_KEY */
0444     }
0445     else if (handle->keySlot == kDCP_OtpUniqueKey)
0446     {
0447         dcpPacket->control0 |= ((uint32_t)1u << 10);  /* OTP_KEY */
0448         dcpPacket->control1 = ((uint32_t)0xFEu << 8); /* KEY_SELECT = UNIQUE_KEY */
0449     }
0450     else if (handle->keySlot == kDCP_PayloadKey)
0451     {
0452         /* ECB does not have IV, so we can point payload directly to keyWord[] stored in handle. */
0453         dcpPacket->payloadPointer = (uint32_t)&handle->keyWord[0];
0454         dcpPacket->control0 |= ((uint32_t)1u << 11); /* PAYLOAD_KEY */
0455     }
0456     else
0457     {
0458         dcpPacket->control1 = ((uint32_t)handle->keySlot << 8); /* KEY_SELECT = keySlot */
0459     }
0460 
0461     return dcp_schedule_work(base, handle, dcpPacket);
0462 }
0463 
0464 /*!
0465  * brief Decrypts AES on one or multiple 128-bit block(s).
0466  *
0467  * Decrypts AES.
0468  * The source ciphertext and destination plaintext can overlap in system memory.
0469  *
0470  * param base DCP peripheral base address
0471  * param handle Handle used for this request.
0472  * param ciphertext Input plain text to encrypt
0473  * param[out] plaintext Output cipher text
0474  * param size Size of input and output data in bytes. Must be multiple of 16 bytes.
0475  * return Status from decrypt operation
0476  */
0477 status_t DCP_AES_DecryptEcb(
0478     DCP_Type *base, dcp_handle_t *handle, const uint8_t *ciphertext, uint8_t *plaintext, size_t size)
0479 {
0480     status_t completionStatus = kStatus_Fail;
0481 
0482     /* Use extended  DCACHE line size aligned structure */
0483 #if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) && defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
0484     dcp_work_packet_t *dcpWork;
0485     uint8_t dcpWorkExt[sizeof(dcp_work_packet_t) + FSL_FEATURE_L1DCACHE_LINESIZE_BYTE] = {0U};
0486     dcpWork = (dcp_work_packet_t *)(uint32_t)DCP_FindCacheLine(dcpWorkExt);
0487 #else
0488     dcp_work_packet_t dcpWorkPacket = {0};
0489     dcp_work_packet_t *dcpWork      = &dcpWorkPacket;
0490 #endif
0491 
0492     do
0493     {
0494         completionStatus = DCP_AES_DecryptEcbNonBlocking(base, handle, dcpWork, ciphertext, plaintext, size);
0495     } while (completionStatus == (int32_t)(kStatus_DCP_Again));
0496 
0497     if (completionStatus != kStatus_Success)
0498     {
0499         return completionStatus;
0500     }
0501 
0502     return DCP_WaitForChannelComplete(base, handle);
0503 }
0504 
0505 /*!
0506  * brief Decrypts AES using ECB block mode.
0507  *
0508  * Puts AES ECB decrypt dcpPacket to DCP input job ring.
0509  *
0510  * param base DCP peripheral base address
0511  * param handle Handle used for this request.
0512  * param[out] dcpPacket Memory for the DCP work packet.
0513  * param ciphertext Input cipher text to decrypt
0514  * param[out] plaintext Output plain text
0515  * param size Size of input and output data in bytes. Must be multiple of 16 bytes.
0516  * return kStatus_Success The work packet has been scheduled at DCP channel.
0517  * return kStatus_DCP_Again The DCP channel is busy processing previous request.
0518  */
0519 status_t DCP_AES_DecryptEcbNonBlocking(DCP_Type *base,
0520                                        dcp_handle_t *handle,
0521                                        dcp_work_packet_t *dcpPacket,
0522                                        const uint8_t *ciphertext,
0523                                        uint8_t *plaintext,
0524                                        size_t size)
0525 {
0526     /* Size must be 16-byte multiple */
0527     if ((size < 16u) || (0U != (size % 16u)))
0528     {
0529         return kStatus_InvalidArgument;
0530     }
0531 
0532     dcpPacket->control0                 = 0x22u | (handle->swapConfig & 0xFC0000u); /* ENABLE_CIPHER | DECR_SEMAPHORE */
0533     dcpPacket->sourceBufferAddress      = (uint32_t)ciphertext;
0534     dcpPacket->destinationBufferAddress = (uint32_t)plaintext;
0535     dcpPacket->bufferSize               = (uint32_t)size;
0536 
0537     if (handle->keySlot == kDCP_OtpKey)
0538     {
0539         dcpPacket->control0 |= ((uint32_t)1u << 10);  /* OTP_KEY */
0540         dcpPacket->control1 = ((uint32_t)0xFFu << 8); /* KEY_SELECT = OTP_KEY */
0541     }
0542     else if (handle->keySlot == kDCP_OtpUniqueKey)
0543     {
0544         dcpPacket->control0 |= ((uint32_t)1u << 10);  /* OTP_KEY */
0545         dcpPacket->control1 = ((uint32_t)0xFEu << 8); /* KEY_SELECT = UNIQUE_KEY */
0546     }
0547     else if (handle->keySlot == kDCP_PayloadKey)
0548     {
0549         /* ECB does not have IV, so we can point payload directly to keyWord[] stored in handle. */
0550         dcpPacket->payloadPointer = (uint32_t)&handle->keyWord[0];
0551         dcpPacket->control0 |= ((uint32_t)1u << 11); /* PAYLOAD_KEY */
0552     }
0553     else
0554     {
0555         dcpPacket->control1 = ((uint32_t)handle->keySlot << 8); /* KEY_SELECT = keySlot */
0556     }
0557 
0558     return dcp_schedule_work(base, handle, dcpPacket);
0559 }
0560 
0561 /*!
0562  * brief Encrypts AES using CBC block mode.
0563  *
0564  * Encrypts AES using CBC block mode.
0565  * The source plaintext and destination ciphertext can overlap in system memory.
0566  *
0567  * param base DCP peripheral base address
0568  * param handle Handle used for this request.
0569  * param plaintext Input plain text to encrypt
0570  * param[out] ciphertext Output cipher text
0571  * param size Size of input and output data in bytes. Must be multiple of 16 bytes.
0572  * param iv Input initial vector to combine with the first input block.
0573  * return Status from encrypt operation
0574  */
0575 status_t DCP_AES_EncryptCbc(DCP_Type *base,
0576                             dcp_handle_t *handle,
0577                             const uint8_t *plaintext,
0578                             uint8_t *ciphertext,
0579                             size_t size,
0580                             const uint8_t iv[16])
0581 {
0582     status_t completionStatus = kStatus_Fail;
0583 
0584     /* Use extended  DCACHE line size aligned structure */
0585 #if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) && defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
0586     dcp_work_packet_t *dcpWork;
0587     uint8_t dcpWorkExt[sizeof(dcp_work_packet_t) + FSL_FEATURE_L1DCACHE_LINESIZE_BYTE] = {0U};
0588     dcpWork = (dcp_work_packet_t *)(uint32_t)DCP_FindCacheLine(dcpWorkExt);
0589 #else
0590     dcp_work_packet_t dcpWorkPacket = {0};
0591     dcp_work_packet_t *dcpWork      = &dcpWorkPacket;
0592 #endif
0593 
0594     do
0595     {
0596         completionStatus = DCP_AES_EncryptCbcNonBlocking(base, handle, dcpWork, plaintext, ciphertext, size, iv);
0597     } while (completionStatus == (int32_t)kStatus_DCP_Again);
0598 
0599     if (completionStatus != kStatus_Success)
0600     {
0601         return completionStatus;
0602     }
0603 
0604     return DCP_WaitForChannelComplete(base, handle);
0605 }
0606 
0607 /*!
0608  * brief Encrypts AES using CBC block mode.
0609  *
0610  * Puts AES CBC encrypt dcpPacket to DCP input job ring.
0611  *
0612  * param base DCP peripheral base address
0613  * param handle Handle used for this request. Specifies jobRing.
0614  * param[out] dcpPacket Memory for the DCP work packet.
0615  * param plaintext Input plain text to encrypt
0616  * param[out] ciphertext Output cipher text
0617  * param size Size of input and output data in bytes. Must be multiple of 16 bytes.
0618  * param iv Input initial vector to combine with the first input block.
0619  * return kStatus_Success The work packet has been scheduled at DCP channel.
0620  * return kStatus_DCP_Again The DCP channel is busy processing previous request.
0621  */
0622 status_t DCP_AES_EncryptCbcNonBlocking(DCP_Type *base,
0623                                        dcp_handle_t *handle,
0624                                        dcp_work_packet_t *dcpPacket,
0625                                        const uint8_t *plaintext,
0626                                        uint8_t *ciphertext,
0627                                        size_t size,
0628                                        const uint8_t *iv)
0629 {
0630     /* Size must be 16-byte multiple */
0631     if ((size < 16u) || (0U != (size % 16u)))
0632     {
0633         return kStatus_InvalidArgument;
0634     }
0635 
0636     dcpPacket->control0 =
0637         0x322u | (handle->swapConfig & 0xFC0000u); /* CIPHER_INIT | CIPHER_ENCRYPT | ENABLE_CIPHER | DECR_SEMAPHORE */
0638     dcpPacket->control1                 = 0x10u;   /* CBC */
0639     dcpPacket->sourceBufferAddress      = (uint32_t)plaintext;
0640     dcpPacket->destinationBufferAddress = (uint32_t)ciphertext;
0641     dcpPacket->bufferSize               = (uint32_t)size;
0642 
0643     if (handle->keySlot == kDCP_OtpKey)
0644     {
0645         dcpPacket->payloadPointer = (uint32_t)iv;
0646         dcpPacket->control0 |= ((uint32_t)1u << 10);   /* OTP_KEY */
0647         dcpPacket->control1 |= ((uint32_t)0xFFu << 8); /* KEY_SELECT = OTP_KEY */
0648     }
0649     else if (handle->keySlot == kDCP_OtpUniqueKey)
0650     {
0651         dcpPacket->payloadPointer = (uint32_t)iv;
0652         dcpPacket->control0 |= ((uint32_t)1u << 10);   /* OTP_KEY */
0653         dcpPacket->control1 |= ((uint32_t)0xFEu << 8); /* KEY_SELECT = UNIQUE_KEY */
0654     }
0655     else if (handle->keySlot == kDCP_PayloadKey)
0656     {
0657         /* In this case payload must contain key & iv in one array. */
0658         /* Copy iv into handle right behind the keyWord[] so we can point payload to keyWord[]. */
0659         (void)dcp_memcpy(handle->iv, (const uint32_t *)(uintptr_t)iv, 16);
0660         dcpPacket->payloadPointer = (uint32_t)&handle->keyWord[0];
0661         dcpPacket->control0 |= ((uint32_t)1u << 11); /* PAYLOAD_KEY */
0662     }
0663     else
0664     {
0665         dcpPacket->payloadPointer = (uint32_t)iv;
0666         dcpPacket->control1 |= ((uint32_t)handle->keySlot << 8); /* KEY_SELECT = keySlot */
0667     }
0668 
0669     return dcp_schedule_work(base, handle, dcpPacket);
0670 }
0671 
0672 /*!
0673  * brief Decrypts AES using CBC block mode.
0674  *
0675  * Decrypts AES using CBC block mode.
0676  * The source ciphertext and destination plaintext can overlap in system memory.
0677  *
0678  * param base DCP peripheral base address
0679  * param handle Handle used for this request.
0680  * param ciphertext Input cipher text to decrypt
0681  * param[out] plaintext Output plain text
0682  * param size Size of input and output data in bytes. Must be multiple of 16 bytes.
0683  * param iv Input initial vector to combine with the first input block.
0684  * return Status from decrypt operation
0685  */
0686 status_t DCP_AES_DecryptCbc(DCP_Type *base,
0687                             dcp_handle_t *handle,
0688                             const uint8_t *ciphertext,
0689                             uint8_t *plaintext,
0690                             size_t size,
0691                             const uint8_t iv[16])
0692 {
0693     status_t completionStatus = kStatus_Fail;
0694 
0695     /* Use extended  DCACHE line size aligned structure */
0696 #if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) && defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
0697     dcp_work_packet_t *dcpWork;
0698     uint8_t dcpWorkExt[sizeof(dcp_work_packet_t) + FSL_FEATURE_L1DCACHE_LINESIZE_BYTE] = {0U};
0699     dcpWork = (dcp_work_packet_t *)(uint32_t)DCP_FindCacheLine(dcpWorkExt);
0700 #else
0701     dcp_work_packet_t dcpWorkPacket = {0};
0702     dcp_work_packet_t *dcpWork      = &dcpWorkPacket;
0703 #endif
0704 
0705     do
0706     {
0707         completionStatus = DCP_AES_DecryptCbcNonBlocking(base, handle, dcpWork, ciphertext, plaintext, size, iv);
0708     } while (completionStatus == (int32_t)kStatus_DCP_Again);
0709 
0710     if (completionStatus != (int32_t)kStatus_Success)
0711     {
0712         return completionStatus;
0713     }
0714 
0715     return DCP_WaitForChannelComplete(base, handle);
0716 }
0717 
0718 /*!
0719  * brief Decrypts AES using CBC block mode.
0720  *
0721  * Puts AES CBC decrypt dcpPacket to DCP input job ring.
0722  *
0723  * param base DCP peripheral base address
0724  * param handle Handle used for this request. Specifies jobRing.
0725  * param[out] dcpPacket Memory for the DCP work packet.
0726  * param ciphertext Input cipher text to decrypt
0727  * param[out] plaintext Output plain text
0728  * param size Size of input and output data in bytes. Must be multiple of 16 bytes.
0729  * param iv Input initial vector to combine with the first input block.
0730  * return kStatus_Success The work packet has been scheduled at DCP channel.
0731  * return kStatus_DCP_Again The DCP channel is busy processing previous request.
0732  */
0733 status_t DCP_AES_DecryptCbcNonBlocking(DCP_Type *base,
0734                                        dcp_handle_t *handle,
0735                                        dcp_work_packet_t *dcpPacket,
0736                                        const uint8_t *ciphertext,
0737                                        uint8_t *plaintext,
0738                                        size_t size,
0739                                        const uint8_t *iv)
0740 {
0741     /* Size must be 16-byte multiple */
0742     if ((size < 16u) || (0U != (size % 16u)))
0743     {
0744         return kStatus_InvalidArgument;
0745     }
0746 
0747     dcpPacket->control0 = 0x222u | (handle->swapConfig & 0xFC0000u); /* CIPHER_INIT | ENABLE_CIPHER | DECR_SEMAPHORE */
0748     dcpPacket->control1 = 0x10u;                                     /* CBC */
0749     dcpPacket->sourceBufferAddress      = (uint32_t)ciphertext;
0750     dcpPacket->destinationBufferAddress = (uint32_t)plaintext;
0751     dcpPacket->bufferSize               = (uint32_t)size;
0752 
0753     if (handle->keySlot == kDCP_OtpKey)
0754     {
0755         dcpPacket->payloadPointer = (uint32_t)iv;
0756         dcpPacket->control0 |= ((uint32_t)1u << 10);   /* OTP_KEY */
0757         dcpPacket->control1 |= ((uint32_t)0xFFu << 8); /* OTP_KEY */
0758     }
0759     else if (handle->keySlot == kDCP_OtpUniqueKey)
0760     {
0761         dcpPacket->payloadPointer = (uint32_t)iv;
0762         dcpPacket->control0 |= ((uint32_t)1u << 10);   /* OTP_KEY */
0763         dcpPacket->control1 |= ((uint32_t)0xFEu << 8); /* UNIQUE_KEY */
0764     }
0765     else if (handle->keySlot == kDCP_PayloadKey)
0766     {
0767         /* in this case payload must contain KEY + IV together */
0768         /* copy iv into handle struct so we can point payload directly to keyWord[]. */
0769         (void)dcp_memcpy(handle->iv, (const uint32_t *)(uintptr_t)iv, 16);
0770         dcpPacket->payloadPointer = (uint32_t)&handle->keyWord[0];
0771         dcpPacket->control0 |= ((uint32_t)1u << 11); /* PAYLOAD_KEY */
0772     }
0773     else
0774     {
0775         dcpPacket->payloadPointer = (uint32_t)iv;
0776         dcpPacket->control1 |= ((uint32_t)handle->keySlot << 8); /* KEY_SELECT */
0777     }
0778 
0779     return dcp_schedule_work(base, handle, dcpPacket);
0780 }
0781 
0782 /*!
0783  * brief Gets the default configuration structure.
0784  *
0785  * This function initializes the DCP configuration structure to a default value. The default
0786  * values are as follows.
0787  *   dcpConfig->gatherResidualWrites = true;
0788  *   dcpConfig->enableContextCaching = true;
0789  *   dcpConfig->enableContextSwitching = true;
0790  *   dcpConfig->enableChannnel = kDCP_chEnableAll;
0791  *   dcpConfig->enableChannelInterrupt = kDCP_chIntDisable;
0792  *
0793  * param[out] config Pointer to configuration structure.
0794  */
0795 void DCP_GetDefaultConfig(dcp_config_t *config)
0796 {
0797     /* ENABLE_CONTEXT_CACHING is disabled by default as the DCP Hash driver uses
0798      * dcp_hash_save_running_hash() and dcp_hash_restore_running_hash() to support
0799      * Hash context switch (different messages interleaved) on the same channel.
0800      */
0801 
0802     /* Initializes the configure structure to zero. */
0803     (void)memset(config, 0, sizeof(*config));
0804 
0805     dcp_config_t userConfig = {
0806         true, false, true, (uint8_t)kDCP_chEnableAll, (uint8_t)kDCP_chIntDisable,
0807     };
0808 
0809     *config = userConfig;
0810 }
0811 
0812 /*!
0813  * brief   Enables clock to and enables DCP
0814  *
0815  * Enable DCP clock and configure DCP.
0816  *
0817  * param base DCP base address
0818  * param config Pointer to configuration structure.
0819  */
0820 void DCP_Init(DCP_Type *base, const dcp_config_t *config)
0821 {
0822 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
0823     CLOCK_EnableClock(kCLOCK_Dcp);
0824 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
0825 
0826     base->CTRL = 0xF0800000u; /* reset value */
0827     base->CTRL = 0x30800000u; /* default value */
0828 
0829     dcp_clear_status(base);
0830     dcp_clear_channel_status(
0831         base, (uint32_t)kDCP_Channel0 | (uint32_t)kDCP_Channel1 | (uint32_t)kDCP_Channel2 | (uint32_t)kDCP_Channel3);
0832 
0833     base->CTRL = DCP_CTRL_GATHER_RESIDUAL_WRITES(config->gatherResidualWrites) |
0834                  DCP_CTRL_ENABLE_CONTEXT_CACHING(config->enableContextCaching) |
0835                  DCP_CTRL_ENABLE_CONTEXT_SWITCHING(config->enableContextSwitching) |
0836                  DCP_CTRL_CHANNEL_INTERRUPT_ENABLE(config->enableChannelInterrupt);
0837 
0838     /* enable DCP channels */
0839     base->CHANNELCTRL = DCP_CHANNELCTRL_ENABLE_CHANNEL(config->enableChannel);
0840 
0841     /* use context switching buffer */
0842     base->CONTEXT = (uint32_t)&s_dcpContextSwitchingBuffer;
0843 }
0844 
0845 /*!
0846  * brief   Disable DCP clock
0847  *
0848  * Reset DCP and Disable DCP clock.
0849  *
0850  * param base DCP base address
0851  */
0852 void DCP_Deinit(DCP_Type *base)
0853 {
0854     base->CTRL = 0xF0800000u; /* reset value */
0855     (void)memset(&s_dcpContextSwitchingBuffer, 0, sizeof(s_dcpContextSwitchingBuffer));
0856 
0857 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
0858     CLOCK_DisableClock(kCLOCK_Dcp);
0859 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
0860 }
0861 
0862 /*!
0863  * brief Poll and wait on DCP channel.
0864  *
0865  * Polls the specified DCP channel until current it completes activity.
0866  *
0867  * param   base DCP peripheral base address.
0868  * param   handle Specifies DCP channel.
0869  * return  kStatus_Success When data processing completes without error.
0870  * return  kStatus_Fail When error occurs.
0871  */
0872 status_t DCP_WaitForChannelComplete(DCP_Type *base, dcp_handle_t *handle)
0873 {
0874     /* wait if our channel is still active */
0875     while ((base->STAT & (uint32_t)handle->channel) == (uint32_t)handle->channel)
0876     {
0877     }
0878 
0879     if (dcp_get_channel_status(base, handle->channel) != kStatus_Success)
0880     {
0881         dcp_clear_status(base);
0882         dcp_clear_channel_status(base, (uint32_t)handle->channel);
0883         return kStatus_Fail;
0884     }
0885 
0886     dcp_clear_status(base);
0887     return kStatus_Success;
0888 }
0889 
0890 /*!
0891  * @brief Check validity of algoritm.
0892  *
0893  * This function checks the validity of input argument.
0894  *
0895  * @param algo Tested algorithm value.
0896  * @return kStatus_Success if valid, kStatus_InvalidArgument otherwise.
0897  */
0898 static status_t dcp_hash_check_input_alg(dcp_hash_algo_t algo)
0899 {
0900     if ((algo != kDCP_Sha256) && (algo != kDCP_Sha1) && (algo != kDCP_Crc32))
0901     {
0902         return kStatus_InvalidArgument;
0903     }
0904     return kStatus_Success;
0905 }
0906 
0907 /*!
0908  * @brief Check validity of input arguments.
0909  *
0910  * This function checks the validity of input arguments.
0911  *
0912  * @param base DCP peripheral base address.
0913  * @param ctx Memory buffer given by user application where the DCP_HASH_Init/DCP_HASH_Update/DCP_HASH_Finish store
0914  * context.
0915  * @param algo Tested algorithm value.
0916  * @return kStatus_Success if valid, kStatus_InvalidArgument otherwise.
0917  */
0918 static status_t dcp_hash_check_input_args(DCP_Type *base, dcp_hash_ctx_t *ctx, dcp_hash_algo_t algo)
0919 {
0920     /* Check validity of input algorithm */
0921     if (kStatus_Success != dcp_hash_check_input_alg(algo))
0922     {
0923         return kStatus_InvalidArgument;
0924     }
0925 
0926     if ((NULL == ctx) || (NULL == base))
0927     {
0928         return kStatus_InvalidArgument;
0929     }
0930 
0931     return kStatus_Success;
0932 }
0933 
0934 /*!
0935  * @brief Check validity of internal software context.
0936  *
0937  * This function checks if the internal context structure looks correct.
0938  *
0939  * @param ctxInternal Internal context.
0940  * @param message Input message address.
0941  * @return kStatus_Success if valid, kStatus_InvalidArgument otherwise.
0942  */
0943 static status_t dcp_hash_check_context(dcp_hash_ctx_internal_t *ctxInternal, const uint8_t *message)
0944 {
0945     if ((NULL == message) || (NULL == ctxInternal) || (kStatus_Success != dcp_hash_check_input_alg(ctxInternal->algo)))
0946     {
0947         return kStatus_InvalidArgument;
0948     }
0949 
0950     return kStatus_Success;
0951 }
0952 
0953 /*!
0954  * @brief Initialize the SHA engine for new hash.
0955  *
0956  * This function sets kDCP_CONTROL0_HASH_INIT for control0 in work packet to start a new hash.
0957  *
0958  * @param base SHA peripheral base address.
0959  * @param ctxInternal Internal context.
0960  */
0961 static status_t dcp_hash_engine_init(DCP_Type *base, dcp_hash_ctx_internal_t *ctxInternal)
0962 {
0963     status_t status;
0964 
0965     status = kStatus_InvalidArgument;
0966 
0967     if ((kDCP_Sha256 == ctxInternal->algo) || (kDCP_Sha1 == ctxInternal->algo) || (kDCP_Crc32 == ctxInternal->algo))
0968     {
0969         ctxInternal->ctrl0 = (uint32_t)kDCP_CONTROL0_HASH_INIT;
0970         status             = kStatus_Success;
0971     }
0972 
0973     return status;
0974 }
0975 
0976 static status_t dcp_hash_update_non_blocking(
0977     DCP_Type *base, dcp_hash_ctx_internal_t *ctxInternal, dcp_work_packet_t *dcpPacket, const uint8_t *msg, size_t size)
0978 {
0979     dcpPacket->control0 = ctxInternal->ctrl0 | (ctxInternal->handle->swapConfig & 0xFC0000u) |
0980                           (uint32_t)kDCP_CONTROL0_ENABLE_HASH | (uint32_t)kDCP_CONTROL0_DECR_SEMAPHOR;
0981     if (ctxInternal->algo == kDCP_Sha256)
0982     {
0983         dcpPacket->control1 = (uint32_t)kDCP_CONTROL1_HASH_SELECT_SHA256;
0984     }
0985     else if (ctxInternal->algo == kDCP_Sha1)
0986     {
0987         dcpPacket->control1 = (uint32_t)kDCP_CONTROL1_HASH_SELECT_SHA1;
0988     }
0989     else if (ctxInternal->algo == kDCP_Crc32)
0990     {
0991         /* In CRC-32 case if size is zero, do not schedule other computing */
0992         if (size == 0U)
0993         {
0994 #if defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
0995             /* Clear DCACHE memory before starting the engine */
0996             DCACHE_CleanByRange((uint32_t)ctxInternal, sizeof(dcp_hash_ctx_internal_t));
0997 #endif
0998             /* Make sure that all data memory accesses are completed before starting of the job */
0999             __DSB();
1000             __ISB();
1001             return kStatus_Success;
1002         }
1003         dcpPacket->control1 = (uint32_t)kDCP_CONTROL1_HASH_SELECT_CRC32;
1004     }
1005     else
1006     {
1007         return kStatus_Fail;
1008     }
1009     dcpPacket->sourceBufferAddress      = (uint32_t)msg;
1010     dcpPacket->destinationBufferAddress = 0;
1011     dcpPacket->bufferSize               = size;
1012     dcpPacket->payloadPointer           = (uint32_t)ctxInternal->runningHash;
1013 
1014 #if defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
1015     /* Clear DCACHE memory before starting the engine */
1016     DCACHE_CleanByRange((uint32_t)ctxInternal, sizeof(dcp_hash_ctx_internal_t));
1017 #endif
1018     /* Make sure that all data memory accesses are completed before starting of the job */
1019     __DSB();
1020     __ISB();
1021 
1022     return dcp_schedule_work(base, ctxInternal->handle, dcpPacket);
1023 }
1024 
1025 static status_t dcp_hash_update(DCP_Type *base, dcp_hash_ctx_internal_t *ctxInternal, const uint8_t *msg, size_t size)
1026 {
1027     status_t completionStatus = kStatus_Fail;
1028 
1029     /* Use extended  DCACHE line size aligned structure */
1030 #if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) && defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
1031     dcp_work_packet_t *dcpWork;
1032     uint8_t dcpWorkExt[sizeof(dcp_work_packet_t) + FSL_FEATURE_L1DCACHE_LINESIZE_BYTE] = {0U};
1033     dcpWork = (dcp_work_packet_t *)(uint32_t)DCP_FindCacheLine(dcpWorkExt);
1034 #else
1035     dcp_work_packet_t dcpWorkPacket = {0};
1036     dcp_work_packet_t *dcpWork      = &dcpWorkPacket;
1037 #endif
1038 
1039     do
1040     {
1041         completionStatus = dcp_hash_update_non_blocking(base, ctxInternal, dcpWork, msg, size);
1042     } while (completionStatus == (int32_t)kStatus_DCP_Again);
1043 
1044     completionStatus = DCP_WaitForChannelComplete(base, ctxInternal->handle);
1045 
1046     ctxInternal->ctrl0 = 0; /* clear kDCP_CONTROL0_HASH_INIT and kDCP_CONTROL0_HASH_TERM flags */
1047     return (completionStatus);
1048 }
1049 
1050 /*!
1051  * @brief Adds message to current hash.
1052  *
1053  * This function merges the message to fill the internal buffer, empties the internal buffer if
1054  * it becomes full, then process all remaining message data.
1055  *
1056  *
1057  * @param base DCP peripheral base address.
1058  * @param ctxInternal Internal context.
1059  * @param message Input message.
1060  * @param messageSize Size of input message in bytes.
1061  * @return kStatus_Success.
1062  */
1063 static status_t dcp_hash_process_message_data(DCP_Type *base,
1064                                               dcp_hash_ctx_internal_t *ctxInternal,
1065                                               const uint8_t *message,
1066                                               size_t messageSize)
1067 {
1068     status_t status = kStatus_Fail;
1069 
1070     /* if there is partially filled internal buffer, fill it to full block */
1071     if (ctxInternal->blksz > 0U)
1072     {
1073         size_t toCopy = DCP_HASH_BLOCK_SIZE - ctxInternal->blksz;
1074         (void)dcp_memcpy(&ctxInternal->blk.b[ctxInternal->blksz], message, toCopy);
1075         message += toCopy;
1076         messageSize -= toCopy;
1077 
1078         /* process full internal block */
1079         status = dcp_hash_update(base, ctxInternal, &ctxInternal->blk.b[0], DCP_HASH_BLOCK_SIZE);
1080         if (kStatus_Success != status)
1081         {
1082             return status;
1083         }
1084     }
1085 
1086     /* process all full blocks in message[] */
1087     uint32_t fullBlocksSize = ((messageSize >> 6) << 6); /* (X / 64) * 64 */
1088     if (fullBlocksSize > 0U)
1089     {
1090         status = dcp_hash_update(base, ctxInternal, message, fullBlocksSize);
1091         if (kStatus_Success != status)
1092         {
1093             return status;
1094         }
1095         message += fullBlocksSize;
1096         messageSize -= fullBlocksSize;
1097     }
1098 
1099     /* copy last incomplete message bytes into internal block */
1100     (void)dcp_memcpy(&ctxInternal->blk.b[0], message, messageSize);
1101     ctxInternal->blksz = messageSize;
1102 
1103     return status;
1104 }
1105 
1106 /*!
1107  * @brief Finalize the running hash to make digest.
1108  *
1109  * This function empties the internal buffer, adds padding bits, and generates final digest.
1110  *
1111  * @param base SHA peripheral base address.
1112  * @param ctxInternal Internal context.
1113  * @return kStatus_Success.
1114  */
1115 static status_t dcp_hash_finalize(DCP_Type *base, dcp_hash_ctx_internal_t *ctxInternal)
1116 {
1117     status_t status;
1118 
1119     ctxInternal->ctrl0 |= (uint32_t)kDCP_CONTROL0_HASH_TERM;
1120     status = dcp_hash_update(base, ctxInternal, &ctxInternal->blk.b[0], ctxInternal->blksz);
1121 
1122     return status;
1123 }
1124 
1125 static void dcp_hash_save_running_hash(dcp_hash_ctx_internal_t *ctxInternal)
1126 {
1127     uint32_t *srcAddr = NULL;
1128 
1129     switch (ctxInternal->handle->channel)
1130     {
1131         case kDCP_Channel0:
1132             srcAddr = &s_dcpContextSwitchingBuffer.x[43];
1133             break;
1134 
1135         case kDCP_Channel1:
1136             srcAddr = &s_dcpContextSwitchingBuffer.x[30];
1137             break;
1138 
1139         case kDCP_Channel2:
1140             srcAddr = &s_dcpContextSwitchingBuffer.x[17];
1141             break;
1142 
1143         case kDCP_Channel3:
1144             srcAddr = &s_dcpContextSwitchingBuffer.x[4];
1145             break;
1146 
1147         default:
1148             /* All the cases have been listed above, the default clause should not be reached. */
1149             break;
1150     }
1151     if (srcAddr != NULL)
1152     {
1153         DCACHE_InvalidateByRange((uint32_t)srcAddr, sizeof(ctxInternal->runningHash));
1154         (void)dcp_memcpy(ctxInternal->runningHash, srcAddr, sizeof(ctxInternal->runningHash));
1155     }
1156 }
1157 
1158 static void dcp_hash_restore_running_hash(dcp_hash_ctx_internal_t *ctxInternal)
1159 {
1160     uint32_t *destAddr = NULL;
1161 
1162     switch (ctxInternal->handle->channel)
1163     {
1164         case kDCP_Channel0:
1165             destAddr = &s_dcpContextSwitchingBuffer.x[43];
1166             break;
1167 
1168         case kDCP_Channel1:
1169             destAddr = &s_dcpContextSwitchingBuffer.x[30];
1170             break;
1171 
1172         case kDCP_Channel2:
1173             destAddr = &s_dcpContextSwitchingBuffer.x[17];
1174             break;
1175 
1176         case kDCP_Channel3:
1177             destAddr = &s_dcpContextSwitchingBuffer.x[4];
1178             break;
1179 
1180         default:
1181             /* No valid channel */
1182             break;
1183     }
1184     if (destAddr != NULL)
1185     {
1186         (void)dcp_memcpy(destAddr, ctxInternal->runningHash, sizeof(ctxInternal->runningHash));
1187     }
1188 }
1189 
1190 /*!
1191  * brief Initialize HASH context
1192  *
1193  * This function initializes the HASH.
1194  *
1195  * param base DCP peripheral base address
1196  * param handle Specifies the DCP channel used for hashing.
1197  * param[out] ctx Output hash context
1198  * param algo Underlaying algorithm to use for hash computation.
1199  * return Status of initialization
1200  */
1201 status_t DCP_HASH_Init(DCP_Type *base, dcp_handle_t *handle, dcp_hash_ctx_t *ctx, dcp_hash_algo_t algo)
1202 {
1203     status_t status;
1204 
1205     dcp_hash_ctx_internal_t *ctxInternal;
1206     /* Align structure on DCACHE line*/
1207 #if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) && defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
1208     ctxInternal = (dcp_hash_ctx_internal_t *)(uint32_t)((uint8_t *)ctx + FSL_FEATURE_L1DCACHE_LINESIZE_BYTE);
1209 #else
1210     ctxInternal                     = (dcp_hash_ctx_internal_t *)(uint32_t)ctx;
1211 #endif
1212 
1213     /* compile time check for the correct structure size */
1214     BUILD_ASSURE(sizeof(dcp_hash_ctx_t) >= sizeof(dcp_hash_ctx_internal_t), dcp_hash_ctx_t_size);
1215     uint32_t i;
1216 
1217     status = dcp_hash_check_input_args(base, ctx, algo);
1218     if (status != kStatus_Success)
1219     {
1220         return status;
1221     }
1222 
1223     /* set algorithm in context struct for later use */
1224     ctxInternal->algo  = algo;
1225     ctxInternal->blksz = 0u;
1226 
1227     const uint32_t j = sizeof(ctxInternal->blk.w) / sizeof(ctxInternal->blk.w[0]);
1228     for (i = 0; i < j; i++)
1229     {
1230         ctxInternal->blk.w[i] = 0u;
1231     }
1232     ctxInternal->state           = kDCP_StateHashInit;
1233     ctxInternal->fullMessageSize = 0;
1234     ctxInternal->handle          = handle;
1235     return status;
1236 }
1237 
1238 /*!
1239  * brief Add data to current HASH
1240  *
1241  * Add data to current HASH. This can be called repeatedly with an arbitrary amount of data to be
1242  * hashed. The functions blocks. If it returns kStatus_Success, the running hash
1243  * has been updated (DCP has processed the input data), so the memory at ref input pointer
1244  * can be released back to system. The DCP context buffer is updated with the running hash
1245  * and with all necessary information to support possible context switch.
1246  *
1247  * param base DCP peripheral base address
1248  * param[in,out] ctx HASH context
1249  * param input Input data
1250  * param inputSize Size of input data in bytes
1251  * return Status of the hash update operation
1252  */
1253 status_t DCP_HASH_Update(DCP_Type *base, dcp_hash_ctx_t *ctx, const uint8_t *input, size_t inputSize)
1254 {
1255     bool isUpdateState;
1256     status_t status;
1257     dcp_hash_ctx_internal_t *ctxInternal;
1258     size_t blockSize;
1259 
1260     /* Align structure on DCACHE line*/
1261 #if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) && defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
1262     ctxInternal = (dcp_hash_ctx_internal_t *)(uint32_t)((uint8_t *)ctx + FSL_FEATURE_L1DCACHE_LINESIZE_BYTE);
1263 #else
1264     ctxInternal                     = (dcp_hash_ctx_internal_t *)(uint32_t)ctx;
1265 #endif
1266 
1267     if (inputSize == 0U)
1268     {
1269         return kStatus_Success;
1270     }
1271 
1272     status = dcp_hash_check_context(ctxInternal, input);
1273     if (kStatus_Success != status)
1274     {
1275         return status;
1276     }
1277 
1278     ctxInternal->fullMessageSize += inputSize;
1279     blockSize = DCP_HASH_BLOCK_SIZE;
1280     /* if we are still less than DCP_HASH_BLOCK_SIZE bytes, keep only in context */
1281     if ((ctxInternal->blksz + inputSize) <= blockSize)
1282     {
1283         (void)dcp_memcpy((&ctxInternal->blk.b[0]) + ctxInternal->blksz, input, inputSize);
1284         ctxInternal->blksz += inputSize;
1285         return status;
1286     }
1287     else
1288     {
1289         isUpdateState = ctxInternal->state == kDCP_StateHashUpdate;
1290         if (!isUpdateState)
1291         {
1292             /* start NEW hash */
1293             status = dcp_hash_engine_init(base, ctxInternal);
1294             if (status != kStatus_Success)
1295             {
1296                 return status;
1297             }
1298             ctxInternal->state = kDCP_StateHashUpdate;
1299         }
1300         else
1301         {
1302             dcp_hash_restore_running_hash(ctxInternal);
1303         }
1304     }
1305 
1306     /* process input data */
1307     status = dcp_hash_process_message_data(base, ctxInternal, input, inputSize);
1308     dcp_hash_save_running_hash(ctxInternal);
1309     return status;
1310 }
1311 
1312 /*!
1313  * brief Finalize hashing
1314  *
1315  * Outputs the final hash (computed by DCP_HASH_Update()) and erases the context.
1316  *
1317  * param[in,out] ctx Input hash context
1318  * param[out] output Output hash data
1319  * param[in,out] outputSize Optional parameter (can be passed as NULL). On function entry, it specifies the size of
1320  * output[] buffer. On function return, it stores the number of updated output bytes.
1321  * return Status of the hash finish operation
1322  */
1323 status_t DCP_HASH_Finish(DCP_Type *base, dcp_hash_ctx_t *ctx, uint8_t *output, size_t *outputSize)
1324 {
1325     size_t algOutSize = 0;
1326     status_t status;
1327     dcp_hash_ctx_internal_t *ctxInternal;
1328 
1329     /* Align structure on DCACHE line*/
1330 #if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) && defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
1331     ctxInternal = (dcp_hash_ctx_internal_t *)(uint32_t)((uint8_t *)ctx + FSL_FEATURE_L1DCACHE_LINESIZE_BYTE);
1332 #else
1333     ctxInternal                     = (dcp_hash_ctx_internal_t *)(uint32_t)ctx;
1334 #endif
1335 
1336     status = dcp_hash_check_context(ctxInternal, output);
1337 
1338     if (kStatus_Success != status)
1339     {
1340         return status;
1341     }
1342 
1343     if (ctxInternal->state == kDCP_StateHashInit)
1344     {
1345         status = dcp_hash_engine_init(base, ctxInternal);
1346         if (status != kStatus_Success)
1347         {
1348             return status;
1349         }
1350     }
1351     else
1352     {
1353         dcp_hash_restore_running_hash(ctxInternal);
1354     }
1355 
1356     size_t outSize = 0u;
1357 
1358     /* compute algorithm output length */
1359     switch (ctxInternal->algo)
1360     {
1361         case kDCP_Sha256:
1362             outSize = (uint32_t)kDCP_OutLenSha256;
1363             break;
1364         case kDCP_Sha1:
1365             outSize = (uint32_t)kDCP_OutLenSha1;
1366             break;
1367         case kDCP_Crc32:
1368             outSize = (uint32_t)kDCP_OutLenCrc32;
1369             break;
1370         default:
1371             /* All the cases have been listed above, the default clause should not be reached. */
1372             break;
1373     }
1374     algOutSize = outSize;
1375 
1376 #if defined(DCP_HASH_CAVP_COMPATIBLE)
1377     if (ctxInternal->fullMessageSize == 0U)
1378     {
1379         switch (ctxInternal->algo)
1380         {
1381             case kDCP_Sha256:
1382                 (void)dcp_memcpy(&output[0], &s_nullSha256, 32);
1383                 break;
1384             case kDCP_Sha1:
1385                 (void)dcp_memcpy(&output[0], &s_nullSha1, 20);
1386                 break;
1387             default:
1388                 /* All the cases have been listed above, the default clause should not be reached. */
1389                 break;
1390         }
1391 
1392         return kStatus_Success;
1393     }
1394 #endif /* DCP_HASH_CAVP_COMPATIBLE */
1395 
1396     /* flush message last incomplete block, if there is any, and add padding bits */
1397     status = dcp_hash_finalize(base, ctxInternal);
1398 
1399     if (outputSize != NULL)
1400     {
1401         if (algOutSize < *outputSize)
1402         {
1403             *outputSize = algOutSize;
1404         }
1405         else
1406         {
1407             algOutSize = *outputSize;
1408         }
1409     }
1410 
1411 #if defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
1412     DCACHE_InvalidateByRange((uint32_t)ctxInternal->runningHash, sizeof(ctxInternal->runningHash));
1413 #endif
1414     /* Reverse and copy result to output[] */
1415     dcp_reverse_and_copy((uint8_t *)ctxInternal->runningHash, &output[0], algOutSize);
1416 
1417     (void)memset(ctx, 0, sizeof(dcp_hash_ctx_t));
1418     return status;
1419 }
1420 
1421 /*!
1422  * brief Create HASH on given data
1423  *
1424  * Perform the full SHA or CRC32 in one function call. The function is blocking.
1425  *
1426  * param base DCP peripheral base address
1427  * param handle Handle used for the request.
1428  * param algo Underlaying algorithm to use for hash computation.
1429  * param input Input data
1430  * param inputSize Size of input data in bytes
1431  * param[out] output Output hash data
1432  * param[out] outputSize Output parameter storing the size of the output hash in bytes
1433  * return Status of the one call hash operation.
1434  */
1435 status_t DCP_HASH(DCP_Type *base,
1436                   dcp_handle_t *handle,
1437                   dcp_hash_algo_t algo,
1438                   const uint8_t *input,
1439                   size_t inputSize,
1440                   uint8_t *output,
1441                   size_t *outputSize)
1442 {
1443     dcp_hash_ctx_t hashCtx = {0};
1444     status_t status;
1445 
1446     status = DCP_HASH_Init(base, handle, &hashCtx, algo);
1447     if (status != kStatus_Success)
1448     {
1449         return status;
1450     }
1451 
1452     status = DCP_HASH_Update(base, &hashCtx, input, inputSize);
1453     if (status != kStatus_Success)
1454     {
1455         return status;
1456     }
1457 
1458     status = DCP_HASH_Finish(base, &hashCtx, output, outputSize);
1459 
1460     return status;
1461 }