/****************************************************************************** * Copyright (C) 2023 Maxim Integrated Products, Inc., All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * * Except as contained in this notice, the name of Maxim Integrated * Products, Inc. shall not be used except as stated in the Maxim Integrated * Products, Inc. Branding Policy. * * The mere transfer of this software does not imply any licenses * of trade secrets, proprietary technology, copyrights, patents, * trademarks, maskwork rights, or any other form of intellectual * property whatsoever. Maxim Integrated Products, Inc. retains all * ownership rights. * ******************************************************************************/ #include <stdlib.h> #include <string.h> #include "mxc_sys.h" #include "mxc_device.h" #include "mxc_errors.h" #include "mxc_assert.h" #include "mxc_lock.h" #include "dma.h" #include "aes_regs.h" #include "aeskeys_regs.h" #include "aes_revb.h" #include "trng_revb.h" /* **** Variable Declaration **** */ typedef struct { uint8_t enc; uint8_t channelRX; uint8_t channelTX; uint32_t remain; uint32_t *inputText; uint32_t *outputText; } mxc_aes_revb_dma_req_t; static mxc_aes_revb_dma_req_t dma_state; #define SWAP_BYTES(x) \ ((((x) >> 24) & 0x000000FF) | (((x) >> 8) & 0x0000FF00) | (((x) << 8) & 0x00FF0000) | \ (((x) << 24) & 0xFF000000)) /* Prevent GCC from optimimzing this function to memcpy */ static void __attribute__((optimize("no-tree-loop-distribute-patterns"))) memcpy32r(uint32_t *dst, const uint32_t *src, unsigned int len) { uint32_t *dstr = dst + (len / 4) - 1; while (len) { *dstr = SWAP_BYTES(*src); dstr--; src++; len -= 4; } } int MXC_AES_RevB_Init(mxc_aes_revb_regs_t *aes) { aes->ctrl = 0x00; while (MXC_AES_RevB_IsBusy(aes) != E_NO_ERROR) {} aes->ctrl |= MXC_F_AES_REVB_CTRL_EN; return E_NO_ERROR; } int MXC_AES_RevB_Shutdown(mxc_aes_revb_regs_t *aes) { MXC_AES_RevB_FlushInputFIFO(aes); MXC_AES_RevB_FlushOutputFIFO(aes); while (MXC_AES_RevB_IsBusy(aes) != E_NO_ERROR) {} aes->ctrl = 0x00; return E_NO_ERROR; } int MXC_AES_RevB_IsBusy(mxc_aes_revb_regs_t *aes) { if (aes->status & MXC_F_AES_REVB_STATUS_BUSY) { return E_BUSY; } return E_NO_ERROR; } void MXC_AES_RevB_SetKeySize(mxc_aes_revb_regs_t *aes, mxc_aes_revb_keys_t key) { while (MXC_AES_IsBusy() != E_NO_ERROR) {} aes->ctrl |= key; } mxc_aes_keys_t MXC_AES_RevB_GetKeySize(mxc_aes_revb_regs_t *aes) { return (aes->ctrl & MXC_F_AES_REVB_CTRL_KEY_SIZE); } void MXC_AES_RevB_FlushInputFIFO(mxc_aes_revb_regs_t *aes) { while (MXC_AES_IsBusy() != E_NO_ERROR) {} aes->ctrl |= MXC_F_AES_REVB_CTRL_INPUT_FLUSH; } void MXC_AES_RevB_FlushOutputFIFO(mxc_aes_revb_regs_t *aes) { while (MXC_AES_IsBusy() != E_NO_ERROR) {} aes->ctrl |= MXC_F_AES_REVB_CTRL_OUTPUT_FLUSH; } void MXC_AES_RevB_Start(mxc_aes_revb_regs_t *aes) { while (MXC_AES_IsBusy() != E_NO_ERROR) {} aes->ctrl |= MXC_F_AES_REVB_CTRL_START; } void MXC_AES_RevB_EnableInt(mxc_aes_revb_regs_t *aes, uint32_t interrupt) { aes->inten |= (interrupt & (MXC_F_AES_REVB_INTEN_DONE | MXC_F_AES_REVB_INTEN_KEY_CHANGE | MXC_F_AES_REVB_INTEN_KEY_ZERO | MXC_F_AES_REVB_INTEN_OV)); } void MXC_AES_RevB_DisableInt(mxc_aes_revb_regs_t *aes, uint32_t interrupt) { aes->inten &= ~(interrupt & (MXC_F_AES_REVB_INTEN_DONE | MXC_F_AES_REVB_INTEN_KEY_CHANGE | MXC_F_AES_REVB_INTEN_KEY_ZERO | MXC_F_AES_REVB_INTEN_OV)); } uint32_t MXC_AES_RevB_GetFlags(mxc_aes_revb_regs_t *aes) { return aes->intfl; } void MXC_AES_RevB_ClearFlags(mxc_aes_revb_regs_t *aes, uint32_t flags) { aes->intfl = (flags & (MXC_F_AES_REVB_INTFL_DONE | MXC_F_AES_REVB_INTFL_KEY_CHANGE | MXC_F_AES_REVB_INTFL_KEY_ZERO | MXC_F_AES_REVB_INTFL_OV)); } int MXC_AES_RevB_Generic(mxc_aes_revb_regs_t *aes, mxc_aes_revb_req_t *req) { int i; int remain; if (req == NULL) { return E_NULL_PTR; } if (req->inputData == NULL || req->resultData == NULL) { return E_NULL_PTR; } if (req->length == 0) { return E_BAD_PARAM; } remain = req->length; MXC_AES_RevB_FlushInputFIFO(aes); MXC_AES_RevB_FlushOutputFIFO(aes); MXC_AES_RevB_SetKeySize(aes, req->keySize); while (MXC_AES_IsBusy() != E_NO_ERROR) {} MXC_SETFIELD(aes->ctrl, MXC_F_AES_REVB_CTRL_TYPE, req->encryption << MXC_F_AES_REVB_CTRL_TYPE_POS); while (remain / 4) { for (i = 0; i < 4; i++) { aes->fifo = SWAP_BYTES(req->inputData[3 - i]); } req->inputData += 4; while (!(aes->intfl & MXC_F_AES_REVB_INTFL_DONE)) {} aes->intfl |= MXC_F_AES_REVB_INTFL_DONE; for (i = 0; i < 4; i++) { uint32_t tmp = aes->fifo; req->resultData[3 - i] = SWAP_BYTES(tmp); } req->resultData += 4; remain -= 4; } if (remain % 4) { for (i = 0; i < remain; i++) { aes->fifo = SWAP_BYTES(req->inputData[remain - 1 - i]); } req->inputData += remain; // Pad last block with 0's for (i = remain; i < 4; i++) { aes->fifo = 0; } while (!(aes->intfl & MXC_F_AES_REVB_INTFL_DONE)) {} aes->intfl |= MXC_F_AES_REVB_INTFL_DONE; for (i = 0; i < 4; i++) { uint32_t tmp = aes->fifo; req->resultData[3 - i] = SWAP_BYTES(tmp); } req->resultData += 4; } return E_NO_ERROR; } int MXC_AES_RevB_Encrypt(mxc_aes_revb_regs_t *aes, mxc_aes_revb_req_t *req) { return MXC_AES_RevB_Generic(aes, req); } int MXC_AES_RevB_Decrypt(mxc_aes_revb_regs_t *aes, mxc_aes_revb_req_t *req) { return MXC_AES_RevB_Generic(aes, req); } int MXC_AES_RevB_TXDMAConfig(void *src_addr, int len) { uint8_t channel; mxc_dma_config_t config; mxc_dma_srcdst_t srcdst; if (src_addr == NULL) { return E_NULL_PTR; } if (len == 0) { return E_BAD_PARAM; } MXC_DMA_Init(); channel = MXC_DMA_AcquireChannel(); dma_state.channelTX = channel; config.reqsel = MXC_DMA_REQUEST_AESTX; config.ch = channel; config.srcwd = MXC_DMA_WIDTH_WORD; config.dstwd = MXC_DMA_WIDTH_WORD; config.srcinc_en = 1; config.dstinc_en = 0; srcdst.ch = channel; srcdst.source = src_addr; if (dma_state.enc == 1) { srcdst.len = 4; } else if (len > 4) { srcdst.len = 4; } else { srcdst.len = len; } MXC_DMA_ConfigChannel(config, srcdst); MXC_DMA_SetCallback(channel, MXC_AES_RevB_DMACallback); MXC_DMA_EnableInt(channel); MXC_DMA_Start(channel); //MXC_DMA->ch[channel].ctrl |= MXC_F_DMA_CTRL_CTZ_IE; MXC_DMA_SetChannelInterruptEn(channel, 0, 1); return E_NO_ERROR; } int MXC_AES_RevB_RXDMAConfig(void *dest_addr, int len) { if (dest_addr == NULL) { return E_NULL_PTR; } if (len == 0) { return E_BAD_PARAM; } uint8_t channel; mxc_dma_config_t config; mxc_dma_srcdst_t srcdst; MXC_DMA_Init(); channel = MXC_DMA_AcquireChannel(); dma_state.channelRX = channel; config.reqsel = MXC_DMA_REQUEST_AESRX; config.ch = channel; config.srcwd = MXC_DMA_WIDTH_WORD; config.dstwd = MXC_DMA_WIDTH_WORD; config.srcinc_en = 0; config.dstinc_en = 1; srcdst.ch = channel; srcdst.dest = dest_addr; if (dma_state.enc == 0) { srcdst.len = 4; } else if (len > 4) { srcdst.len = 4; } else { srcdst.len = len; } MXC_DMA_ConfigChannel(config, srcdst); MXC_DMA_SetCallback(channel, MXC_AES_RevB_DMACallback); MXC_DMA_EnableInt(channel); MXC_DMA_Start(channel); //MXC_DMA->ch[channel].ctrl |= MXC_F_DMA_CTRL_CTZ_IE; MXC_DMA_SetChannelInterruptEn(channel, 0, 1); return E_NO_ERROR; } int MXC_AES_RevB_GenericAsync(mxc_aes_revb_regs_t *aes, mxc_aes_revb_req_t *req, uint8_t enc) { if (req == NULL) { return E_NULL_PTR; } if (req->inputData == NULL || req->resultData == NULL) { return E_NULL_PTR; } if (req->length == 0) { return E_BAD_PARAM; } MXC_AES_RevB_FlushInputFIFO(aes); MXC_AES_RevB_FlushOutputFIFO(aes); MXC_AES_RevB_SetKeySize(aes, req->keySize); MXC_AES_IsBusy(); MXC_SETFIELD(aes->ctrl, MXC_F_AES_REVB_CTRL_TYPE, req->encryption << MXC_F_AES_REVB_CTRL_TYPE_POS); dma_state.enc = enc; dma_state.remain = req->length; dma_state.inputText = req->inputData; dma_state.outputText = req->resultData; aes->ctrl |= MXC_F_AES_REVB_CTRL_DMA_RX_EN; //Enable AES DMA aes->ctrl |= MXC_F_AES_REVB_CTRL_DMA_TX_EN; //Enable AES DMA if (MXC_AES_RevB_TXDMAConfig(dma_state.inputText, dma_state.remain) != E_NO_ERROR) { return E_BAD_PARAM; } return E_NO_ERROR; } int MXC_AES_RevB_EncryptAsync(mxc_aes_revb_regs_t *aes, mxc_aes_revb_req_t *req) { return MXC_AES_RevB_GenericAsync(aes, req, 0); } int MXC_AES_RevB_DecryptAsync(mxc_aes_revb_regs_t *aes, mxc_aes_revb_req_t *req) { return MXC_AES_RevB_GenericAsync(aes, req, 1); } void MXC_AES_RevB_DMACallback(int ch, int error) { if (error != E_NO_ERROR) { } else { if (dma_state.channelTX == ch) { MXC_DMA_ReleaseChannel(dma_state.channelTX); if (dma_state.remain < 4) { MXC_AES_Start(); } MXC_AES_RevB_RXDMAConfig(dma_state.outputText, dma_state.remain); } else if (dma_state.channelRX == ch) { if (dma_state.remain > 4) { dma_state.remain -= 4; } else if (dma_state.remain > 0) { dma_state.remain = 0; } MXC_DMA_ReleaseChannel(dma_state.channelRX); if (dma_state.remain > 0) { MXC_AES_RevB_TXDMAConfig(dma_state.inputText, dma_state.remain); } } } } void MXC_AES_RevB_SetExtKey(mxc_aeskeys_revb_regs_t *aeskeys, const void *key, mxc_aes_keys_t len) { int numBytes; if (len == MXC_AES_128BITS) { numBytes = 16; } else if (len == MXC_AES_192BITS) { numBytes = 24; } else { numBytes = 32; } /* TODO: Figure out if this is the correct byte ordering */ memcpy32r((void *)&(aeskeys->key0), key, numBytes); }