/** This is the function to write data to PCAP interface * * @param WrSize: Number of 32bit words that the DMA should write to * the PCAP interface * @param WrAddr: Linear memory space from where CSUDMA will read * the data to be written to PCAP interface * * @return None * *****************************************************************************/ u32 XFsbl_WriteToPcap(u32 WrSize, u8 *WrAddr) { u32 RegVal; u32 Status = XFSBL_SUCCESS; /* * Setup the SSS, setup the PCAP to receive from DMA source */ RegVal = XFsbl_In32(CSU_CSU_SSS_CFG) & CSU_CSU_SSS_CFG_PCAP_SSS_MASK; RegVal = RegVal | (XFSBL_CSU_SSS_SRC_SRC_DMA << CSU_CSU_SSS_CFG_PCAP_SSS_SHIFT); XFsbl_Out32(CSU_CSU_SSS_CFG, RegVal); /* Setup the source DMA channel */ XCsuDma_Transfer(&CsuDma, XCSUDMA_SRC_CHANNEL, (PTRSIZE) WrAddr, WrSize, 0); /* wait for the SRC_DMA to complete and the pcap to be IDLE */ XCsuDma_WaitForDone(&CsuDma, XCSUDMA_SRC_CHANNEL); /* Acknowledge the transfer has completed */ XCsuDma_IntrClear(&CsuDma, XCSUDMA_SRC_CHANNEL, XCSUDMA_IXR_DONE_MASK); XFsbl_Printf(DEBUG_GENERAL, "DMA transfer done \r\n"); Status = XFsbl_PcapWaitForDone(); if (Status != XFSBL_SUCCESS) { goto END; } END: return Status; }
/****************************************************************************** * * This function sends data to AES engine which needs to be decrypted till the * end of the encryption block. * * @param PartitionParams is a pointer to XFsblPs_PlPartition * @param ChunkAdrs is a pointer to the data location * @param ChunkSize is the remaining chunk size * * @return * Error code on failure * XFSBL_SUCESS on success * * @note None * ******************************************************************************/ static u32 XFsbl_DecrptPl(XFsblPs_PlPartition *PartitionParams, u64 ChunkAdrs, u32 ChunkSize) { u32 Size = ChunkSize; u32 Status = XFSBL_SUCCESS; u64 SrcAddr = (u64)ChunkAdrs; XCsuDma_Configure ConfigurValues = {0}; UINTPTR NextBlkAddr = 0; u32 SssAes; u32 SssCfg; do { /* Enable byte swapping */ XCsuDma_GetConfig( PartitionParams->PlEncrypt.SecureAes->CsuDmaPtr, XCSUDMA_SRC_CHANNEL, &ConfigurValues); ConfigurValues.EndianType = 1U; XCsuDma_SetConfig( PartitionParams->PlEncrypt.SecureAes->CsuDmaPtr, XCSUDMA_SRC_CHANNEL, &ConfigurValues); /* Configure AES engine */ SssAes = XSecure_SssInputAes(XSECURE_CSU_SSS_SRC_SRC_DMA); SssCfg = SssAes | XSecure_SssInputPcap(XSECURE_CSU_SSS_SRC_AES); XSecure_SssSetup(SssCfg); /* Send whole chunk of data to AES */ if ((Size <= (PartitionParams->PlEncrypt.SecureAes->SizeofData)) && (PartitionParams->PlEncrypt.SecureAes->SizeofData != 0)) { XFsbl_DmaPlCopy( PartitionParams->PlEncrypt.SecureAes->CsuDmaPtr, (UINTPTR)SrcAddr, Size/4, 0); PartitionParams->PlEncrypt.SecureAes->SizeofData = PartitionParams->PlEncrypt.SecureAes->SizeofData - Size; Size = 0; } /* * If data to be processed is not zero * and chunk of data is greater */ else if (PartitionParams->PlEncrypt.SecureAes->SizeofData != 0) { /* First transfer whole data other than secure header */ XFsbl_DmaPlCopy( PartitionParams->PlEncrypt.SecureAes->CsuDmaPtr, (UINTPTR)SrcAddr, PartitionParams->PlEncrypt.SecureAes->SizeofData/4, 0); SrcAddr = SrcAddr + PartitionParams->PlEncrypt.SecureAes->SizeofData; Size = Size - PartitionParams->PlEncrypt.SecureAes->SizeofData; PartitionParams->PlEncrypt.SecureAes->SizeofData = 0; /* * when data to be processed is greater than * remaining data of the encrypted block * and part of GCM tag and secure header of next block * also exists with chunk, copy that portion for * proceessing along with next chunk of data */ if (Size < (XSECURE_SECURE_HDR_SIZE + XSECURE_SECURE_GCM_TAG_SIZE)) { XFsbl_CopyData(PartitionParams, PartitionParams->SecureHdr, (u8 *)(UINTPTR)SrcAddr, Size); PartitionParams->Hdr = Size; Size = 0; } } /* Wait PCAP done */ Status = XFsbl_PcapWaitForDone(); if (Status != XFSBL_SUCCESS) { return Status; } XCsuDma_GetConfig( PartitionParams->PlEncrypt.SecureAes->CsuDmaPtr, XCSUDMA_SRC_CHANNEL, &ConfigurValues); ConfigurValues.EndianType = 0U; XCsuDma_SetConfig( PartitionParams->PlEncrypt.SecureAes->CsuDmaPtr, XCSUDMA_SRC_CHANNEL, &ConfigurValues); /* Decrypting secure header and GCM tag address */ if ((PartitionParams->PlEncrypt.SecureAes->SizeofData == 0) && (Size != 0)) { Status = XFsbl_DecrypSecureHdr( PartitionParams->PlEncrypt.SecureAes, SrcAddr, 0); if (Status != XFSBL_SUCCESS) { return Status; } Size = Size - (XSECURE_SECURE_HDR_SIZE + XSECURE_SECURE_GCM_TAG_SIZE); if (Size != 0x00) { NextBlkAddr = SrcAddr + XSECURE_SECURE_HDR_SIZE + XSECURE_SECURE_GCM_TAG_SIZE; } /* * This means we are done with Secure header and Block 0 * And now we can change the AES key source to KUP. */ PartitionParams->PlEncrypt.SecureAes->KeySel = XSECURE_CSU_AES_KEY_SRC_KUP; XSecure_AesKeySelNLoad( PartitionParams->PlEncrypt.SecureAes); Status = XFsbl_DecrptSetUpNextBlk(PartitionParams, NextBlkAddr, Size); if (Status != XFSBL_SUCCESS) { return Status; } if ((NextBlkAddr != 0x00U) && (PartitionParams->PlEncrypt.SecureAes->SizeofData != 0)) { SrcAddr = NextBlkAddr; } else { break; } } } while (Size != 0x00); return Status; }
/****************************************************************************** * * This function re-authenticates the each chunk of the block and compares * with the stored hash and sends the data AES engine if encryption exists * and to PCAP directly in encryption is not existing. * * @param PartitionParams is a pointer to XFsblPs_PlPartition * @param Address start address of the authentication block. * @param BlockLen size of the authentication block. * @param NoOfChunks holds the no of chunks for the provided block * * @return * Error code on failure * XFSBL_SUCESS on success * * @note None. * ******************************************************************************/ static u32 XFsbl_ReAuthenticationBlock(XFsblPs_PlPartition *PartitionParams, UINTPTR Address, u32 BlockLen, u32 NoOfChunks) { u32 Status; u32 Index; u32 Len = PartitionParams->ChunkSize;; UINTPTR Offset; u8 ChunksHash[48]; XSecure_Sha3 SecureSha3; u32 HashDataLen = BlockLen; u8 *HashStored = PartitionParams->PlAuth.HashsOfChunks; (void)memset(ChunksHash,0U,sizeof(ChunksHash)); Status = XSecure_Sha3Initialize(&SecureSha3, PartitionParams->CsuDmaPtr); if (Status != XFSBL_SUCCESS) { return Status; } XSecure_Sha3Start(&SecureSha3); /* calculating hashs for all chunks copies to AES/PCAP */ for (Index = 0; Index < NoOfChunks; Index++) { /* Last chunk */ if (Index == NoOfChunks -1) { Len = HashDataLen; } Offset = (UINTPTR)Address + (u64)(PartitionParams->ChunkSize * Index); /* Copy from DDR or flash to Buffer */ Status = XFsbl_CopyData(PartitionParams, PartitionParams->ChunkBuffer, (u8 *)Offset, Len); if (Status != XFSBL_SUCCESS) { return Status; } /* Calculating hash for each chunk */ XSecure_Sha3Update(&SecureSha3, PartitionParams->ChunkBuffer, Len); XSecure_Sha3_ReadHash(&SecureSha3, (u8 *)ChunksHash); /* Comparing with stored Hashs */ Status = XFsbl_CompareHashs(HashStored, ChunksHash, PartitionParams->PlAuth.AuthType); if (Status != XFSBL_SUCCESS) { XFsbl_Printf(DEBUG_GENERAL, "XFsbl_PlReAuth:" " XFSBL_ERROR_CHUNK_HASH_COMPARISON\r\n"); XFsbl_PrintArray(DEBUG_INFO, HashStored, PartitionParams->PlAuth.AuthType, "Stored Chunk Hash"); XFsbl_PrintArray(DEBUG_INFO, ChunksHash, PartitionParams->PlAuth.AuthType, "Calculated chunk Hash"); Status = XFSBL_ERROR_CHUNK_HASH_COMPARISON; goto END; } /* Remaining block size will be in HashDataLen */ HashDataLen = HashDataLen - PartitionParams->ChunkSize; if (Index+1 <= NoOfChunks - 1) { HashStored = HashStored + PartitionParams->PlAuth.AuthType; } /* If image is not encrypted */ if (PartitionParams->IsEncrypted == FALSE) { /* Configure Secure stream swith to PCAP */ XFsbl_Out32(CSU_CSU_SSS_CFG, XFSBL_CSU_SSS_SRC_SRC_DMA << CSU_CSU_SSS_CFG_PCAP_SSS_SHIFT); /* Copy bitstream to PCAP */ XFsbl_DmaPlCopy(PartitionParams->CsuDmaPtr, (UINTPTR)PartitionParams->ChunkBuffer, Len/4, 0); Status = XFsbl_PcapWaitForDone(); if (Status != XFSBL_SUCCESS) { goto END; } } /* If image is encrypted */ else { Status = XFsbl_DecrptPlChunks(PartitionParams, (UINTPTR)PartitionParams->ChunkBuffer, Len); if (Status != XFSBL_SUCCESS) { goto END; } } } END: return Status; }