diff options
author | Gary King <gking@nvidia.com> | 2010-06-07 09:46:21 -0700 |
---|---|---|
committer | Gary King <gking@nvidia.com> | 2010-06-07 12:35:55 -0700 |
commit | 4dcd7a1c7fc8a02c93f9bdf954dda9eab6cad44f (patch) | |
tree | f27737f0bd8b03a11902e0ce7dc8ac9627362723 /arch/arm/mach-tegra/nvddk | |
parent | 5ce1e0a1a36b2034708366a47a88fce38ef4a252 (diff) |
[ARM/tegra] add cryptographic engine (AES) driver
Supports CBC & ECB encryption/decryption, AnsiX9.31 RNG, SSK/SBK/User Key,
fine-grain uid/gid access control and ability for privileged user to reset
the engine. A device node (/dev/nvaes) is provided to enable access from
user-land.
based on work done by David Le Tacon (dletacon@nvidia.com)
Change-Id: I1a9c29b964ca15e6fec70389c2000306ef604086
Reviewed-on: http://git-master/r/2216
Reviewed-by: David Le Tacon <dletacon@nvidia.com>
Reviewed-by: Gary King <gking@nvidia.com>
Tested-by: Gary King <gking@nvidia.com>
Diffstat (limited to 'arch/arm/mach-tegra/nvddk')
-rw-r--r-- | arch/arm/mach-tegra/nvddk/Makefile | 8 | ||||
-rw-r--r-- | arch/arm/mach-tegra/nvddk/NvDdkAES_Dispatch.c | 92 | ||||
-rw-r--r-- | arch/arm/mach-tegra/nvddk/nvddk_aes.c | 2669 | ||||
-rw-r--r-- | arch/arm/mach-tegra/nvddk/nvddk_aes_core_ap20.c | 617 | ||||
-rw-r--r-- | arch/arm/mach-tegra/nvddk/nvddk_aes_core_ap20.h | 229 | ||||
-rw-r--r-- | arch/arm/mach-tegra/nvddk/nvddk_aes_dispatch.c | 715 | ||||
-rw-r--r-- | arch/arm/mach-tegra/nvddk/nvddk_aes_hw.h | 154 | ||||
-rw-r--r-- | arch/arm/mach-tegra/nvddk/nvddk_aes_intf_ap20.c | 701 | ||||
-rw-r--r-- | arch/arm/mach-tegra/nvddk/nvddk_aes_priv.h | 436 |
9 files changed, 5620 insertions, 1 deletions
diff --git a/arch/arm/mach-tegra/nvddk/Makefile b/arch/arm/mach-tegra/nvddk/Makefile index 17d78897e5c6..e6cd0acf9f15 100644 --- a/arch/arm/mach-tegra/nvddk/Makefile +++ b/arch/arm/mach-tegra/nvddk/Makefile @@ -10,4 +10,10 @@ obj-y += nvddk_usbphy.o obj-y += nvddk_usbphy_ap20.o endif -obj-$(CONFIG_TEGRA_FUSE) += nvddk_fuse_ap20.o
\ No newline at end of file +obj-$(CONFIG_TEGRA_FUSE) += nvddk_fuse_ap20.o + +obj-$(CONFIG_TEGRA_AES) += nvddk_aes_intf_ap20.o +obj-$(CONFIG_TEGRA_AES_USER) += NvDdkAES_Dispatch.o +obj-$(CONFIG_TEGRA_AES) += nvddk_aes_core_ap20.o +obj-$(CONFIG_TEGRA_AES) += nvddk_aes.o +obj-$(CONFIG_TEGRA_AES_USER) += nvddk_aes_dispatch.o diff --git a/arch/arm/mach-tegra/nvddk/NvDdkAES_Dispatch.c b/arch/arm/mach-tegra/nvddk/NvDdkAES_Dispatch.c new file mode 100644 index 000000000000..fe98e7028f5d --- /dev/null +++ b/arch/arm/mach-tegra/nvddk/NvDdkAES_Dispatch.c @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2007-2009 NVIDIA Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of the NVIDIA Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "nvcommon.h" +#include "nvos.h" +#include "nvassert.h" +#include "nvidlcmd.h" +#include "nvreftrack.h" +#include "nvddk_aes.h" +NvError nvddk_aes_Dispatch( NvU32 function, void *InBuffer, NvU32 InSize, void *OutBuffer, NvU32 OutSize, NvDispatchCtx* Ctx ); + +// NvDdkAesCommon Package +typedef enum +{ + NvDdkAesCommon_Invalid = 0, + NvDdkAesCommon_nvddk_aes_common, + NvDdkAesCommon_Num, + NvDdkAesCommon_Force32 = 0x7FFFFFFF, +} NvDdkAesCommon; + +// NvDdkAes Package +typedef enum +{ + NvDdkAes_Invalid = 0, + NvDdkAes_nvddk_aes, + NvDdkAes_Num, + NvDdkAes_Force32 = 0x7FFFFFFF, +} NvDdkAes; + +typedef NvError (* NvIdlDispatchFunc)( NvU32 function, void *InBuffer, NvU32 InSize, void *OutBuffer, NvU32 OutSize, NvDispatchCtx* Ctx ); + +typedef struct NvIdlDispatchTableRec +{ + NvU32 PackageId; + NvIdlDispatchFunc DispFunc; +} NvIdlDispatchTable; + +static NvIdlDispatchTable gs_DispatchTable[] = +{ + { NvDdkAes_nvddk_aes, nvddk_aes_Dispatch }, + { 0, 0 }, +}; + +NvError NvDdkAes_Dispatch( void *InBuffer, NvU32 InSize, void *OutBuffer, NvU32 OutSize, NvDispatchCtx* Ctx ) +{ + NvU32 packid_; + NvU32 funcid_; + NvIdlDispatchTable *table_; + + NV_ASSERT( InBuffer ); + NV_ASSERT( OutBuffer ); + + packid_ = ((NvU32 *)InBuffer)[0]; + funcid_ = ((NvU32 *)InBuffer)[1]; + table_ = gs_DispatchTable; + + if ( packid_-1 >= NV_ARRAY_SIZE(gs_DispatchTable) || + !table_[packid_ - 1].DispFunc ) + return NvError_IoctlFailed; + + return table_[packid_ - 1].DispFunc( funcid_, InBuffer, InSize, + OutBuffer, OutSize, Ctx ); +} diff --git a/arch/arm/mach-tegra/nvddk/nvddk_aes.c b/arch/arm/mach-tegra/nvddk/nvddk_aes.c new file mode 100644 index 000000000000..76736c7325a8 --- /dev/null +++ b/arch/arm/mach-tegra/nvddk/nvddk_aes.c @@ -0,0 +1,2669 @@ +/* + * Copyright (c) 2007-2009 NVIDIA Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of the NVIDIA Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "nvos.h" +#include "nvassert.h" +#include "nvrm_power.h" +#include "nvrm_hardware_access.h" +#include "nvrm_module.h" +#include "nvrm_xpc.h" +#if NV_OAL +#include "nvbl_virtual.h" +#endif +#include "nvddk_aes.h" +#include "nvddk_aes_priv.h" + +#include <linux/interrupt.h> +#include <linux/proc_fs.h> + +// RFC3394 key wrap block size is 64 bites which is equal to 8 bytes +#define AES_RFC_3394_KEY_WRAP_BLOCK_SIZE_BYTES 8 + +// Number of RFC3394 key wrap blocks for 128 bit key +#define AES_RFC_3394_NUM_OF_BLOCKS_FOR_128BIT_KEY 2 + +static void AesCoreRequestHwAccess(void); +static void AesCoreReleaseHwAccess(void); +static void AesCoreDeAllocateRmMemory(AesHwContext *const pAesHwCtxt); +static void AesCoreFreeUpEngine(AesCoreEngine *const pAesCoreEngine); +static void AesCorePowerUp(const AesCoreEngine *const pAesCoreEngine); +static void AesCorePowerDown(const AesCoreEngine *const pAesCoreEngine); +static void AesCoreDeInitializeEngineSpace(const AesHwContext *const pAesHwCtxt); + +static NvError AesCoreAllocateRmMemory(AesHwContext *const pAesHwCtxt); +static NvError AesCoreLoadSskToSecureScratchAndLock(const AesHwContext *const pAesHwCtxt, const NvU8 *const pKey); +static NvError AesCoreDfsBusyHint(const NvRmDeviceHandle hRmDevice, const NvU32 PowerClientId, const NvBool IsDfsOn); +static NvError AesCoreInitializeEngineSpace(const NvRmDeviceHandle hRmDevice, AesHwContext *const pAesHwCtxt); +static NvError AesCoreInitEngine(const NvRmDeviceHandle hRmDevice); +static NvError AesCoreGetCapabilities(const NvRmDeviceHandle hRmDevice, AesHwCapabilities **const ppCaps); +static NvError AesCoreClearUserKey(const NvDdkAes *const pAesClient); +static NvError +AesCoreWrapKey( + const NvDdkAes *const pAesClient, + const NvU8 *const pOrgKey, + const NvU8 *const pOrgIv, + NvU8 *const pWrappedKey, + NvU8 *const pWrappedIv); +static NvError +AesCoreUnWrapKey( + const NvDdkAes *const pAesClient, + const NvU8 *const pWrappedKey, + const NvU8 *const pWrappedIv, + NvU8 *const pOrgKey, + NvU8 *const pOrgIv); +static NvError +AesCoreGetFreeSlot( + const AesCoreEngine *const pAesCoreEngine, + AesHwEngine *const pEngine, + AesHwKeySlot *const pKeySlot); +static NvError +AesCoreSetKey( + const NvDdkAesKeyType KeyType, + const NvBool IsDedicatedSlot, + const NvU8 *const pKeyData, + NvDdkAes *const pAesClient); +static NvError +AesCoreProcessBuffer( + const NvU32 SkipOffset, + const NvU32 SrcBufferSize, + const NvU32 DestBufferSize, + NvDdkAes *const pAesClient, + const NvU8 *pSrcBuffer, + NvU8 *pDestBuffer); +static NvError +AesCoreEcbProcessBuffer( + const NvDdkAes *const pAesClient, + const NvU8 *const pInputBuffer, + const NvU32 BufSize, + const NvBool IsEncrypt, + NvU8 *const pOutputBuffer); + +static NvBool +AesCoreIsUserKeyCleared( + const AesHwEngine Engine, + const AesHwKeySlot KeySlot, + AesHwContext *const pAesHwCtxt); +static NvBool +AesCoreIsSbkCleared( + const AesHwEngine Engine, + const AesHwKeySlot EncryptSlot, + const AesHwKeySlot DecryptSlot, + AesHwContext *const pAesHwCtxt); +static NvBool +AesCoreIsSskLocked( + const AesHwEngine Engine, + const AesHwKeySlot EncryptSlot, + const AesHwKeySlot DecryptSlot, + AesHwContext *const pAesHwCtxt); + +static AesCoreEngine *gs_pAesCoreEngine = NULL; +static NvOsMutexHandle gs_hAesCoreEngineMutex = {0}; + +// Original IV of size 8 byte which is used in RFC 3394 key wrap algorithm +static NvU8 gs_OriginalIV[AES_RFC_IV_LENGTH_BYTES] = +{ + 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6 +}; + +extern NvRmDeviceHandle s_hRmGlobal; + +#define NVDDK_AES_CHECK_INPUT_PARAMS(parm) \ + do \ + { \ + if ((!pAesClient) || (!parm)) \ + return NvError_BadParameter; \ + } while (0) + +#define NVDDK_AES_CHECK_ROOT_PERMISSION \ + do \ + { \ + if ((0 != pAesClient->uid) || (0 != pAesClient->gid)) \ + return NvError_AesPermissionDenied; \ + } while (0) + +#define NVDDK_AES_CHECK_USER_IDENTITY \ + do \ + { \ + if ((pAesClient->uid != current->cred->uid) || (pAesClient->gid != current->cred->gid)) \ + return NvError_AesPermissionDenied; \ + } while (0) + +#define NVDDK_AES_CHECK_INTERFACE(ctxt, engine) \ + do \ + { \ + NV_ASSERT(ctxt); \ + NV_ASSERT(ctxt->ppEngineCaps); \ + NV_ASSERT(ctxt->ppEngineCaps[engine]); \ + NV_ASSERT(ctxt->ppEngineCaps[engine]->pAesInterf); \ + } while (0) + +#define NVDDK_AES_CHECK_INTERFACE_FUNC(ctxt, engine, func) \ + do \ + { \ + NV_ASSERT(ctxt->ppEngineCaps[engine]->pAesInterf->func); \ + } while (0) + +NvError NvDdkAesOpen(NvU32 InstanceId, NvDdkAesHandle *phAes) +{ + NvError e = NvSuccess; + NvDdkAes *pAes = NULL; + NvOsMutexHandle hMutex = NULL; + + if (!phAes) + return NvError_BadParameter; + + // Create mutex (if not already done) + if (NULL == gs_hAesCoreEngineMutex) + { + e = NvOsMutexCreate(&hMutex); + if (NvSuccess != e) + return e; + if (0 != NvOsAtomicCompareExchange32((NvS32*)&gs_hAesCoreEngineMutex, 0, (NvS32)hMutex)) + NvOsMutexDestroy(hMutex); + } + + NvOsMutexLock(gs_hAesCoreEngineMutex); + + // Create client record + pAes = NvOsAlloc(sizeof(NvDdkAes)); + if (!pAes) + { + e = NvError_InsufficientMemory; + goto fail; + } + NvOsMemset(pAes, 0, sizeof(NvDdkAes)); + + if (NULL == gs_pAesCoreEngine) + { + // Init engine + NV_CHECK_ERROR_CLEANUP(AesCoreInitEngine(s_hRmGlobal)); + // Power up + AesCorePowerUp(gs_pAesCoreEngine); + } + + // Add client + gs_pAesCoreEngine->OpenCount++; + + pAes->pAesCoreEngine = gs_pAesCoreEngine; + + // Store uid & gid + pAes->uid = current->cred->uid; + pAes->gid = current->cred->gid; + + *phAes = pAes; + NvOsMutexUnlock(gs_hAesCoreEngineMutex); + return NvSuccess; + +fail: + NvDdkAesClose(pAes); + NvOsMutexUnlock(gs_hAesCoreEngineMutex); + return e; +} + +void NvDdkAesClose(NvDdkAesHandle hAes) +{ + NvDdkAes *pAesClient = (NvDdkAes *)hAes; + + if (!hAes) + return; + + if ((pAesClient->uid != current->cred->uid) || (pAesClient->gid != current->cred->gid)) + return; + + if (pAesClient->pAesCoreEngine) + { + NvOsMutexLock(gs_hAesCoreEngineMutex); + + // Check if client is using USER key with dedicated slot then free the associated client slot + if ((NV_TRUE == pAesClient->IsDedicatedSlot) && + (NvDdkAesKeyType_UserSpecified == pAesClient->KeyType)) + { + // Client is using USER key with dedicated slot. So + // clear the key in hardware slot and free the associated client slot + if (!AesCoreClearUserKey(pAesClient)) + { + NV_ASSERT(!"Failed to clear User Key"); + } + pAesClient->pAesCoreEngine->IsKeySlotUsed[pAesClient->Engine][pAesClient->KeySlot] = NV_FALSE; + } + + // Free up engine if no other clients + if (pAesClient->pAesCoreEngine->OpenCount) + { + // Decrement the Open count + pAesClient->pAesCoreEngine->OpenCount--; + + if (0 == pAesClient->pAesCoreEngine->OpenCount) + { + // Power down + AesCorePowerDown(pAesClient->pAesCoreEngine); + + // Free up resources + AesCoreFreeUpEngine(pAesClient->pAesCoreEngine); + + NvOsFree(gs_pAesCoreEngine); + gs_pAesCoreEngine = NULL; + } + } + NvOsMutexUnlock(gs_hAesCoreEngineMutex); + } + + NvOsMemset(pAesClient, 0, sizeof(NvDdkAes)); + NvOsFree(pAesClient); +} + +NvError NvDdkAesSelectKey(NvDdkAesHandle hAes, const NvDdkAesKeyInfo *pKeyInfo) +{ + NvDdkAes *pAesClient = (NvDdkAes*)hAes; + + NVDDK_AES_CHECK_INPUT_PARAMS(pKeyInfo); + + NVDDK_AES_CHECK_USER_IDENTITY; + + switch (pKeyInfo->KeyLength) + { + case NvDdkAesKeySize_128Bit: + return AesCoreSetKey( + pKeyInfo->KeyType, + pKeyInfo->IsDedicatedKeySlot, + pKeyInfo->Key, + pAesClient); + break; + case NvDdkAesKeySize_192Bit: + case NvDdkAesKeySize_256Bit: + default: + return NvError_NotSupported; + } +} + +NvError NvDdkAesSelectOperation(NvDdkAesHandle hAes, const NvDdkAesOperation *pOperation) +{ + NvDdkAes *pAesClient = (NvDdkAes*)hAes; + + NVDDK_AES_CHECK_INPUT_PARAMS(pOperation); + + NVDDK_AES_CHECK_USER_IDENTITY; + + switch (pOperation->OpMode) + { + case NvDdkAesOperationalMode_Cbc: + case NvDdkAesOperationalMode_Ecb: + pAesClient->IsEncryption = pOperation->IsEncrypt; + break; + case NvDdkAesOperationalMode_AnsiX931: + pAesClient->IsEncryption = NV_TRUE; + break; + default: + return NvError_NotSupported; + } + + pAesClient->OpMode = pOperation->OpMode; + return NvSuccess; +} + +NvError NvDdkAesSetInitialVector(NvDdkAesHandle hAes, const NvU8 *pInitialVector, NvU32 VectorSize) +{ + NvDdkAes *pAesClient = (NvDdkAes*)hAes; + + NVDDK_AES_CHECK_INPUT_PARAMS(pInitialVector); + + NVDDK_AES_CHECK_USER_IDENTITY; + + if (NvDdkAesOperationalMode_Ecb == pAesClient->OpMode) + return NvError_NotSupported; + + if (VectorSize < NvDdkAesConst_IVLengthBytes) + return NvError_BadParameter; + + // Set the IV and store it with client + NvOsMemcpy(pAesClient->Iv, pInitialVector, NvDdkAesConst_IVLengthBytes); + + return NvSuccess; +} + +NvError NvDdkAesGetInitialVector(NvDdkAesHandle hAes, NvU32 VectorSize, NvU8 *pInitialVector) +{ + NvDdkAes *pAesClient = (NvDdkAes*)hAes; + + NVDDK_AES_CHECK_INPUT_PARAMS(pInitialVector); + + NVDDK_AES_CHECK_USER_IDENTITY; + + if (VectorSize < NvDdkAesConst_IVLengthBytes) + return NvError_BadParameter; + + NvOsMemcpy(pInitialVector, pAesClient->Iv, NvDdkAesConst_IVLengthBytes); + + return NvSuccess; +} + +NvError +NvDdkAesProcessBuffer( + NvDdkAesHandle hAes, + NvU32 SrcBufferSize, + NvU32 DestBufferSize, + const NvU8 *pSrcBuffer, + NvU8 *pDestBuffer) +{ + if ((!hAes) || (!pSrcBuffer) || (!pDestBuffer)) + return NvError_BadParameter; + + return AesCoreProcessBuffer(0, SrcBufferSize, DestBufferSize, (NvDdkAes*)hAes, pSrcBuffer, pDestBuffer); +} + +NvError NvDdkAesClearSecureBootKey(NvDdkAesHandle hAes) +{ + NvError e = NvSuccess; + NvDdkAes *pAesClient = (NvDdkAes*)hAes; + AesHwContext *pAesHwCtxt = NULL; + AesHwEngine Engine; + + if (!hAes) + return NvError_BadParameter; + + NVDDK_AES_CHECK_USER_IDENTITY; + + NVDDK_AES_CHECK_ROOT_PERMISSION; + + NvOsMutexLock(gs_hAesCoreEngineMutex); + + // Get the AES H/W context + NV_ASSERT(pAesClient->pAesCoreEngine); + pAesHwCtxt = &pAesClient->pAesCoreEngine->AesHwCtxt; + + for (Engine = AesHwEngine_A; Engine < AesHwEngine_Num; Engine++) + { + AesHwEngine SbkEngine = pAesClient->pAesCoreEngine->SbkEngine[Engine]; + AesHwKeySlot DecryptSlot = pAesClient->pAesCoreEngine->SbkDecryptSlot; + AesHwKeySlot EncryptSlot = pAesClient->pAesCoreEngine->SbkEncryptSlot; + + if (SbkEngine < AesHwEngine_Num) + { + NVDDK_AES_CHECK_INTERFACE(pAesHwCtxt, SbkEngine); + + AesCoreRequestHwAccess(); + + // Clear the SBK encrypt key + NVDDK_AES_CHECK_INTERFACE_FUNC(pAesHwCtxt, SbkEngine, AesHwClearKeyAndIv); + pAesHwCtxt->ppEngineCaps[SbkEngine]->pAesInterf->AesHwClearKeyAndIv(SbkEngine, EncryptSlot, pAesHwCtxt); + + // Clear the SBK decrypt key + pAesHwCtxt->ppEngineCaps[SbkEngine]->pAesInterf->AesHwClearKeyAndIv(SbkEngine, DecryptSlot, pAesHwCtxt); + + AesCoreReleaseHwAccess(); + + if (!AesCoreIsSbkCleared(SbkEngine, EncryptSlot, DecryptSlot, pAesHwCtxt)) + { + // Return error if SB clear check fails + e = NvError_AesClearSbkFailed; + } + } + } + + NvOsMutexUnlock(gs_hAesCoreEngineMutex); + return e; +} + +NvError NvDdkAesLockSecureStorageKey(NvDdkAesHandle hAes) +{ + NvError e = NvSuccess; + NvDdkAes *pAesClient = (NvDdkAes*)hAes; + AesHwContext *pAesHwCtxt = NULL; + AesHwEngine Engine; + + if (!hAes) + return NvError_BadParameter; + + NVDDK_AES_CHECK_USER_IDENTITY; + + NVDDK_AES_CHECK_ROOT_PERMISSION; + + NvOsMutexLock(gs_hAesCoreEngineMutex); + + // Get the AES H/W context + NV_ASSERT(pAesClient->pAesCoreEngine); + pAesHwCtxt = &pAesClient->pAesCoreEngine->AesHwCtxt; + + for (Engine = AesHwEngine_A; Engine < AesHwEngine_Num; Engine++) + { + AesHwEngine SskEngine = pAesClient->pAesCoreEngine->SskEngine[Engine]; + AesHwKeySlot DecryptSlot = pAesClient->pAesCoreEngine->SskDecryptSlot; + AesHwKeySlot EncryptSlot = pAesClient->pAesCoreEngine->SskEncryptSlot; + + if (SskEngine < AesHwEngine_Num) + { + NVDDK_AES_CHECK_INTERFACE(pAesHwCtxt, SskEngine); + + AesCoreRequestHwAccess(); + + // Disable permissions to the SSK key slot in the AES engine + NVDDK_AES_CHECK_INTERFACE_FUNC(pAesHwCtxt, SskEngine, AesHwLockSskReadWrites); + pAesHwCtxt->ppEngineCaps[SskEngine]->pAesInterf->AesHwLockSskReadWrites(pAesHwCtxt, SskEngine); + + AesCoreReleaseHwAccess(); + + if (!AesCoreIsSskLocked(SskEngine, EncryptSlot, DecryptSlot, pAesHwCtxt)) + { + e = NvError_AesLockSskFailed; + goto fail; + } + + // Also, lock the Secure scratch registers + NV_CHECK_ERROR_CLEANUP(AesCoreLoadSskToSecureScratchAndLock(pAesHwCtxt, NULL)); + } + } + +fail: + NvOsMutexUnlock(gs_hAesCoreEngineMutex); + return e; +} + +NvError +NvDdkAesSetAndLockSecureStorageKey( + NvDdkAesHandle hAes, + NvDdkAesKeySize KeyLength, + const NvU8 *pSecureStorageKey) +{ + NvError e = NvSuccess; + NvDdkAes *pAesClient = (NvDdkAes*)hAes; + AesHwContext *pAesHwCtxt = NULL; + AesHwIv Iv; + AesHwEngine Engine; + + NVDDK_AES_CHECK_INPUT_PARAMS(pSecureStorageKey); + + NVDDK_AES_CHECK_USER_IDENTITY; + + NVDDK_AES_CHECK_ROOT_PERMISSION; + + switch (KeyLength) + { + case NvDdkAesKeySize_128Bit: + break; + case NvDdkAesKeySize_192Bit: + case NvDdkAesKeySize_256Bit: + default: + return NvError_NotSupported; + } + + NvOsMutexLock(gs_hAesCoreEngineMutex); + + // Get the AES H/W context + NV_ASSERT(pAesClient->pAesCoreEngine); + pAesHwCtxt = &pAesClient->pAesCoreEngine->AesHwCtxt; + + for (Engine = AesHwEngine_A; Engine < AesHwEngine_Num; Engine++) + { + AesHwEngine SskEngine = pAesClient->pAesCoreEngine->SskEngine[Engine]; + AesHwKeySlot DecryptSlot = pAesClient->pAesCoreEngine->SskDecryptSlot; + AesHwKeySlot EncryptSlot = pAesClient->pAesCoreEngine->SskEncryptSlot; + + if (SskEngine < AesHwEngine_Num) + { + // Setup the SSK with Zero IV + NvOsMemset(&Iv, 0, NvDdkAesConst_IVLengthBytes); + + NVDDK_AES_CHECK_INTERFACE(pAesHwCtxt, SskEngine); + + AesCoreRequestHwAccess(); + + // Setup SSK Key table for encryption + NVDDK_AES_CHECK_INTERFACE_FUNC(pAesHwCtxt, SskEngine, AesHwSetKeyAndIv); + pAesHwCtxt->ppEngineCaps[SskEngine]->pAesInterf->AesHwSetKeyAndIv( + SskEngine, + EncryptSlot, + (AesHwKey*)pSecureStorageKey, + &Iv, + NV_TRUE, + pAesHwCtxt); + + // Setup SSK Key table for decryption + pAesHwCtxt->ppEngineCaps[SskEngine]->pAesInterf->AesHwSetKeyAndIv( + SskEngine, + DecryptSlot, + (AesHwKey*)pSecureStorageKey, + &Iv, + NV_FALSE, + pAesHwCtxt); + + // Disable the read / write access + NVDDK_AES_CHECK_INTERFACE_FUNC(pAesHwCtxt, SskEngine, AesHwLockSskReadWrites); + pAesHwCtxt->ppEngineCaps[SskEngine]->pAesInterf->AesHwLockSskReadWrites(pAesHwCtxt, SskEngine); + + AesCoreReleaseHwAccess(); + + if (!AesCoreIsSskLocked(SskEngine, EncryptSlot, DecryptSlot, pAesHwCtxt)) + { + e = NvError_AesLockSskFailed; + goto fail; + } + + // Store the SSK in the Secure scratch and lock + NV_CHECK_ERROR_CLEANUP(AesCoreLoadSskToSecureScratchAndLock(pAesHwCtxt, pSecureStorageKey)); + } + } + +fail: + NvOsMutexUnlock(gs_hAesCoreEngineMutex); + return e; +} + +NvError NvDdkAesDisableCrypto(NvDdkAesHandle hAes) +{ + NvError e = NvSuccess; + NvDdkAes *pAesClient = (NvDdkAes*)hAes; + AesHwContext *pAesHwCtxt = NULL; + AesHwEngine Engine; + + if (!hAes) + return NvError_BadParameter; + + NVDDK_AES_CHECK_USER_IDENTITY; + + NVDDK_AES_CHECK_ROOT_PERMISSION; + + NvOsMutexLock(gs_hAesCoreEngineMutex); + + // Get the AES H/W context + NV_ASSERT(pAesClient->pAesCoreEngine); + pAesHwCtxt = &pAesClient->pAesCoreEngine->AesHwCtxt; + + AesCoreRequestHwAccess(); + + for (Engine = AesHwEngine_A; Engine < AesHwEngine_Num; Engine++) + { + NVDDK_AES_CHECK_INTERFACE(pAesHwCtxt, Engine); + NVDDK_AES_CHECK_INTERFACE_FUNC(pAesHwCtxt, Engine, AesHwDisableEngine); + + if (NvSuccess != pAesHwCtxt->ppEngineCaps[Engine]->pAesInterf->AesHwDisableEngine(pAesHwCtxt, Engine)) + e = NvError_AesDisableCryptoFailed; + } + + AesCoreReleaseHwAccess(); + + if (NvSuccess == e) + { + // Mark engine as disabled + pAesClient->pAesCoreEngine->IsEngineDisabled = NV_TRUE; + } + + NvOsMutexUnlock(gs_hAesCoreEngineMutex); + return e; +} + +NvError NvDdkAesGetCapabilities(NvDdkAesHandle hAes, NvDdkAesCapabilities *pCapabilities) +{ + NvDdkAes *pAesClient = (NvDdkAes*)hAes; + + NVDDK_AES_CHECK_INPUT_PARAMS(pCapabilities); + + NVDDK_AES_CHECK_USER_IDENTITY; + + pCapabilities->OptimalBufferAlignment = 1; + + return NvSuccess; +} + +/** + * Request access to HW. + */ +void AesCoreRequestHwAccess(void) +{ +#if !NV_OAL + NvRmXpcModuleAcquire(NvRmModuleID_Vde); + NvRmXpcModuleAcquire(NvRmModuleID_BseA); +#endif +} + +/** + * Release access to HW. + */ +void AesCoreReleaseHwAccess(void) +{ +#if !NV_OAL + NvRmXpcModuleRelease(NvRmModuleID_BseA); + NvRmXpcModuleRelease(NvRmModuleID_Vde); +#endif +} + +#if NV_OAL + +/** + * Allocate the RM memory for key table and dma buffers. + * + * @param pAesHwCtxt Pointer to the AES H/W engine context. + * + * @retval NvError_Success if memory is allocated successfully. + * @retval NvError_InsufficientMemory if memory is not allocated successfully. + */ +NvError AesCoreAllocateRmMemory(AesHwContext *const pAesHwCtxt) +{ + NvError e; + NvU8 *pKeyTabVirtAddr = NULL; + NvRmPhysAddr KeyTabPhyAddr = NVBL_AES_KEY_TABLE_ADDR; + NvU8 *pDmaVirtAddr = NULL; + NvRmPhysAddr DmaPhyAddr = 0; + AesHwEngine Engine; + NvU32 size = 0; + + NV_ASSERT(pAesHwCtxt); + + NvOsMutexLock(gs_hAesCoreEngineMutex); + + // Calculate total size needed + for (Engine = AesHwEngine_A; Engine < AesHwEngine_Num; Engine++) + size += (pAesHwCtxt->KeyTableSize[Engine] + NvDdkAesKeySize_128Bit); + + // Get virtual address + NV_ASSERT_SUCCESS(NvOsPhysicalMemMap( + KeyTabPhyAddr, + size, + NvOsMemAttribute_Uncached, + NVOS_MEM_READ_WRITE, + (void*)&pKeyTabVirtAddr)); + + size = 0; + for (Engine = AesHwEngine_A; Engine < AesHwEngine_Num; Engine++) + { + pAesHwCtxt->KeyTablePhyAddr[Engine] = KeyTabPhyAddr + size; + pAesHwCtxt->pKeyTableVirAddr[Engine] = pKeyTabVirtAddr + size; + size = pAesHwCtxt->KeyTableSize[Engine] + NvDdkAesKeySize_128Bit; + } + + // Allocate DMA buffer for both the engines + size = AES_HW_DMA_BUFFER_SIZE_BYTES * AesHwEngine_Num; + NV_CHECK_ERROR_CLEANUP(NvRmMemHandleCreate(pAesHwCtxt->hRmDevice, &pAesHwCtxt->hDmaMemBuf, size)); + + NV_CHECK_ERROR_CLEANUP(NvRmMemAlloc( + pAesHwCtxt->hDmaMemBuf, + NULL, + 0, + AES_HW_DMA_ADDR_ALIGNMENT, + NvOsMemAttribute_Uncached)); + + // Get the virtual address + pDmaVirtAddr = (NvU8 *)NvRmMemPin((NvRmMemHandle)pAesHwCtxt->hDmaMemBuf); + + // Get the physical address + DmaPhyAddr = NvBlVaToPa(pDmaVirtAddr); + if (NVBL_INVALID_PA == DmaPhyAddr) + { + NV_ASSERT(0); + e = NvError_InvalidAddress; + goto fail; + } + + // Get a uncached alias to the buffer + if (NvOsPhysicalMemMap(DmaPhyAddr, size, NvOsMemAttribute_Uncached, NVOS_MEM_READ_WRITE, (void **)&pDmaVirtAddr) != + NvError_Success) + { + NV_ASSERT(0); + e = NvError_InvalidAddress; + goto fail; + } + + for (Engine = AesHwEngine_A; Engine < AesHwEngine_Num; Engine++) + { + pAesHwCtxt->DmaPhyAddr[Engine] = DmaPhyAddr + (Engine * AES_HW_DMA_BUFFER_SIZE_BYTES); + pAesHwCtxt->pDmaVirAddr[Engine] = pDmaVirtAddr + (Engine * AES_HW_DMA_BUFFER_SIZE_BYTES); + } + + NvOsMutexUnlock(gs_hAesCoreEngineMutex); + return NvError_Success; + +fail: + AesCoreDeAllocateRmMemory(pAesHwCtxt); + NvOsMutexUnlock(gs_hAesCoreEngineMutex); + return e; +} + +/** + * De-allocate the RM memory allocated with .AesAllocateRmMemory(). + * + * @param pAesHwCtxt Pointer to the AES Hw engine context. + * + * @retval None. + */ +void AesCoreDeAllocateRmMemory(AesHwContext *const pAesHwCtxt); +{ + NV_ASSERT(pAesHwCtxt); + + NvOsMutexLock(gs_hAesCoreEngineMutex); + + if (pAesHwCtxt->hKeyTableMemBuf) + { + NvRmMemUnpin(pAesHwCtxt->hKeyTableMemBuf); + NvRmMemHandleFree(pAesHwCtxt->hKeyTableMemBuf); + pAesHwCtxt->hKeyTableMemBuf = NULL; + } + + if (pAesHwCtxt->hDmaMemBuf) + { + NvRmMemUnpin(pAesHwCtxt->hDmaMemBuf); + NvRmMemHandleFree(pAesHwCtxt->hDmaMemBuf); + pAesHwCtxt->hDmaMemBuf = NULL; + } + + NvOsMutexUnlock(gs_hAesCoreEngineMutex); +} + +#else + +/** + * Allocate the RM memory for key table and dma buffers. + * + * @param pAesHwCtxt Pointer to the AES H/W engine context. + * + * @retval NvError_Success if memory is allocated successfully. + * @retval NvError_InsufficientMemory if memory is not allocated successfully. + */ +NvError AesCoreAllocateRmMemory(AesHwContext *const pAesHwCtxt) +{ + NvError e; + static const NvRmHeap s_Heaps[] = {NvRmHeap_IRam}; + NvU8 *pKeyTabVirtAddr = NULL; + NvRmPhysAddr KeyTabPhyAddr = 0; + NvU8 * pDmaVirtAddr = NULL; + NvRmPhysAddr DmaPhyAddr = 0; + // Allocate key table memory for both the engines + NvU32 size = NVBL_AES_KEY_TABLE_OFFSET; + AesHwEngine Engine; + + NV_ASSERT(pAesHwCtxt); + + NvOsMutexLock(gs_hAesCoreEngineMutex); + + // Calculate total size needed + for (Engine = AesHwEngine_A; Engine < AesHwEngine_Num; Engine++) + size += (pAesHwCtxt->KeyTableSize[Engine] + NvDdkAesKeySize_128Bit); + + NV_CHECK_ERROR(NvRmMemHandleCreate(pAesHwCtxt->hRmDevice, &pAesHwCtxt->hKeyTableMemBuf, size)); + + if (!pAesHwCtxt->hKeyTableMemBuf) + { + e = NvError_InsufficientMemory; + goto fail; + } + + NV_CHECK_ERROR_CLEANUP(NvRmMemAlloc( + pAesHwCtxt->hKeyTableMemBuf, + s_Heaps, + NV_ARRAY_SIZE(s_Heaps), + AES_HW_KEY_TABLE_ADDR_ALIGNMENT, + NvOsMemAttribute_Uncached)); + + KeyTabPhyAddr = NvRmMemPin(pAesHwCtxt->hKeyTableMemBuf) + NVBL_AES_KEY_TABLE_OFFSET; + + NV_CHECK_ERROR_CLEANUP(NvRmPhysicalMemMap( + KeyTabPhyAddr, + (size - NVBL_AES_KEY_TABLE_OFFSET), + NVOS_MEM_READ_WRITE, + NvOsMemAttribute_Uncached, + (void **)&pKeyTabVirtAddr)); + + size = 0; + for (Engine = AesHwEngine_A; Engine < AesHwEngine_Num; Engine++) + { + pAesHwCtxt->KeyTablePhyAddr[Engine] = KeyTabPhyAddr + size; + pAesHwCtxt->pKeyTableVirAddr[Engine] = pKeyTabVirtAddr + size; + size = pAesHwCtxt->KeyTableSize[Engine] + NvDdkAesKeySize_128Bit; + } + + // Allocate DMA buffer for both the engines + size = AES_HW_DMA_BUFFER_SIZE_BYTES * AesHwEngine_Num; + + NV_CHECK_ERROR_CLEANUP(NvRmMemHandleCreate(pAesHwCtxt->hRmDevice, &pAesHwCtxt->hDmaMemBuf, size)); + + NV_CHECK_ERROR_CLEANUP(NvRmMemAlloc( + pAesHwCtxt->hDmaMemBuf, + NULL, + 0, + AES_HW_DMA_ADDR_ALIGNMENT, + NvOsMemAttribute_Uncached)); + + DmaPhyAddr = NvRmMemPin(pAesHwCtxt->hDmaMemBuf); + + NV_CHECK_ERROR_CLEANUP(NvRmMemMap(pAesHwCtxt->hDmaMemBuf, 0, size, NVOS_MEM_READ_WRITE, (void **)&pDmaVirtAddr)); + + for (Engine = AesHwEngine_A; Engine < AesHwEngine_Num; Engine++) + { + pAesHwCtxt->DmaPhyAddr[Engine] = DmaPhyAddr + (Engine * AES_HW_DMA_BUFFER_SIZE_BYTES); + pAesHwCtxt->pDmaVirAddr[Engine] = pDmaVirtAddr + (Engine * AES_HW_DMA_BUFFER_SIZE_BYTES); + } + + NvOsMutexUnlock(gs_hAesCoreEngineMutex); + return NvSuccess; + +fail: + AesCoreDeAllocateRmMemory(pAesHwCtxt); + NvOsMutexUnlock(gs_hAesCoreEngineMutex); + return e; +} + +/** + * De-allocate the RM memory allocated with .AesAllocateRmMemory(). + * + * @param pAesHwCtxt Pointer to the AES Hw engine context. + * + * @retval None. + */ +void AesCoreDeAllocateRmMemory(AesHwContext *const pAesHwCtxt) +{ + NV_ASSERT(pAesHwCtxt); + + NvOsMutexLock(gs_hAesCoreEngineMutex); + + if (pAesHwCtxt->hKeyTableMemBuf) + { + AesHwEngine Engine; + NvU32 size = 0; + + for (Engine = AesHwEngine_A; Engine < AesHwEngine_Num; Engine++) + size += (pAesHwCtxt->KeyTableSize[Engine] + NvDdkAesKeySize_128Bit); + + NvRmPhysicalMemUnmap(pAesHwCtxt->pKeyTableVirAddr[0], size); + NvRmMemUnpin(pAesHwCtxt->hKeyTableMemBuf); + NvRmMemHandleFree(pAesHwCtxt->hKeyTableMemBuf); + pAesHwCtxt->hKeyTableMemBuf = NULL; + } + + if (pAesHwCtxt->hDmaMemBuf) + { + NvRmMemUnmap( + pAesHwCtxt->hDmaMemBuf, + pAesHwCtxt->pDmaVirAddr[0], + AES_HW_DMA_BUFFER_SIZE_BYTES * AesHwEngine_Num); + NvRmMemUnpin(pAesHwCtxt->hDmaMemBuf); + NvRmMemHandleFree(pAesHwCtxt->hDmaMemBuf); + pAesHwCtxt->hDmaMemBuf = NULL; + } + + NvOsMutexUnlock(gs_hAesCoreEngineMutex); +} + +#endif // NV_OAL + +/** + * Select the key specified by the client in the AES engine. + * + + * @param KeyType Key type. + * @param IsDedicatedSlot NV_TRUE if slot is dedicated, NV_FALSE if not. + * @param pKeyData Pointer to the key data. + * @param pAesClient Pointer to AES client. + * + * @retval NvSuccess if successfully completed. + * @retval NvError_NotSupported if operation is not supported. + */ +NvError +AesCoreSetKey( + const NvDdkAesKeyType KeyType, + const NvBool IsDedicatedSlot, + const NvU8 *const pKeyData, + NvDdkAes *const pAesClient) +{ + NvError e = NvSuccess; + AesHwContext *pAesHwCtxt = NULL; + AesHwEngine Engine; + AesHwKeySlot KeySlot; + + NV_ASSERT(pAesClient); + + if ((NvDdkAesKeyType_SecureBootKey == KeyType) || (NvDdkAesKeyType_SecureStorageKey == KeyType)) + { + NVDDK_AES_CHECK_ROOT_PERMISSION; + } + + pAesClient->IsDedicatedSlot = NV_FALSE; + + NvOsMutexLock(gs_hAesCoreEngineMutex); + + // Get the AES H/W context + NV_ASSERT(pAesClient->pAesCoreEngine); + pAesHwCtxt = &pAesClient->pAesCoreEngine->AesHwCtxt; + + switch (KeyType) + { + case NvDdkAesKeyType_SecureBootKey: + pAesClient->Engine = pAesClient->pAesCoreEngine->SbkEngine[0]; + pAesClient->KeySlot = pAesClient->IsEncryption ? + pAesClient->pAesCoreEngine->SbkEncryptSlot : pAesClient->pAesCoreEngine->SbkDecryptSlot; + break; + case NvDdkAesKeyType_SecureStorageKey: + pAesClient->Engine = pAesClient->pAesCoreEngine->SskEngine[0]; + pAesClient->KeySlot = pAesClient->IsEncryption ? + pAesClient->pAesCoreEngine->SskEncryptSlot : pAesClient->pAesCoreEngine->SskDecryptSlot; + break; + case NvDdkAesKeyType_UserSpecified: + pAesClient->IsDedicatedSlot = IsDedicatedSlot; + if (!IsDedicatedSlot) + { + // It is not dedicated slot => obfuscate the key + // Wrap the key using RFC3394 key wrapping algorithm + // The wrapped key and RFCwrapped IV will be stored in client handle + NV_CHECK_ERROR_CLEANUP(AesCoreWrapKey( + pAesClient, + pKeyData, + gs_OriginalIV, + pAesClient->Key, + pAesClient->WrappedIv)); + goto done; + } + // It is dedicated slot + NV_CHECK_ERROR_CLEANUP(AesCoreGetFreeSlot(pAesClient->pAesCoreEngine, &Engine, &KeySlot)); + pAesClient->pAesCoreEngine->IsKeySlotUsed[Engine][KeySlot] = NV_TRUE; + pAesClient->Engine = Engine; + pAesClient->KeySlot = KeySlot; + + // Initialize IV to zeros + NvOsMemset(pAesClient->Iv, 0, NvDdkAesConst_IVLengthBytes); + NVDDK_AES_CHECK_INTERFACE(pAesHwCtxt, Engine); + + AesCoreRequestHwAccess(); + + // Setup Key table + NVDDK_AES_CHECK_INTERFACE_FUNC(pAesHwCtxt, Engine, AesHwSetKeyAndIv); + pAesHwCtxt->ppEngineCaps[pAesClient->Engine]->pAesInterf->AesHwSetKeyAndIv( + pAesClient->Engine, + pAesClient->KeySlot, + (AesHwKey *)pKeyData, + (AesHwIv *)pAesClient->Iv, + pAesClient->IsEncryption, + pAesHwCtxt); + + AesCoreReleaseHwAccess(); + break; + default: + goto fail; + } + + NVDDK_AES_CHECK_INTERFACE(pAesHwCtxt, pAesClient->Engine); + + AesCoreRequestHwAccess(); + + // Select Key slot + NVDDK_AES_CHECK_INTERFACE_FUNC(pAesHwCtxt, pAesClient->Engine, AesHwSelectKeyIvSlot); + pAesHwCtxt->ppEngineCaps[pAesClient->Engine]->pAesInterf->AesHwSelectKeyIvSlot( + pAesClient->Engine, + pAesClient->KeySlot, + pAesHwCtxt); + + // Get the IV and store it with client + NVDDK_AES_CHECK_INTERFACE_FUNC(pAesHwCtxt, pAesClient->Engine, AesHwGetIv); + pAesHwCtxt->ppEngineCaps[pAesClient->Engine]->pAesInterf->AesHwGetIv( + pAesHwCtxt, + pAesClient->Engine, + pAesClient->KeySlot, + (AesHwIv *)pAesClient->Iv); + + AesCoreReleaseHwAccess(); + +done: + // Store the Key Type for this client + pAesClient->KeyType = KeyType; + +fail: + NvOsMutexUnlock(gs_hAesCoreEngineMutex); + return e; +} + +/** + * Load the SSK into the secure scratch and disables the write permissions. + * Note: If Key is not specified then this API locks the Secure Scratch registers. + * + * @param pAesHwCtxt Pointer to AES H/W context. + * @param pKey Pointer to the key. If pKey == NULL then key will not be set to the + * secure scratch registers, but locks the Secure scratch register. + * + * @retval NvSuccess if successfully completed. + */ +NvError AesCoreLoadSskToSecureScratchAndLock(const AesHwContext *const pAesHwCtxt, const NvU8 *const pKey) +{ + NvError e = NvSuccess; + NvRmPhysAddr PhysAdr; + NvU32 BankSize; + NvU32 RmPwrClientId = 0; + + NVDDK_AES_CHECK_INTERFACE(pAesHwCtxt, 0); + + // Get the secure scratch base address + NvRmModuleGetBaseAddress(pAesHwCtxt->hRmDevice, NVRM_MODULE_ID(NvRmModuleID_Pmif, 0), &PhysAdr, &BankSize); + + // Register with Power Manager + RmPwrClientId = NVRM_POWER_CLIENT_TAG('A','E','S','2'); + + NV_CHECK_ERROR_CLEANUP(NvRmPowerRegister(pAesHwCtxt->hRmDevice, NULL, &RmPwrClientId)); + + // Enable the Voltage + NV_CHECK_ERROR_CLEANUP(NvRmPowerVoltageControl( + pAesHwCtxt->hRmDevice, + NvRmModuleID_Pmif, + RmPwrClientId, + NvRmVoltsUnspecified, + NvRmVoltsUnspecified, + NULL, + 0, + NULL)); + + // Emable the clock to the PMIC + NV_CHECK_ERROR_CLEANUP(NvRmPowerModuleClockControl(pAesHwCtxt->hRmDevice, NvRmModuleID_Pmif, RmPwrClientId, NV_TRUE)); + + // Store SSK and lock the secure scratch -- engine doesn't matter here + // since the key is being provided and not really read from the key table of an engine .here + // If pKey == NULL this call will disable the write permissions to the scratch registers. + AesCoreRequestHwAccess(); + + NVDDK_AES_CHECK_INTERFACE_FUNC(pAesHwCtxt, 0, AesHwLoadSskToSecureScratchAndLock); + pAesHwCtxt->ppEngineCaps[0]->pAesInterf->AesHwLoadSskToSecureScratchAndLock(PhysAdr, (AesHwKey *)pKey, BankSize); + + AesCoreReleaseHwAccess(); + +fail: + // Disable the clock to the PMIC + NV_ASSERT_SUCCESS(NvRmPowerModuleClockControl(pAesHwCtxt->hRmDevice, NvRmModuleID_Pmif, RmPwrClientId, NV_FALSE)); + + // Disable the Voltage + NV_ASSERT_SUCCESS(NvRmPowerVoltageControl( + pAesHwCtxt->hRmDevice, + NvRmModuleID_Pmif, + RmPwrClientId, + NvRmVoltsOff, + NvRmVoltsOff, + NULL, + 0, + NULL)); + + // Unregister driver from Power Manager + NvRmPowerUnRegister(pAesHwCtxt->hRmDevice, RmPwrClientId); + return e; +} + +/** + * Check the SBK clear by encrypting / decrypting the known data. + * + * @param Engine Engine on which encryption and decryption need to be performed + * @param EncryptSlot Key slot where encrypt key is located. + * @param DecryptSlot Key slot where decrypt key is located. + * @param pAesHwCtxt Pointer to AES H/W context. + * + * @retval NV_TRUE if successfully encryption and decryption is done else NV_FALSE. + */ +NvBool AesCoreIsSbkCleared( + const AesHwEngine Engine, + const AesHwKeySlot EncryptSlot, + const AesHwKeySlot DecryptSlot, + AesHwContext *const pAesHwCtxt) +{ + NvError e = NvSuccess; + AesHwIv ZeroIv; + NvU32 i; + + // Known Good data + static NvU8 s_GoldData[NvDdkAesConst_BlockLengthBytes] = + { + 0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, + 0x0C, 0x0D, 0x0E, 0x0F + }; + + // Encrypted data for above known data with Zero key and Zero IV + static NvU8 s_EncryptDataWithZeroKeyTable[NvDdkAesConst_BlockLengthBytes] = + { + 0x7A, 0xCA, 0x0F, 0xD9, + 0xBC, 0xD6, 0xEC, 0x7C, + 0x9F, 0x97, 0x46, 0x66, + 0x16, 0xE6, 0xA2, 0x82 + }; + + // Encrypted data for above known data with Zero key and Zero IV + static NvU8 s_EncryptDataWithZeroKeySchedule[NvDdkAesConst_BlockLengthBytes] = + { + 0x18, 0x9D, 0x19, 0xEA, + 0xDB, 0xA7, 0xE3, 0x0E, + 0xD9, 0x72, 0x80, 0x8F, + 0x3F, 0x2B, 0xA0, 0x30 + }; + + NvU8 *pEncryptData = NULL; + NvU8 EncryptBuffer[NvDdkAesConst_BlockLengthBytes]; + NvU8 DecryptBuffer[NvDdkAesConst_BlockLengthBytes]; + + NVDDK_AES_CHECK_INTERFACE(pAesHwCtxt, Engine); + + NvOsMutexLock(gs_hAesCoreEngineMutex); + + if (pAesHwCtxt->ppEngineCaps[Engine]->IsHwKeySchedGenSupported) + pEncryptData = s_EncryptDataWithZeroKeyTable; + else + pEncryptData = s_EncryptDataWithZeroKeySchedule; + + NvOsMemset(EncryptBuffer, 0, NvDdkAesConst_BlockLengthBytes); + NvOsMemset(DecryptBuffer, 0, NvDdkAesConst_BlockLengthBytes); + NvOsMemset(&ZeroIv, 0, sizeof(AesHwIv)); + + AesCoreRequestHwAccess(); + + // Select Encrypt Key slot + NVDDK_AES_CHECK_INTERFACE_FUNC(pAesHwCtxt, Engine, AesHwSelectKeyIvSlot); + pAesHwCtxt->ppEngineCaps[Engine]->pAesInterf->AesHwSelectKeyIvSlot(Engine, EncryptSlot, pAesHwCtxt); + + // Set the Zero IV for test data + NVDDK_AES_CHECK_INTERFACE_FUNC(pAesHwCtxt, Engine, AesHwSetIv); + NV_CHECK_ERROR_CLEANUP(pAesHwCtxt->ppEngineCaps[Engine]->pAesInterf->AesHwSetIv( + Engine, + EncryptSlot, + &ZeroIv, + pAesHwCtxt)); + + // Process the buffer for encryption + NVDDK_AES_CHECK_INTERFACE_FUNC(pAesHwCtxt, Engine, AesHwStartEngine); + NV_CHECK_ERROR_CLEANUP(pAesHwCtxt->ppEngineCaps[Engine]->pAesInterf->AesHwStartEngine( + Engine, + NvDdkAesConst_BlockLengthBytes, + s_GoldData, + NV_TRUE, + NvDdkAesOperationalMode_Cbc, + EncryptBuffer, + pAesHwCtxt)); + + // Select Decrypt Key slot + NVDDK_AES_CHECK_INTERFACE_FUNC(pAesHwCtxt, Engine, AesHwSelectKeyIvSlot); + pAesHwCtxt->ppEngineCaps[Engine]->pAesInterf->AesHwSelectKeyIvSlot(Engine, DecryptSlot, pAesHwCtxt); + + // Set the Zero IV for test data + NVDDK_AES_CHECK_INTERFACE_FUNC(pAesHwCtxt, Engine, AesHwSetIv); + NV_CHECK_ERROR_CLEANUP(pAesHwCtxt->ppEngineCaps[Engine]->pAesInterf->AesHwSetIv( + Engine, + DecryptSlot, + &ZeroIv, + pAesHwCtxt)); + + // Process the buffer for encryption + NVDDK_AES_CHECK_INTERFACE_FUNC(pAesHwCtxt, Engine, AesHwStartEngine); + NV_CHECK_ERROR_CLEANUP(pAesHwCtxt->ppEngineCaps[Engine]->pAesInterf->AesHwStartEngine( + Engine, + NvDdkAesConst_BlockLengthBytes, + EncryptBuffer, + NV_FALSE, + NvDdkAesOperationalMode_Cbc, + DecryptBuffer, + pAesHwCtxt)); + + // Clear the IV in the engine before we leave + NVDDK_AES_CHECK_INTERFACE_FUNC(pAesHwCtxt, Engine, AesHwClearIv); + pAesHwCtxt->ppEngineCaps[Engine]->pAesInterf->AesHwClearIv(Engine, EncryptSlot, pAesHwCtxt); + pAesHwCtxt->ppEngineCaps[Engine]->pAesInterf->AesHwClearIv(Engine, DecryptSlot, pAesHwCtxt); + + // Clear the DMA buffer before we leave from this operation. + NvOsMemset(pAesHwCtxt->pDmaVirAddr[Engine], 0, AES_HW_DMA_BUFFER_SIZE_BYTES); + + for (i = 0; i < NvDdkAesConst_BlockLengthBytes; i++) + { + if ((pEncryptData[i] != EncryptBuffer[i]) || (s_GoldData[i] != DecryptBuffer[i])) + goto fail; + } + + AesCoreReleaseHwAccess(); + NvOsMutexUnlock(gs_hAesCoreEngineMutex); + return NV_TRUE; + +fail: + // Clear the DMA buffer before we leave from this operation + NvOsMemset(pAesHwCtxt->pDmaVirAddr[Engine], 0, AES_HW_DMA_BUFFER_SIZE_BYTES); + AesCoreReleaseHwAccess(); + NvOsMutexUnlock(gs_hAesCoreEngineMutex); + return NV_FALSE; +} + +/** + * Check the SSK lock is successfully done or not by writing zero key into SSK. + * + * @param Engine Engine where SSK is set. + * @param EncryptSlot Key slot where encrypt key is located. + * @param DecryptSlot Key slot where decrypt key is located. + * @param pAesHwCtxt Pointer to AES H/W context. + * + * @retval NV_TRUE if successfully SSK is locked else NV_FALSE. + */ +NvBool +AesCoreIsSskLocked( + const AesHwEngine Engine, + const AesHwKeySlot EncryptSlot, + const AesHwKeySlot DecryptSlot, + AesHwContext *const pAesHwCtxt) +{ + NvError e = NvSuccess; + AesHwIv ZeroIv; + AesHwKey ZeroKey; + NvU32 i; + + static NvU8 s_GoldData[NvDdkAesConst_BlockLengthBytes] = + { + 0x00, 0x11, 0x22, 0x33, + 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xAA, 0xBB, + 0xCC, 0xDD, 0xEE, 0xFF + }; + + NvU8 EncryptBuffer1[NvDdkAesConst_BlockLengthBytes]; + NvU8 DecryptBuffer1[NvDdkAesConst_BlockLengthBytes]; + NvU8 EncryptBuffer2[NvDdkAesConst_BlockLengthBytes]; + NvU8 DecryptBuffer2[NvDdkAesConst_BlockLengthBytes]; + + NVDDK_AES_CHECK_INTERFACE(pAesHwCtxt, Engine); + + NvOsMemset(EncryptBuffer1, 0, NvDdkAesConst_BlockLengthBytes); + NvOsMemset(DecryptBuffer1, 0, NvDdkAesConst_BlockLengthBytes); + NvOsMemset(EncryptBuffer2, 0, NvDdkAesConst_BlockLengthBytes); + NvOsMemset(DecryptBuffer2, 0, NvDdkAesConst_BlockLengthBytes); + NvOsMemset(&ZeroIv, 0, sizeof(AesHwIv)); + NvOsMemset(&ZeroKey, 0, sizeof(AesHwKey)); + + NvOsMutexLock(gs_hAesCoreEngineMutex); + + AesCoreRequestHwAccess(); + + // Select Encrypt Key slot + NVDDK_AES_CHECK_INTERFACE_FUNC(pAesHwCtxt, Engine, AesHwSelectKeyIvSlot); + pAesHwCtxt->ppEngineCaps[Engine]->pAesInterf->AesHwSelectKeyIvSlot(Engine, EncryptSlot, pAesHwCtxt); + + // Set the Zero IV for test data + NVDDK_AES_CHECK_INTERFACE_FUNC(pAesHwCtxt, Engine, AesHwSetIv); + NV_CHECK_ERROR_CLEANUP(pAesHwCtxt->ppEngineCaps[Engine]->pAesInterf->AesHwSetIv( + Engine, + EncryptSlot, + &ZeroIv, + pAesHwCtxt)); + + // Process the buffer for encryption + NVDDK_AES_CHECK_INTERFACE_FUNC(pAesHwCtxt, Engine, AesHwStartEngine); + NV_CHECK_ERROR_CLEANUP(pAesHwCtxt->ppEngineCaps[Engine]->pAesInterf->AesHwStartEngine( + Engine, + NvDdkAesConst_BlockLengthBytes, + s_GoldData, + NV_TRUE, + NvDdkAesOperationalMode_Cbc, + EncryptBuffer1, + pAesHwCtxt)); + + // Select Decrypt Key slot + NVDDK_AES_CHECK_INTERFACE_FUNC(pAesHwCtxt, Engine, AesHwSelectKeyIvSlot); + pAesHwCtxt->ppEngineCaps[Engine]->pAesInterf->AesHwSelectKeyIvSlot(Engine, DecryptSlot, pAesHwCtxt); + + // Set the Zero IV for test data + NVDDK_AES_CHECK_INTERFACE_FUNC(pAesHwCtxt, Engine, AesHwSetIv); + NV_CHECK_ERROR_CLEANUP(pAesHwCtxt->ppEngineCaps[Engine]->pAesInterf->AesHwSetIv( + Engine, + DecryptSlot, + &ZeroIv, + pAesHwCtxt)); + + // Process the buffer for encryption + NVDDK_AES_CHECK_INTERFACE_FUNC(pAesHwCtxt, Engine, AesHwStartEngine); + NV_CHECK_ERROR_CLEANUP(pAesHwCtxt->ppEngineCaps[Engine]->pAesInterf->AesHwStartEngine( + Engine, + NvDdkAesConst_BlockLengthBytes, + s_GoldData, + NV_FALSE, + NvDdkAesOperationalMode_Cbc, + DecryptBuffer1, + pAesHwCtxt)); + + // Set Zero key to the SSK slot and try encryption / decryption with + // known data and check data after encryption and decryption are same with SSK + + // Setup SSK Key table for encryption + NVDDK_AES_CHECK_INTERFACE_FUNC(pAesHwCtxt, Engine, AesHwSetKeyAndIv); + pAesHwCtxt->ppEngineCaps[Engine]->pAesInterf->AesHwSetKeyAndIv( + Engine, + EncryptSlot, + &ZeroKey, + &ZeroIv, + NV_TRUE, + pAesHwCtxt); + + // Setup SSK Key table for encryption + NVDDK_AES_CHECK_INTERFACE_FUNC(pAesHwCtxt, Engine, AesHwSetKeyAndIv); + pAesHwCtxt->ppEngineCaps[Engine]->pAesInterf->AesHwSetKeyAndIv( + Engine, + DecryptSlot, + &ZeroKey, + &ZeroIv, + NV_FALSE, + pAesHwCtxt); + + // Select Encrypt Key slot + NVDDK_AES_CHECK_INTERFACE_FUNC(pAesHwCtxt, Engine, AesHwSelectKeyIvSlot); + pAesHwCtxt->ppEngineCaps[Engine]->pAesInterf->AesHwSelectKeyIvSlot(Engine, EncryptSlot, pAesHwCtxt); + + // Set the Zero IV for test data + NVDDK_AES_CHECK_INTERFACE_FUNC(pAesHwCtxt, Engine, AesHwSetIv); + NV_CHECK_ERROR_CLEANUP(pAesHwCtxt->ppEngineCaps[Engine]->pAesInterf->AesHwSetIv( + Engine, + EncryptSlot, + &ZeroIv, + pAesHwCtxt)); + + // Process the buffer for encryption + NVDDK_AES_CHECK_INTERFACE_FUNC(pAesHwCtxt, Engine, AesHwStartEngine); + NV_CHECK_ERROR_CLEANUP(pAesHwCtxt->ppEngineCaps[Engine]->pAesInterf->AesHwStartEngine( + Engine, + NvDdkAesConst_BlockLengthBytes, + s_GoldData, + NV_TRUE, + NvDdkAesOperationalMode_Cbc, + EncryptBuffer2, + pAesHwCtxt)); + + // Select Decrypt Key slot + NVDDK_AES_CHECK_INTERFACE_FUNC(pAesHwCtxt, Engine, AesHwSelectKeyIvSlot); + pAesHwCtxt->ppEngineCaps[Engine]->pAesInterf->AesHwSelectKeyIvSlot(Engine, DecryptSlot, pAesHwCtxt); + + // Set the Zero IV for test data + NVDDK_AES_CHECK_INTERFACE_FUNC(pAesHwCtxt, Engine, AesHwSetIv); + NV_CHECK_ERROR_CLEANUP(pAesHwCtxt->ppEngineCaps[Engine]->pAesInterf->AesHwSetIv( + Engine, + DecryptSlot, + &ZeroIv, + pAesHwCtxt)); + + // Process the buffer for encryption + NVDDK_AES_CHECK_INTERFACE_FUNC(pAesHwCtxt, Engine, AesHwStartEngine); + NV_CHECK_ERROR_CLEANUP(pAesHwCtxt->ppEngineCaps[Engine]->pAesInterf->AesHwStartEngine( + Engine, + NvDdkAesConst_BlockLengthBytes, + s_GoldData, + NV_FALSE, + NvDdkAesOperationalMode_Cbc, + DecryptBuffer2, + pAesHwCtxt)); + + // Clear the IV in the engine before we leave + NVDDK_AES_CHECK_INTERFACE_FUNC(pAesHwCtxt, Engine, AesHwClearIv); + pAesHwCtxt->ppEngineCaps[Engine]->pAesInterf->AesHwClearIv(Engine, EncryptSlot, pAesHwCtxt); + pAesHwCtxt->ppEngineCaps[Engine]->pAesInterf->AesHwClearIv(Engine, DecryptSlot, pAesHwCtxt); + + // Clear the DMA buffer before we leave from this operation. + NvOsMemset(pAesHwCtxt->pDmaVirAddr[Engine], 0, AES_HW_DMA_BUFFER_SIZE_BYTES); + + // Check encrypt and decrypt output is same before and after zero key set to SSK + // If both encrypt and decrypt data match then SSK lock is OK + for (i = 0; i < NvDdkAesConst_BlockLengthBytes; i++) + { + if ((EncryptBuffer1[i] != EncryptBuffer2[i]) || (DecryptBuffer1[i] != DecryptBuffer2[i])) + goto fail; + } + + AesCoreReleaseHwAccess(); + NvOsMutexUnlock(gs_hAesCoreEngineMutex); + return NV_TRUE; + +fail: + // Clear the DMA buffer before we leave from this operation. + NvOsMemset(pAesHwCtxt->pDmaVirAddr[Engine], 0, AES_HW_DMA_BUFFER_SIZE_BYTES); + AesCoreReleaseHwAccess(); + NvOsMutexUnlock(gs_hAesCoreEngineMutex); + return NV_FALSE; +} + +/** + * Add the Busy hints to boost or reduce the CPU, System and EMC frequencies. + * + * @param hRmDevice RM device handle. + * @param PowerClientId The client ID obtained during Power registration. + * @param IsDfsOn Indicator to boost the frequency, if set to NV_TRUE. Cancel the + * DFS busy hint if set to NV_FALSE. + * + * @retval NvSuccess if busy hint request completed successfully. + * @retval NvError_NotSupported if DFS is disabled. + * @retval NvError_BadValue if specified client ID is not registered. + * @retval NvError_InsufficientMemory if failed to allocate memory for busy hints. + */ +NvError AesCoreDfsBusyHint(const NvRmDeviceHandle hRmDevice, const NvU32 PowerClientId, const NvBool IsDfsOn) +{ + #define AES_EMC_BOOST_FREQ_KHZ 100000 + #define AES_SYS_BOOST_FREQ_KHZ 100000 + + NvRmDfsBusyHint AesBusyHintOn[] = + { + {NvRmDfsClockId_Emc, NV_WAIT_INFINITE, AES_EMC_BOOST_FREQ_KHZ, NV_TRUE}, + {NvRmDfsClockId_System, NV_WAIT_INFINITE, AES_SYS_BOOST_FREQ_KHZ, NV_TRUE} + }; + + NvRmDfsBusyHint AesBusyHintOff[] = + { + {NvRmDfsClockId_Emc, 0, 0, NV_TRUE}, + {NvRmDfsClockId_System, 0, 0, NV_TRUE} + }; + + NV_ASSERT(hRmDevice); + + if (IsDfsOn) + { + return NvRmPowerBusyHintMulti( + hRmDevice, + PowerClientId, + AesBusyHintOn, + NV_ARRAY_SIZE(AesBusyHintOn), + NvRmDfsBusyHintSyncMode_Async); + } + else + { + return NvRmPowerBusyHintMulti( + hRmDevice, + PowerClientId, + AesBusyHintOff, + NV_ARRAY_SIZE(AesBusyHintOff), + NvRmDfsBusyHintSyncMode_Async); + } +} + +/** + * Populate the structure for AES context with the engine base address. + * + * @param hRmDevice Rm device handle. + * @param pAesHwCtxt Pointer to AES H/W context. + * + * @retval NvSuccess if successfully completed. + * + */ +NvError AesCoreInitializeEngineSpace(const NvRmDeviceHandle hRmDevice, AesHwContext *const pAesHwCtxt) +{ + NvError e = NvSuccess; + AesHwEngine Engine; + + NV_ASSERT(hRmDevice); + NV_ASSERT(pAesHwCtxt); + + NvOsMutexLock(gs_hAesCoreEngineMutex); + + for (Engine = AesHwEngine_A; Engine < AesHwEngine_Num; Engine++) + { + switch (Engine) + { + case AesHwEngine_A: + // Get the controller base address + NvRmModuleGetBaseAddress( + hRmDevice, + NVRM_MODULE_ID(NvRmModuleID_Vde, 0), + &pAesHwCtxt->PhysAdr[Engine], + &pAesHwCtxt->BankSize[Engine]); + break; + case AesHwEngine_B: + // Get the controller base address + NvRmModuleGetBaseAddress( + hRmDevice, + NVRM_MODULE_ID(NvRmModuleID_BseA, 0), + &pAesHwCtxt->PhysAdr[Engine], + &pAesHwCtxt->BankSize[Engine]); + break; + default: + break; + } + + // Map the physical memory to virtual memory + NV_CHECK_ERROR_CLEANUP(NvRmPhysicalMemMap( + pAesHwCtxt->PhysAdr[Engine], + pAesHwCtxt->BankSize[Engine], + NVOS_MEM_READ_WRITE, + NvOsMemAttribute_Uncached, + (void **)&pAesHwCtxt->pVirAdr[Engine])); + } + + NvOsMutexUnlock(gs_hAesCoreEngineMutex); + return NvSuccess; + +fail: + NvOsMutexUnlock(gs_hAesCoreEngineMutex); + return e; +} + +/** + * Unmap all engine space. + * + * @param pAesHwCtxt Pointer to AES H/W context. + * + * @retval None. + * + */ +void AesCoreDeInitializeEngineSpace(const AesHwContext *const pAesHwCtxt) +{ + AesHwEngine Engine; + + NV_ASSERT(pAesHwCtxt); + + NvOsMutexLock(gs_hAesCoreEngineMutex); + + // Clean up resources + for (Engine = AesHwEngine_A; Engine < AesHwEngine_Num; Engine++) + { + // UnMap the virtual Address + NvRmPhysicalMemUnmap(pAesHwCtxt->pVirAdr[Engine], pAesHwCtxt->BankSize[Engine]); + } + + NvOsMutexUnlock(gs_hAesCoreEngineMutex); +} + +/** + * Find the unused key slot. + * + * @param pAesCoreEngine Pointer to AES core engine. + * @param pEngine Pointer to the engine. + * @param pKeySlot Pointer to the key slot. + * + * @retval NvSuccess if successfully completed. + * @retval NvError_AlreadyAllocated if all slots are allocated. + */ +NvError +AesCoreGetFreeSlot( + const AesCoreEngine *const pAesCoreEngine, + AesHwEngine *const pEngine, + AesHwKeySlot *const pKeySlot) +{ + AesHwEngine Engine; + AesHwKeySlot KeySlot; + const AesHwContext *pAesHwCtxt; + + NV_ASSERT(pAesCoreEngine); + NV_ASSERT(pEngine); + NV_ASSERT(pKeySlot); + + NvOsMutexLock(gs_hAesCoreEngineMutex); + + // Get the AES H/W context + pAesHwCtxt = &pAesCoreEngine->AesHwCtxt; + + // Get the free slot + for (Engine = AesHwEngine_A; Engine < AesHwEngine_Num; Engine++) + { + NV_ASSERT(pAesHwCtxt->ppEngineCaps); + NV_ASSERT(pAesHwCtxt->ppEngineCaps[Engine]); + for (KeySlot = AesHwKeySlot_0; + KeySlot < (NvU32)(pAesHwCtxt->ppEngineCaps[Engine]->NumSlotsSupported); + KeySlot++) + { + if (!pAesCoreEngine->IsKeySlotUsed[Engine][KeySlot]) + { + *pEngine = Engine; + *pKeySlot = KeySlot; + + NvOsMutexUnlock(gs_hAesCoreEngineMutex); + return NvSuccess; + } + } + } + + NvOsMutexUnlock(gs_hAesCoreEngineMutex); + return NvError_AlreadyAllocated; +} + +/** + * Init AES engine. + * + * @param hRmDevice Resource Manager Handle. + * + * @retval NvSuccess if successful. + */ +NvError AesCoreInitEngine(const NvRmDeviceHandle hRmDevice) +{ + NvError e = NvSuccess; + AesHwContext *pAesHwCtxt = NULL; + AesHwEngine Engine; + + NV_ASSERT(hRmDevice); + + gs_pAesCoreEngine = NvOsAlloc(sizeof(AesCoreEngine)); + if (NULL == gs_pAesCoreEngine) + return NvError_InsufficientMemory; + + // Clear the memory initially + NvOsMemset(gs_pAesCoreEngine, 0, sizeof(AesCoreEngine)); + + // Get the AES H/W context + pAesHwCtxt = &gs_pAesCoreEngine->AesHwCtxt; + + // Store the RM handle for future use + pAesHwCtxt->hRmDevice = hRmDevice; + + pAesHwCtxt->ppEngineCaps = (AesHwCapabilities **)NvOsAlloc(sizeof(AesHwCapabilities) * AesHwEngine_Num); + if (NULL == pAesHwCtxt->ppEngineCaps) + { + NvOsFree(gs_pAesCoreEngine); + gs_pAesCoreEngine = NULL; + return NvError_InsufficientMemory; + } + AesCoreGetCapabilities(hRmDevice, pAesHwCtxt->ppEngineCaps); + + for (Engine = AesHwEngine_A; Engine < AesHwEngine_Num; Engine++) + { + NV_ASSERT(pAesHwCtxt->ppEngineCaps[Engine]); + pAesHwCtxt->KeyTableSize[Engine] = pAesHwCtxt->ppEngineCaps[Engine]->HwKeySchedLengthBytes; + } + + NV_CHECK_ERROR(AesCoreInitializeEngineSpace(hRmDevice, pAesHwCtxt)); + + // Allocate memories required for H/W operation + NV_CHECK_ERROR(AesCoreAllocateRmMemory(pAesHwCtxt)); + + // Create mutex to guard the H/W engine + for (Engine = AesHwEngine_A; Engine < AesHwEngine_Num; Engine++) + { + NV_CHECK_ERROR(NvOsMutexCreate(&pAesHwCtxt->Mutex[Engine])); + + // Register with Power Manager + gs_pAesCoreEngine->RmPwrClientId[Engine] = NVRM_POWER_CLIENT_TAG('A','E','S','1'); + + NV_CHECK_ERROR(NvRmPowerRegister(hRmDevice, NULL, &gs_pAesCoreEngine->RmPwrClientId[Engine])); + + // Enable the voltage + NV_CHECK_ERROR(NvRmPowerVoltageControl( + hRmDevice, + (AesHwEngine_A == Engine) ? + NvRmModuleID_Vde : NvRmModuleID_BseA, + gs_pAesCoreEngine->RmPwrClientId[Engine], + NvRmVoltsUnspecified, + NvRmVoltsUnspecified, + NULL, + 0, + NULL)); + + // Enable clock + NV_CHECK_ERROR(NvRmPowerModuleClockControl( + hRmDevice, + (AesHwEngine_A == Engine) ? + NvRmModuleID_Vde : NvRmModuleID_BseA, + gs_pAesCoreEngine->RmPwrClientId[Engine], + NV_TRUE)); + } + + // Request the H/W semaphore before accessing the AES H/W + AesCoreRequestHwAccess(); + + // Reset the BSEV and BSEA engines + NvRmModuleReset(hRmDevice, NvRmModuleID_Vde); + NvRmModuleReset(hRmDevice, NvRmModuleID_BseA); + + for (Engine = AesHwEngine_A; Engine < AesHwEngine_Num; Engine++) + { + NVDDK_AES_CHECK_INTERFACE(pAesHwCtxt, Engine); + NVDDK_AES_CHECK_INTERFACE_FUNC(pAesHwCtxt, Engine, AesHwIsEngineDisabled); + + gs_pAesCoreEngine->IsEngineDisabled = + pAesHwCtxt->ppEngineCaps[Engine]->pAesInterf->AesHwIsEngineDisabled(pAesHwCtxt, Engine); + } + + // If engine is not disabled then set the SBK & SSK + if (!gs_pAesCoreEngine->IsEngineDisabled) + { + // The slots already dedicated don't depend on which engine is being used but + // on the capabilities the engines can provide. Basic assumption: both engines have + // same capabilities. + NVDDK_AES_CHECK_INTERFACE_FUNC(pAesHwCtxt, 0, AesGetUsedSlots); + pAesHwCtxt->ppEngineCaps[0]->pAesInterf->AesHwGetUsedSlots(gs_pAesCoreEngine); + } + + // Get the Iv read permissions + for (Engine = AesHwEngine_A; Engine < AesHwEngine_Num; Engine++) + { + NVDDK_AES_CHECK_INTERFACE(pAesHwCtxt, Engine); + NVDDK_AES_CHECK_INTERFACE_FUNC(pAesHwCtxt, Engine, GetIvReadPermissions); + pAesHwCtxt->ppEngineCaps[Engine]->pAesInterf->AesHwGetIvReadPermissions(Engine, pAesHwCtxt); + } + + // Release the H/W semaphore + AesCoreReleaseHwAccess(); + + // Disable clocks after AES init + for (Engine = AesHwEngine_A; Engine < AesHwEngine_Num; Engine++) + { + // Disable clock + NV_CHECK_ERROR(NvRmPowerModuleClockControl( + pAesHwCtxt->hRmDevice, + (AesHwEngine_A == Engine) ? + NvRmModuleID_Vde : NvRmModuleID_BseA, + gs_pAesCoreEngine->RmPwrClientId[Engine], + NV_FALSE)); + + // Disable the voltage + NV_CHECK_ERROR(NvRmPowerVoltageControl( + pAesHwCtxt->hRmDevice, + (AesHwEngine_A == Engine) ? + NvRmModuleID_Vde : NvRmModuleID_BseA, + gs_pAesCoreEngine->RmPwrClientId[Engine], + NvRmVoltsOff, + NvRmVoltsOff, + NULL, + 0, + NULL)); + } + return e; +} + +/** + * Free up resources. + * + * @retval None. + */ +void AesCoreFreeUpEngine(AesCoreEngine *const pAesCoreEngine) +{ + AesHwEngine Engine; + AesHwContext *pAesHwCtxt; + + NV_ASSERT(pAesCoreEngine); + + // Get the AES H/W context + pAesHwCtxt = &pAesCoreEngine->AesHwCtxt; + + AesCoreDeInitializeEngineSpace(pAesHwCtxt); + + // Deallocate the memory + AesCoreDeAllocateRmMemory(pAesHwCtxt); + + // Destroy mutex + for (Engine = AesHwEngine_A; Engine < AesHwEngine_Num; Engine++) + { + NvOsMutexDestroy(pAesHwCtxt->Mutex[Engine]); + // Unregister driver from Power Manager + NvRmPowerUnRegister(pAesHwCtxt->hRmDevice, pAesCoreEngine->RmPwrClientId[Engine]); + if (pAesHwCtxt->ppEngineCaps[Engine]->pAesInterf) + { + NvOsFree(pAesHwCtxt->ppEngineCaps[Engine]->pAesInterf); + pAesHwCtxt->ppEngineCaps[Engine]->pAesInterf = NULL; + } + } + if (pAesHwCtxt->ppEngineCaps) + { + NvOsFree(pAesHwCtxt->ppEngineCaps); + pAesHwCtxt->ppEngineCaps = NULL; + } +} + +/** + * Power up the AES core engine. + * + * @param pAesCoreEngine Pointer to the AesCoreEngine argument. + * + * @retval None. + */ +void AesCorePowerUp(const AesCoreEngine *const pAesCoreEngine) +{ + AesHwEngine Engine; + const AesHwContext *pAesHwCtxt; + + NV_ASSERT(pAesCoreEngine); + + // Get the Aes Hw context + pAesHwCtxt = &pAesCoreEngine->AesHwCtxt; + + for (Engine = AesHwEngine_A; Engine < AesHwEngine_Num; Engine++) + { + // DFS busy hints On + NV_ASSERT_SUCCESS(AesCoreDfsBusyHint(pAesHwCtxt->hRmDevice, pAesCoreEngine->RmPwrClientId[Engine], NV_TRUE)); + + // Enable the voltage + NV_ASSERT_SUCCESS(NvRmPowerVoltageControl( + pAesHwCtxt->hRmDevice, + (AesHwEngine_A == Engine) ? NvRmModuleID_Vde : NvRmModuleID_BseA, + pAesCoreEngine->RmPwrClientId[Engine], + NvRmVoltsUnspecified, + NvRmVoltsUnspecified, + NULL, + 0, + NULL)); + + // Enable clock + NV_ASSERT_SUCCESS(NvRmPowerModuleClockControl( + pAesHwCtxt->hRmDevice, + (AesHwEngine_A == Engine) ? NvRmModuleID_Vde : NvRmModuleID_BseA, + pAesCoreEngine->RmPwrClientId[Engine], + NV_TRUE)); + } +} + +/** + * Power down the AES core engine. + * + * @param pAesCoreEngine Pointer to the AesCoreEngine argument. + * + * @retval None. + */ +void AesCorePowerDown(const AesCoreEngine *const pAesCoreEngine) +{ + AesHwEngine Engine; + const AesHwContext *pAesHwCtxt; + + NV_ASSERT(pAesCoreEngine); + + // Get the AES H/W context + pAesHwCtxt = &pAesCoreEngine->AesHwCtxt; + + for (Engine = AesHwEngine_A; Engine < AesHwEngine_Num; Engine++) + { + // Disable clock + NV_ASSERT_SUCCESS(NvRmPowerModuleClockControl( + pAesHwCtxt->hRmDevice, + (AesHwEngine_A == Engine) ? NvRmModuleID_Vde : NvRmModuleID_BseA, + pAesCoreEngine->RmPwrClientId[Engine], + NV_FALSE)); + + // Disable the voltage + NV_ASSERT_SUCCESS(NvRmPowerVoltageControl( + pAesHwCtxt->hRmDevice, + (AesHwEngine_A == Engine) ? NvRmModuleID_Vde : NvRmModuleID_BseA, + pAesCoreEngine->RmPwrClientId[Engine], + NvRmVoltsOff, + NvRmVoltsOff, + NULL, + 0, + NULL)); + + // DFS busy hints Off + NV_ASSERT_SUCCESS(AesCoreDfsBusyHint(pAesHwCtxt->hRmDevice, pAesCoreEngine->RmPwrClientId[Engine], NV_FALSE)); + } +} + +/** + * Process the buffers for encryption or decryption. + * + * @param SkipOffset Skip initial SkipOffset bytes of SrcBuffer before beginning cipher. + * @param SrcBufferSize Size of src buffer in bytes. + * @param DestBufferSize Size of dest buffer in bytes. + * @param pAesClient Pointer to AES client. + * @param pSrcBuffer Pointer to src buffer. + * @param pDestBuffer Pointer to dest buffer. + * + * @retval NvSuccess if successfully completed. + */ +NvError +AesCoreProcessBuffer( + const NvU32 SkipOffset, + const NvU32 SrcBufferSize, + const NvU32 DestBufferSize, + NvDdkAes *const pAesClient, + const NvU8 *pSrcBuffer, + NvU8 *pDestBuffer) +{ + NvError e = NvSuccess; + AesHwContext *pAesHwCtxt = NULL; + AesHwEngine Engine; + AesHwKeySlot KeySlot; + NvU32 TotalBytesToProcess = 0; + NvU32 BytesToProcess = 0; + + NV_ASSERT(pAesClient); + NV_ASSERT(pSrcBuffer); + NV_ASSERT(pDestBuffer); + + NVDDK_AES_CHECK_USER_IDENTITY; + + // Check type of operation supported for the process buffer + switch (pAesClient->OpMode) + { + case NvDdkAesOperationalMode_Cbc: + case NvDdkAesOperationalMode_Ecb: + case NvDdkAesOperationalMode_AnsiX931: + break; + default: + return NvError_InvalidState; + } + + if (DestBufferSize % NvDdkAesConst_BlockLengthBytes) + return NvError_InvalidSize; + + // Check if client has already assigned key for this process if not return + if ((NvDdkAesKeyType_Invalid == pAesClient->KeyType) || (pAesClient->KeyType >= NvDdkAesKeyType_Num)) + return NvError_InvalidState; + + // Get the AES H/W context + NV_ASSERT(pAesClient->pAesCoreEngine); + pAesHwCtxt = &pAesClient->pAesCoreEngine->AesHwCtxt; + + TotalBytesToProcess = DestBufferSize; + + NvOsMutexLock(gs_hAesCoreEngineMutex); + + NVDDK_AES_CHECK_INTERFACE(pAesHwCtxt, pAesClient->Engine); + + while (TotalBytesToProcess) + { + // Request the H/W semaphore before accesing the AES H/W + AesCoreRequestHwAccess(); + + // In the bootloader version entire buffer is processed for AES operation +#if NV_OAL + BytesToProcess = TotalBytesToProcess; + TotalBytesToProcess = 0; +#else + // At OS level only AES_HW_MAX_PROCESS_SIZE_BYTES will be processed. + // Once the AES H/W lock is acquired again then remaining bytes or maximum of + // AES_HW_MAX_PROCESS_SIZE_BYTES will be processed. + if (TotalBytesToProcess > AES_HW_MAX_PROCESS_SIZE_BYTES) + BytesToProcess = AES_HW_MAX_PROCESS_SIZE_BYTES; + else + BytesToProcess = TotalBytesToProcess; +#endif + + if ((!pAesClient->IsDedicatedSlot) && (NvDdkAesKeyType_UserSpecified == pAesClient->KeyType)) + { + // If it is not dedicated slot, unwrap the key + NvU8 UnWrappedRFCIv[AES_RFC_IV_LENGTH_BYTES]; + + NV_CHECK_ERROR_CLEANUP(AesCoreGetFreeSlot(pAesClient->pAesCoreEngine, &Engine, &KeySlot)); + pAesClient->Engine = Engine; + pAesClient->KeySlot = KeySlot; + + // Unwrap the key + NV_CHECK_ERROR_CLEANUP(AesCoreUnWrapKey( + pAesClient, + pAesClient->Key, + pAesClient->WrappedIv, + pAesHwCtxt->pKeyTableVirAddr[Engine] + pAesHwCtxt->KeyTableSize[Engine], + UnWrappedRFCIv)); + // Check whether the key unwrap is success or not by comparing the unwrapped RFC IV with original RFC IV + if (NvOsMemcmp(UnWrappedRFCIv, gs_OriginalIV, sizeof(gs_OriginalIV))) + { + // Unwrap key failed + e = NvError_AesKeyUnWrapFailed; + goto fail; + } + + // Setup Key table + NVDDK_AES_CHECK_INTERFACE_FUNC(pAesHwCtxt, pAesClient->Engine, AesHwSetKeyAndIv); + pAesHwCtxt->ppEngineCaps[pAesClient->Engine]->pAesInterf->AesHwSetKeyAndIv( + pAesClient->Engine, + pAesClient->KeySlot, + (AesHwKey *)(pAesHwCtxt->pKeyTableVirAddr[Engine] + pAesHwCtxt->KeyTableSize[Engine]), + (AesHwIv *)pAesClient->Iv, + pAesClient->IsEncryption, + pAesHwCtxt); + + // Memset the local variable to zeros where the key is stored + NvOsMemset( + (pAesHwCtxt->pKeyTableVirAddr[Engine] + pAesHwCtxt->KeyTableSize[Engine]), + 0, + NvDdkAesKeySize_128Bit); + } + else + { + // Select Key slot + NVDDK_AES_CHECK_INTERFACE_FUNC(pAesHwCtxt, pAesClient->Engine, AesHwSelectKeyIvSlot); + pAesHwCtxt->ppEngineCaps[pAesClient->Engine]->pAesInterf->AesHwSelectKeyIvSlot( + pAesClient->Engine, + pAesClient->KeySlot, + pAesHwCtxt); + + // Set the last IV operated with this client + NVDDK_AES_CHECK_INTERFACE_FUNC(pAesHwCtxt, pAesClient->Engine, AesHwSetIv); + NV_CHECK_ERROR_CLEANUP(pAesHwCtxt->ppEngineCaps[pAesClient->Engine]->pAesInterf->AesHwSetIv( + pAesClient->Engine, + pAesClient->KeySlot, + (AesHwIv *)pAesClient->Iv, + pAesHwCtxt)); + } + + // Process the buffer for encryption/decryption + NVDDK_AES_CHECK_INTERFACE_FUNC(pAesHwCtxt, pAesClient->Engine, AesHwStartEngine); + e = pAesHwCtxt->ppEngineCaps[pAesClient->Engine]->pAesInterf->AesHwStartEngine( + pAesClient->Engine, + BytesToProcess, + pSrcBuffer, + pAesClient->IsEncryption, + pAesClient->OpMode, + pDestBuffer, + pAesHwCtxt); + if (NvSuccess != e) + { + // If the key is user specified and not in dedicated slot, clear it + if ((!pAesClient->IsDedicatedSlot) && (NvDdkAesKeyType_UserSpecified == pAesClient->KeyType)) + { + // Clear key + NVDDK_AES_CHECK_INTERFACE_FUNC(pAesHwCtxt, pAesClient->Engine, AesHwClearKeyAndIv); + pAesHwCtxt->ppEngineCaps[pAesClient->Engine]->pAesInterf->AesHwClearKeyAndIv( + pAesClient->Engine, + pAesClient->KeySlot, + pAesHwCtxt); + } + goto fail; + } + + // Store the last IV operated with this client + NVDDK_AES_CHECK_INTERFACE_FUNC(pAesHwCtxt, pAesClient->Engine, AesHwGetIv); + pAesHwCtxt->ppEngineCaps[pAesClient->Engine]->pAesInterf->AesHwGetIv( + pAesHwCtxt, + pAesClient->Engine, + pAesClient->KeySlot, + (AesHwIv *)pAesClient->Iv); + + // If the key is user specified and not in dedicated slot, clear it + if ((!pAesClient->IsDedicatedSlot) && (NvDdkAesKeyType_UserSpecified == pAesClient->KeyType)) + { + // Clear key + NVDDK_AES_CHECK_INTERFACE_FUNC(pAesHwCtxt, pAesClient->Engine, AesHwClearKeyAndIv); + pAesHwCtxt->ppEngineCaps[pAesClient->Engine]->pAesInterf->AesHwClearKeyAndIv( + pAesClient->Engine, + pAesClient->KeySlot, + pAesHwCtxt); + } + else + { + // Clear the IV in the engine + NVDDK_AES_CHECK_INTERFACE_FUNC(pAesHwCtxt, pAesClient->Engine, AesHwClearIv); + pAesHwCtxt->ppEngineCaps[pAesClient->Engine]->pAesInterf->AesHwClearIv( + pAesClient->Engine, + pAesClient->KeySlot, + pAesHwCtxt); + } + +#if !NV_OAL + pSrcBuffer += BytesToProcess; + pDestBuffer += BytesToProcess; + TotalBytesToProcess -= BytesToProcess; +#endif + + // Release the H/W semaphore + AesCoreReleaseHwAccess(); + } + + // Clear the DMA buffer before we leave from this operation + NvOsMemset(pAesHwCtxt->pDmaVirAddr[pAesClient->Engine], 0, AES_HW_DMA_BUFFER_SIZE_BYTES); + NvOsMutexUnlock(gs_hAesCoreEngineMutex); + return NvSuccess; + +fail: + // Release the H/W semaphore + AesCoreReleaseHwAccess(); + // Clear the DMA buffer before we leave from this operation + NvOsMemset(pAesHwCtxt->pDmaVirAddr[pAesClient->Engine], 0, AES_HW_DMA_BUFFER_SIZE_BYTES); + NvOsMutexUnlock(gs_hAesCoreEngineMutex); + return e; +} + +/** + * Clear the User Key. + * + * @param pAesClient Pointer to AES client. + * + * @retval NvSuccess if User key is cleared, NV_FALSE otherwise. + */ +NvError AesCoreClearUserKey(const NvDdkAes *const pAesClient) +{ + AesHwContext *pAesHwCtxt = NULL; + NvBool IsSuccess = NV_TRUE; + + NV_ASSERT(pAesClient); + + NvOsMutexLock(gs_hAesCoreEngineMutex); + + // Get the AES H/W context + NV_ASSERT(pAesClient->pAesCoreEngine); + pAesHwCtxt = &pAesClient->pAesCoreEngine->AesHwCtxt; + + NVDDK_AES_CHECK_INTERFACE(pAesHwCtxt, pAesClient->Engine); + + AesCoreRequestHwAccess(); + + // Clear the key and IV + NVDDK_AES_CHECK_INTERFACE_FUNC(pAesHwCtxt, pAesClient->Engine, AesHwClearKeyAndIv); + pAesHwCtxt->ppEngineCaps[pAesClient->Engine]->pAesInterf->AesHwClearKeyAndIv( + pAesClient->Engine, + pAesClient->KeySlot, + pAesHwCtxt); + + AesCoreReleaseHwAccess(); + + IsSuccess = AesCoreIsUserKeyCleared(pAesClient->Engine, pAesClient->KeySlot, pAesHwCtxt); + + NvOsMutexUnlock(gs_hAesCoreEngineMutex); + return IsSuccess; +} + +/** + * Check the user key clear by encrypting the known data. + * + * @param Engine Engine on which encryption need to be performed. + * @param KeySlot Key slot where encrypt key is located. + * @param pAesHw Pointer to AES H/W context. + * + * @retval NV_TRUE if encryption and decryption is successfully done else NV_FALSE + */ +NvBool +AesCoreIsUserKeyCleared( + const AesHwEngine Engine, + const AesHwKeySlot KeySlot, + AesHwContext *const pAesHwCtxt) +{ + NvError e = NvSuccess; + AesHwIv ZeroIv; + NvU32 i; + + // Known Good data + static NvU8 s_GoldData[NvDdkAesConst_BlockLengthBytes] = + { + 0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, + 0x0C, 0x0D, 0x0E, 0x0F + }; + + // Encrypted data for above known data with Zero key and Zero IV + static NvU8 s_EncryptDataWithZeroKeyTable[NvDdkAesConst_BlockLengthBytes] = + { + 0x7A, 0xCA, 0x0F, 0xD9, + 0xBC, 0xD6, 0xEC, 0x7C, + 0x9F, 0x97, 0x46, 0x66, + 0x16, 0xE6, 0xA2, 0x82 + }; + + // Encrypted data for above known data with Zero key and Zero IV + static NvU8 s_EncryptDataWithZeroKeySchedule[NvDdkAesConst_BlockLengthBytes] = + { + 0x18, 0x9D, 0x19, 0xEA, + 0xDB, 0xA7, 0xE3, 0x0E, + 0xD9, 0x72, 0x80, 0x8F, + 0x3F, 0x2B, 0xA0, 0x30 + }; + + NvU8 *pEncryptData; + NvU8 EncryptBuffer[NvDdkAesConst_BlockLengthBytes]; + + NvOsMutexLock(gs_hAesCoreEngineMutex); + + NVDDK_AES_CHECK_INTERFACE(pAesHwCtxt, Engine); + + if (pAesHwCtxt->ppEngineCaps[Engine]->IsHwKeySchedGenSupported) + pEncryptData = s_EncryptDataWithZeroKeyTable; + else + pEncryptData = s_EncryptDataWithZeroKeySchedule; + + NvOsMemset(EncryptBuffer, 0, NvDdkAesConst_BlockLengthBytes); + NvOsMemset(&ZeroIv, 0, sizeof(AesHwIv)); + + AesCoreRequestHwAccess(); + + // Select Encrypt Key slot + NVDDK_AES_CHECK_INTERFACE_FUNC(pAesHwCtxt, Engine, AesHwSelectKeyIvSlot); + pAesHwCtxt->ppEngineCaps[Engine]->pAesInterf->AesHwSelectKeyIvSlot(Engine, KeySlot, pAesHwCtxt); + + // Set the Zero IV for test data + NVDDK_AES_CHECK_INTERFACE_FUNC(pAesHwCtxt, Engine, AesHwSetIv); + NV_CHECK_ERROR_CLEANUP(pAesHwCtxt->ppEngineCaps[Engine]->pAesInterf->AesHwSetIv( + Engine, + KeySlot, + &ZeroIv, + pAesHwCtxt)); + + // Process the buffer for encryption + NVDDK_AES_CHECK_INTERFACE_FUNC(pAesHwCtxt, Engine, AesHwStartEngine); + NV_CHECK_ERROR_CLEANUP(pAesHwCtxt->ppEngineCaps[Engine]->pAesInterf->AesHwStartEngine( + Engine, + NvDdkAesConst_BlockLengthBytes, + s_GoldData, + NV_TRUE, + NvDdkAesOperationalMode_Cbc, + EncryptBuffer, + pAesHwCtxt)); + + // Clear the IV in the engine before we leave + NVDDK_AES_CHECK_INTERFACE_FUNC(pAesHwCtxt, Engine, AesHwClearIv); + pAesHwCtxt->ppEngineCaps[Engine]->pAesInterf->AesHwClearIv(Engine, KeySlot, pAesHwCtxt); + + AesCoreReleaseHwAccess(); + + // Clear the DMA buffer before we leave from this operation + NvOsMemset(pAesHwCtxt->pDmaVirAddr[Engine], 0, AES_HW_DMA_BUFFER_SIZE_BYTES); + + for (i = 0; i < NvDdkAesConst_BlockLengthBytes; i++) + { + if (pEncryptData[i] != EncryptBuffer[i]) + goto fail; + } + + NvOsMutexUnlock(gs_hAesCoreEngineMutex); + return NV_TRUE; + +fail: + // Clear the DMA buffer before we leave from this operation + NvOsMemset(pAesHwCtxt->pDmaVirAddr[Engine], 0, AES_HW_DMA_BUFFER_SIZE_BYTES); + NvOsMutexUnlock(gs_hAesCoreEngineMutex); + return NV_FALSE; +} + +/** + * Return the AES module capabilities. + * + * @param hRmDevice Rm Device handle. + * @param ppCaps Pointer to pointer to capbilities structure. + * + * @retval NvSuccess if capabilities could be returned successfully. + * + */ +NvError AesCoreGetCapabilities(const NvRmDeviceHandle hRmDevice, AesHwCapabilities **const ppCaps) +{ + NvError e = NvSuccess; + + static AesHwCapabilities s_Caps1; + static AesHwCapabilities s_Caps2; + + static NvRmModuleCapability s_EngineA_Caps[] = + { + {1, 0, 0, &s_Caps1}, + {1, 1, 0, &s_Caps1}, + {1, 2, 0, &s_Caps2}, + {1, 3, 0, &s_Caps2} + }; + + static NvRmModuleCapability s_engineB_caps[] = + { + {1, 0, 0, &s_Caps1}, + {1, 1, 0, &s_Caps2}, + {1, 2, 0, &s_Caps2} + }; + + NV_ASSERT(hRmDevice); + NV_ASSERT(ppCaps); + + NvOsMemset(&s_Caps1, 0, sizeof(s_Caps1)); + NvOsMemset(&s_Caps2, 0, sizeof(s_Caps2)); + + s_Caps1.IsHashSupported = NV_FALSE; + s_Caps1.IsHwKeySchedGenSupported = NV_FALSE; + s_Caps1.MinBufferAlignment = 16; + s_Caps1.MinKeyTableAlignment = 256; + s_Caps1.NumSlotsSupported = AesHwKeySlot_Num; + s_Caps1.pAesInterf = NULL; + + s_Caps2.IsHashSupported = NV_FALSE; + s_Caps2.IsHwKeySchedGenSupported = NV_TRUE; + s_Caps2.HwKeySchedLengthBytes = 80; + s_Caps2.MinBufferAlignment = 16; + s_Caps2.MinKeyTableAlignment = 4; + s_Caps2.NumSlotsSupported = AesHwKeySlot_NumExt; + s_Caps2.pAesInterf = NULL; + + NV_CHECK_ERROR_CLEANUP(NvRmModuleGetCapabilities( + hRmDevice, + NvRmModuleID_Vde, + s_EngineA_Caps, + NV_ARRAY_SIZE(s_EngineA_Caps), + (void **)&(ppCaps[AesHwEngine_A]))); + + if (ppCaps[AesHwEngine_A] == &s_Caps2) + { + if (NULL == s_Caps2.pAesInterf) + { + s_Caps2.pAesInterf = NvOsAlloc(sizeof(AesHwInterface)); + if (NULL == s_Caps2.pAesInterf) + goto fail; + NvAesIntfAp20GetHwInterface(s_Caps2.pAesInterf); + } + } + + NV_CHECK_ERROR_CLEANUP(NvRmModuleGetCapabilities( + hRmDevice, + NvRmModuleID_BseA, + s_engineB_caps, + NV_ARRAY_SIZE(s_engineB_caps), + (void **)&(ppCaps[AesHwEngine_B]))); + + if (ppCaps[AesHwEngine_B] == &s_Caps2) + { + if (NULL == s_Caps2.pAesInterf) + { + s_Caps2.pAesInterf = NvOsAlloc(sizeof(AesHwInterface)); + if (NULL == s_Caps2.pAesInterf) + goto fail; + NvAesIntfAp20GetHwInterface(s_Caps2.pAesInterf); + } + } + +fail: + return e; +} + +/** + * Encrypt/Decrypt the given input buffer using Electronic CodeBook (ECB) mode. + * + * @param pAesClient Pointer to AES client. + * @param pInputBuffer Pointer to input bufffer. + * @param BufSize Buffer size. + * @param IsEncrypt If set to NV_TRUE, encrypt the input buffer else decrypt it. + * @param pOutputBuffer Pointer to output buffer. + * + * @retval NvSuccess if successfully completed. + */ +NvError +AesCoreEcbProcessBuffer( + const NvDdkAes *const pAesClient, + const NvU8 *const pInputBuffer, + const NvU32 BufSize, + const NvBool IsEncrypt, + NvU8 *const pOutputBuffer) +{ + NvError e = NvSuccess; + AesHwEngine SskEngine; + AesHwKeySlot SskKeySlot; + AesHwContext *pAesHwCtxt; + + NV_ASSERT(pAesClient); + NV_ASSERT(pInputBuffer); + NV_ASSERT(pOutputBuffer); + + // Get the AES H/W context + NV_ASSERT(pAesClient->pAesCoreEngine); + pAesHwCtxt = &pAesClient->pAesCoreEngine->AesHwCtxt; + + SskEngine = pAesClient->pAesCoreEngine->SskEngine[0]; + SskKeySlot = (IsEncrypt ? pAesClient->pAesCoreEngine->SskEncryptSlot : pAesClient->pAesCoreEngine->SskDecryptSlot); + + NVDDK_AES_CHECK_INTERFACE(pAesHwCtxt, SskEngine); + + AesCoreRequestHwAccess(); + + // Select SSK key for processing + NVDDK_AES_CHECK_INTERFACE_FUNC(pAesHwCtxt, SskEngine, AesHwSelectKeyIvSlot); + pAesHwCtxt->ppEngineCaps[SskEngine]->pAesInterf->AesHwSelectKeyIvSlot(SskEngine, SskKeySlot, pAesHwCtxt); + + // Process the buffer + NVDDK_AES_CHECK_INTERFACE_FUNC(pAesHwCtxt, SskEngine, AesHwStartEngine); + e = pAesHwCtxt->ppEngineCaps[SskEngine]->pAesInterf->AesHwStartEngine( + SskEngine, + BufSize, + pInputBuffer, + IsEncrypt, + NvDdkAesOperationalMode_Ecb, + pOutputBuffer, + pAesHwCtxt); + + AesCoreReleaseHwAccess(); + return e; +} + +/** + * Wrap the given key data using RFC 3394 algoritham. + * + * Follwing is RFC3394 key wrap algoritham. + * Inputs: Plaintext, n 64-bit values {P1, P2, ..., Pn}, and + * Key, K (the KEK). + * Outputs: Ciphertext, (n+1) 64-bit values {C0, C1, ..., Cn}. + + * 1) Initialize variables. + * Set A = IV, an initial value (see 2.2.3) + * For i = 1 to n + * R[i] = P[i] + * 2) Calculate intermediate values. + * For j = 0 to 5 + * For i=1 to n + * B = AES(K, A | R[i]) + * A = MSB(64, B) ^ t where t = (n*j)+i + * R[i] = LSB(64, B) + * 3) Output the results. + * Set C[0] = A + * For i = 1 to n + * C[i] = R[i] + * + * @param pAesClient Pointer to AES client. + * @param pOrgKey Pointer to Original Key. + * @param pOrgIv Pointer to Original Iv which is used in RFC3394 algorithm. + * @param pWrappedKey Pointer to wrapped key. + * @param pWrappedIv Pointer to wrapped Iv. + * + */ +NvError +AesCoreWrapKey( + const NvDdkAes *const pAesClient, + const NvU8 *const pOrgKey, + const NvU8 *const pOrgIv, + NvU8 *const pWrappedKey, + NvU8 *const pWrappedIv) +{ + NvError e = NvSuccess; + NvU8 n = AES_RFC_3394_NUM_OF_BLOCKS_FOR_128BIT_KEY, i, j, k, t; + NvU8 *A, *B; + NvU8 **R; + AesHwContext *pAesHwCtxt; + + NV_ASSERT(pAesClient); + NV_ASSERT(pOrgKey); + NV_ASSERT(pOrgIv); + NV_ASSERT(pWrappedKey); + NV_ASSERT(pWrappedIv); + + // Get the AES H/W context + NV_ASSERT(pAesClient->pAesCoreEngine); + pAesHwCtxt = &pAesClient->pAesCoreEngine->AesHwCtxt; + + // Local buffers which are used for processing should be in IRAM. + // Use KeyTable buffer which is in IRAM. + // The local variables should be of following format and sizes. + // NvU8 A[AES_RFC_3394_KEY_WRAP_BLOCK_SIZE_BYTES]; + // NvU8 B[AES_RFC_3394_KEY_WRAP_BLOCK_SIZE_BYTES * AES_RFC_3394_NUM_OF_BLOCKS_FOR_128BIT_KEY]; + // NvU8 R[AES_RFC_3394_NUM_OF_BLOCKS_FOR_128BIT_KEY][AES_RFC_3394_KEY_WRAP_BLOCK_SIZE_BYTES]; + + A = pAesHwCtxt->pKeyTableVirAddr[0]; + B = A + AES_RFC_3394_KEY_WRAP_BLOCK_SIZE_BYTES; + + R = (NvU8 **)(B + (AES_RFC_3394_NUM_OF_BLOCKS_FOR_128BIT_KEY * AES_RFC_3394_KEY_WRAP_BLOCK_SIZE_BYTES)); + for(i = 0; i < AES_RFC_3394_NUM_OF_BLOCKS_FOR_128BIT_KEY; i++) + { + R[i] = ((B + (AES_RFC_3394_NUM_OF_BLOCKS_FOR_128BIT_KEY * AES_RFC_3394_KEY_WRAP_BLOCK_SIZE_BYTES)) + + (AES_RFC_3394_KEY_WRAP_BLOCK_SIZE_BYTES * sizeof(NvU8 *)) + + (i * AES_RFC_3394_KEY_WRAP_BLOCK_SIZE_BYTES)); + } + + // Set A = IV + for (i = 0; i < AES_RFC_3394_KEY_WRAP_BLOCK_SIZE_BYTES; i++) + A[i] = pOrgIv[i]; + + //For i = 1 to n R[i] = P[i] + for (i = 0; i < n; i++) + { + for (j = 0; j < AES_RFC_3394_KEY_WRAP_BLOCK_SIZE_BYTES; j++) + R[i][j] = pOrgKey[j + (i *AES_RFC_3394_KEY_WRAP_BLOCK_SIZE_BYTES)]; + } + + // Calculate intermediate values. + // For j = 0 to 5 + // For i=1 to n + // B = AES(K, A | R[i]) + // A = MSB(64, B) ^ t where t = (n*j)+i + // R[i] = LSB(64, B) + for (j = 0; j <= 5; j++) + { + for (i = 0; i < n; i++) + { + for (k = 0; k < AES_RFC_3394_KEY_WRAP_BLOCK_SIZE_BYTES; k++) + { + B[k] = A[k]; + B[AES_RFC_3394_KEY_WRAP_BLOCK_SIZE_BYTES+k] = R[i][k]; + } + NV_CHECK_ERROR(AesCoreEcbProcessBuffer(pAesClient, B, NvDdkAesKeySize_128Bit, NV_TRUE, B)); + for (k = 0; k < AES_RFC_3394_KEY_WRAP_BLOCK_SIZE_BYTES; k++) + { + A[k] = B[k]; + R[i][k] = B[AES_RFC_3394_KEY_WRAP_BLOCK_SIZE_BYTES + k]; + } + t = (n * j) + (i+1); + A[AES_RFC_3394_KEY_WRAP_BLOCK_SIZE_BYTES-1] ^= t; + } + } + + // Output the results. + // Set C[0] = A + // For i = 1 to n + // C[i] = R[i] + for (k = 0; k < AES_RFC_3394_KEY_WRAP_BLOCK_SIZE_BYTES; k++) { + pWrappedIv[k] = A[k]; + } + for (i = 0; i < n; i++) + { + for (k = 0; k < AES_RFC_3394_KEY_WRAP_BLOCK_SIZE_BYTES; k++) + { + pWrappedKey[(AES_RFC_3394_KEY_WRAP_BLOCK_SIZE_BYTES*i) + k] = R[i][k]; + } + } + + // Clear the buffers. + NvOsMemset(pAesHwCtxt->pKeyTableVirAddr[0], 0, pAesHwCtxt->KeyTableSize[0]); + return e; +} + +/** + * UnWrapKey the given key data using RFC 3394 algorithm. + * + * Follwing is RFC3394 key unwrap algoritham. + * Inputs: Ciphertext, (n+1) 64-bit values {C0, C1, ..., Cn}, and + * Key, K (the KEK). + * Outputs: Plaintext, n 64-bit values {P0, P1, K, Pn}. + * + * 1) Initialize variables. + * Set A = C[0] + * For i = 1 to n + * R[i] = C[i] + * 2) Compute intermediate values. + * For j = 5 to 0 + * For i = n to 1 + * B = AES-1(K, (A ^ t) | R[i]) where t = n*j+i + * A = MSB(64, B) + * R[i] = LSB(64, B) + * 3) Output results. + * If A is an appropriate initial value (see 2.2.3), + * Then + * For i = 1 to n + * P[i] = R[i] + * Else + * Return an error + * + * @param pAesClient Pointer to AES client. + * @param pWrappedKey Pointer to wrapped key + * @param pWrappedIv Pointer to wrapped Iv + * @param pOrgKey Pointer to Original Key. + * @param pOrgIv Pointer to Original Iv which is used in RFC3394 algorithm. + * + */ +NvError +AesCoreUnWrapKey( + const NvDdkAes *const pAesClient, + const NvU8 *const pWrappedKey, + const NvU8 *const pWrappedIv, + NvU8 *const pOrgKey, + NvU8 *const pOrgIv) +{ + NvError e = NvSuccess; + NvS32 n = AES_RFC_3394_NUM_OF_BLOCKS_FOR_128BIT_KEY, i, j, k, t; + NvU8 *A, *B; + NvU8 **R; + AesHwContext *pAesHwCtxt; + + NV_ASSERT(pAesClient); + NV_ASSERT(pWrappedKey); + NV_ASSERT(pWrappedIv); + NV_ASSERT(pOrgKey); + NV_ASSERT(pOrgIv); + + // Get the AES H/W context + NV_ASSERT(pAesClient->pAesCoreEngine); + pAesHwCtxt = &pAesClient->pAesCoreEngine->AesHwCtxt; + + // Local buffers which are used for processing should in IRAM. + // Use KeyTable buffer which is in IRAM. + // The local variables should be of following format and sizes. + // NvU8 A[AES_RFC_3394_KEY_WRAP_BLOCK_SIZE_BYTES]; + // NvU8 B[AES_RFC_3394_KEY_WRAP_BLOCK_SIZE_BYTES * AES_RFC_3394_NUM_OF_BLOCKS_FOR_128BIT_KEY]; + // NvU8 R[AES_RFC_3394_NUM_OF_BLOCKS_FOR_128BIT_KEY][AES_RFC_3394_KEY_WRAP_BLOCK_SIZE_BYTES]; + + A = pAesHwCtxt->pKeyTableVirAddr[0]; + B = A + AES_RFC_3394_KEY_WRAP_BLOCK_SIZE_BYTES; + R = (NvU8 **)(B + (AES_RFC_3394_NUM_OF_BLOCKS_FOR_128BIT_KEY * AES_RFC_3394_KEY_WRAP_BLOCK_SIZE_BYTES)); + for(i = 0; i < AES_RFC_3394_NUM_OF_BLOCKS_FOR_128BIT_KEY; i++) + { + R[i] = ((B + (AES_RFC_3394_NUM_OF_BLOCKS_FOR_128BIT_KEY * AES_RFC_3394_KEY_WRAP_BLOCK_SIZE_BYTES)) + + (AES_RFC_3394_KEY_WRAP_BLOCK_SIZE_BYTES * sizeof(NvU8 *)) + + (i * AES_RFC_3394_KEY_WRAP_BLOCK_SIZE_BYTES)); + } + + // Set A = C[0] + for (i = 0; i < AES_RFC_3394_KEY_WRAP_BLOCK_SIZE_BYTES; i++) + A[i] = pWrappedIv[i]; + + // For i = 1 to n R[i] = C[i] + for (i = 0; i < n; i++) { + for (j = 0; j < AES_RFC_3394_KEY_WRAP_BLOCK_SIZE_BYTES; j++) + R[i][j] = pWrappedKey[j + (i *AES_RFC_3394_KEY_WRAP_BLOCK_SIZE_BYTES)]; + } + + // Compute intermediate values. + // For j = 5 to 0 + // For i = n to 1 + // B = AES-1(K, (A ^ t) | R[i]) where t = n*j+i + // A = MSB(64, B) + // R[i] = LSB(64, B) + for (j = 5; j >= 0; j--) + { + for (i = n; i > 0; i--) + { + t = (n * j) + (i); + A[AES_RFC_3394_KEY_WRAP_BLOCK_SIZE_BYTES-1] ^= t; + for (k = 0; k < AES_RFC_3394_KEY_WRAP_BLOCK_SIZE_BYTES; k++) + { + B[k] = A[k]; + B[AES_RFC_3394_KEY_WRAP_BLOCK_SIZE_BYTES+k] = R[i-1][k]; + } + NV_CHECK_ERROR(AesCoreEcbProcessBuffer(pAesClient, B, NvDdkAesKeySize_128Bit, NV_FALSE, B)); + for (k = 0; k < AES_RFC_3394_KEY_WRAP_BLOCK_SIZE_BYTES; k++) + { + A[k] = B[k]; + R[i-1][k] = B[AES_RFC_3394_KEY_WRAP_BLOCK_SIZE_BYTES + k]; + } + } + } + + // Output results. + // For i = 1 to n + // P[i] = R[i] + for (k = 0; k < AES_RFC_3394_KEY_WRAP_BLOCK_SIZE_BYTES; k++) + { + pOrgIv[k] = A[k]; + } + + for (i = 0; i < n; i++) + { + for (k = 0; k < AES_RFC_3394_KEY_WRAP_BLOCK_SIZE_BYTES; k++) + { + pOrgKey[(AES_RFC_3394_KEY_WRAP_BLOCK_SIZE_BYTES*i) + k] = R[i][k]; + } + } + + // Clear the buffers. + NvOsMemset(pAesHwCtxt->pKeyTableVirAddr[0], 0, pAesHwCtxt->KeyTableSize[0]); + return e; +} diff --git a/arch/arm/mach-tegra/nvddk/nvddk_aes_core_ap20.c b/arch/arm/mach-tegra/nvddk/nvddk_aes_core_ap20.c new file mode 100644 index 000000000000..1e24deb90c2e --- /dev/null +++ b/arch/arm/mach-tegra/nvddk/nvddk_aes_core_ap20.c @@ -0,0 +1,617 @@ +/* + * Copyright (c) 2007-2009 NVIDIA Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of the NVIDIA Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "nvos.h" +#include "nvassert.h" +#include "nvrm_drf.h" +#include "nvrm_hardware_access.h" +#include "ap20/arvde_bsev_aes.h" +#include "ap20/aravp_bsea_aes.h" +#include "ap20/arapbpm.h" +#include "nvddk_aes_common.h" +#include "nvddk_aes_priv.h" +#include "nvddk_aes_hw.h" +#include "nvddk_aes_core_ap20.h" + +#define SECURE_HW_REGR(engine, viraddr, reg, value) \ +{ \ + if (AesHwEngine_A == engine) \ + { \ + (value) = NV_READ32((NvU32)(viraddr) + (ARVDE_BSEV_##reg##_0)); \ + } \ + else if (AesHwEngine_B == engine) \ + { \ + (value) = NV_READ32((NvU32)(viraddr) + (AVPBSEA_##reg##_0)); \ + } \ +} + +#define SECURE_HW_REGW(engine, viraddr, reg, data) \ +{ \ + if (AesHwEngine_A == engine) \ + { \ + NV_WRITE32((NvU32)(viraddr) + (ARVDE_BSEV_##reg##_0), (data)); \ + } \ + else if (AesHwEngine_B == engine) \ + { \ + NV_WRITE32((NvU32)(viraddr) + (AVPBSEA_##reg##_0), (data)); \ + } \ +} + +#define SECURE_DRF_SET_VAL(engine, reg, field, newData, value) \ +{ \ + if (AesHwEngine_A == engine) \ + { \ + value = NV_FLD_SET_DRF_NUM(ARVDE_BSEV, reg, field, newData, value); \ + } \ + else if (AesHwEngine_B == engine) \ + { \ + value = NV_FLD_SET_DRF_NUM(AVPBSEA, reg, field, newData, value); \ + } \ +} + +#define SECURE_DRF_READ_VAL(engine, reg, field, regData, value) \ +{ \ + if (AesHwEngine_A == engine) \ + { \ + value = NV_DRF_VAL(ARVDE_BSEV, reg, field, regData); \ + } \ + else if (AesHwEngine_B == engine) \ + { \ + value = NV_DRF_VAL(AVPBSEA, reg, field, regData); \ + } \ +} + +#define SECURE_DRF_NUM(engine, reg, field, num) \ + NV_DRF_NUM(ARVDE_BSEV, reg, field, num) \ + +#define SECURE_INDEXED_REGR(engine, viraddr, reg, index,value) \ +{ \ + if (AesHwEngine_A == engine) \ + { \ + (value) = NV_READ32((NvU32)(viraddr) + (ARVDE_BSEV_##reg##_##0) + index * 4); \ + } \ + else if (AesHwEngine_B == engine) \ + { \ + (value) = NV_READ32((NvU32)(viraddr) + (AVPBSEA_##reg##_##0) + index * 4 ); \ + } \ +} + +#define NV_ADDRESS_MAP_IRAM_A_BASE 0x40000000 + +static NvBool NvAesCoreAp20IsEngineBusy(const AesHwEngine Engine, const NvU32 *const pEngineVirAddr); + +/** + * Define Ucq opcodes required for AES operation. + */ +typedef enum +{ + // Opcode for Block Start Engine command + AesUcqOpcode_BlockStartEngine = 0x0E, + // Opcode for Dma setup command + AesUcqOpcode_DmaSetup = 0x10, + // Opcode for Dma Finish Command + AesUcqOpcode_DmaFinish = 0x11, + // Opcode for Table setup command + AesUcqOpcode_SetupTable = 0x15, + AesUcqOpcode_Force32 = 0x7FFFFFFF +} AesUcqOpcode; + +/** + * Define Aes command values. + */ +typedef enum +{ + // Command value for AES Table select + AesUcqCommand_TableSelect = 0x3, + // Command value for Keytable selection + AesUcqCommand_KeyTableSelect = 0x8, + // Command value for KeySchedule selection + AesUcqCommand_KeySchedTableSelect = 0x4, + // Command mask for ketable address mask + AesUcqCommand_KeyTableAddressMask = 0x1FFFF, + AesUcqCommand_Force32 = 0x7FFFFFFF +} AesUcqCommand; + +/** + * @brief Define AES Interactive command Queue commands Bit positions. + */ +typedef enum +{ + // Define bit position for command Queue Opcode + AesIcqBitShift_Opcode = 26, + // Define bit position for AES Table select + AesIcqBitShift_TableSelect = 24, + // Define bit position for AES Key Table select + AesIcqBitShift_KeyTableId = 17, + // Define bit position for AES Key Table Address + AesIcqBitShift_KeyTableAddr = 0, + // Define bit position for 128 bit blocks count + AesIcqBitShift_BlockCount = 0, + AesIcqBitShift_Force32 = 0x7FFFFFFF +} AesIcqBitShift; + +NvError NvAesCoreAp20DisableEngine(const AesHwEngine Engine, const NvU32 *const pEngineVirAddr) +{ + NvU32 RegValue = 0; + + // Disable the AES engine + SECURE_HW_REGR(Engine, pEngineVirAddr, SECURE_SECURITY, RegValue); + SECURE_DRF_SET_VAL(Engine, SECURE_SECURITY, SECURE_ENG_DIS, 1, RegValue); + SECURE_HW_REGW(Engine, pEngineVirAddr, SECURE_SECURITY, RegValue); + + SECURE_HW_REGW(Engine, pEngineVirAddr, SECURE_SECURITY, 0); + SECURE_HW_REGR(Engine, pEngineVirAddr, SECURE_SECURITY, RegValue); + + if (RegValue == SECURE_DRF_NUM(Engine, SECURE_SECURITY, SECURE_ENG_DIS, 1)) + return NvSuccess; + return NvError_AesDisableCryptoFailed; +} + +NvBool NvAesCoreAp20IsEngineDisabled(const AesHwEngine Engine, const NvU32 *const pEngineVirAddr) +{ + NvU32 RegValue = 0; + NvU32 EngineStatus = 0; + + SECURE_HW_REGR(Engine, pEngineVirAddr, SECURE_SECURITY, RegValue); + SECURE_DRF_READ_VAL(Engine, SECURE_SECURITY, SECURE_ENG_DIS, RegValue, EngineStatus); + + return (NvBool)EngineStatus; +} + +/** + * Query the status of the engine. + * + * @param Engine The engine for which status is required. + * @param pEngineVirAddr AES engine virtual address. + * + * @retval NV_TRUE if the engine is busy. + * @retval NV_FALSE if the engine is not busy. + */ +NvBool NvAesCoreAp20IsEngineBusy(const AesHwEngine Engine, const NvU32 *const pEngineVirAddr) +{ + NvU32 RegValue = 0; + NvU32 EngBusy = 0; + NvU32 IcqEmpty = 0; + NvU32 DmaBusy = 0; + + SECURE_HW_REGR(Engine, pEngineVirAddr, INTR_STATUS, RegValue); + + // Extract the EngBusy, IcqEmpty and DmaBusy status + SECURE_DRF_READ_VAL(Engine, INTR_STATUS, ENGINE_BUSY, RegValue, EngBusy); + SECURE_DRF_READ_VAL(Engine, INTR_STATUS, ICQ_EMPTY, RegValue, IcqEmpty); + SECURE_DRF_READ_VAL(Engine, INTR_STATUS, DMA_BUSY, RegValue, DmaBusy); + + // Check for engine busy, ICQ not empty and DMA busy + if ((EngBusy) || (!IcqEmpty) || (DmaBusy)) + { + // Return TRUE if any of the condition is true + return NV_TRUE; + } + + // Return FALSE if engine is not doing anything + return NV_FALSE; +} + +void NvAesCoreAp20WaitTillEngineIdle(const AesHwEngine Engine, const NvU32 *const pEngineVirAddr) +{ + while (NvAesCoreAp20IsEngineBusy(Engine, pEngineVirAddr)); +} + +void +NvAesCoreAp20SetupTable( + const AesHwEngine Engine, + const NvU32 *const pEngineVirAddr, + const NvU32 KeyTablePhyAddr, + const NvU32 Slot) +{ + NvU32 SetupTableCmd = ((AesUcqOpcode_SetupTable << AesIcqBitShift_Opcode) | + (AesUcqCommand_TableSelect << AesIcqBitShift_TableSelect) | + ((AesUcqCommand_KeyTableSelect | Slot) << AesIcqBitShift_KeyTableId) | + ((KeyTablePhyAddr & AesUcqCommand_KeyTableAddressMask) << + AesIcqBitShift_KeyTableAddr)); + + NvAesCoreAp20WaitTillEngineIdle(Engine, pEngineVirAddr); + + // Issue the ICQ command to update the table to H/W registers + SECURE_HW_REGW(Engine, pEngineVirAddr, ICMDQUE_WR, SetupTableCmd); + + NvAesCoreAp20WaitTillEngineIdle(Engine, pEngineVirAddr); +} + +void NvAesCoreAp20SelectKeyIvSlot(const AesHwEngine Engine, const NvU32 *const pEngineVirAddr, const NvU32 Slot) +{ + NvU32 RegValue = 0; + + // Select the KEY slot for updating the IV vectors + SECURE_HW_REGR(Engine, pEngineVirAddr, SECURE_CONFIG, RegValue); + // 2-bit index to select between the 4- keys + SECURE_DRF_SET_VAL(Engine, SECURE_CONFIG, SECURE_KEY_INDEX, Slot, RegValue); + // Update the AES config register + SECURE_HW_REGW(Engine, pEngineVirAddr, SECURE_CONFIG, RegValue); +} + +void +NvAesCoreAp20SetIv( + const AesHwEngine Engine, + const NvU32 *const pEngineVirAddr, + const NvU32 Slot, + const NvU32 Start, + const NvU32 End, + const NvU32 *const pKeyTable, + const NvU32 KeyTableSize, + const NvU32 *const pIvAddress) +{ + // Setting the iv will be done through decryption of Iv + // because Iv can't be written without overwriting the key + // especially in cases when key is not readable. +} + +void +NvAesCoreAp20GetIv( + const AesHwEngine Engine, + const NvU32 *const pEngineVirAddr, + const NvU32 Slot, + const NvU32 Start, + const NvU32 End, + const NvU32 *const pIvAddress) +{ + // The Iv is preserved within the driver because read permission is locked + // down for dedicated key slots +} + +void +NvAesCoreAp20ControlKeyScheduleGeneration( + const AesHwEngine Engine, + const NvU32 *const pEngineVirAddr, + const NvBool IsEnabled) +{ + NvU32 RegValue = 0; + + // Disable key schedule generation in hardware + SECURE_HW_REGR(Engine, pEngineVirAddr, SECURE_CONFIG_EXT, RegValue); + SECURE_DRF_SET_VAL(Engine, SECURE_CONFIG_EXT, SECURE_KEY_SCH_DIS, (IsEnabled ? 0 : 1), RegValue); + SECURE_HW_REGW(Engine, pEngineVirAddr, SECURE_CONFIG_EXT, RegValue); +} + +void NvAesCoreAp20LockSskReadWrites(const AesHwEngine Engine, const NvU32 *const pEngineVirAddr) +{ + NvU32 RegValue = 0; + + SECURE_HW_REGR(Engine, pEngineVirAddr, SECURE_SEC_SEL4, RegValue); + SECURE_DRF_SET_VAL(Engine, SECURE_SEC_SEL4, KEYREAD_ENB4, 0, RegValue); + SECURE_DRF_SET_VAL(Engine, SECURE_SEC_SEL4, KEYUPDATE_ENB4, 0, RegValue); + SECURE_HW_REGW(Engine, pEngineVirAddr, SECURE_SEC_SEL4, RegValue); +} + +static void +AesHwPrivProcessBuffer( + const AesHwEngine Engine, + const NvU32 *const pEngineVirAddr, + const NvU32 SrcPhyAddress, + const NvU32 DestPhyAddress, + const NvU32 NumBlocks, + const NvBool IsEncryption, + const NvDdkAesOperationalMode OpMode) +{ + NvU32 CommandQueueData[AES_HW_MAX_ICQ_LENGTH]; + NvU32 CommandQueueLength = 0; + NvU32 RegValue = 0; + NvU32 EngBusy = 0; + NvU32 IcqEmpty = 0; + NvU32 i; + + // Setup DMA command + CommandQueueData[CommandQueueLength++] = (AesUcqOpcode_DmaSetup << AesIcqBitShift_Opcode); + CommandQueueData[CommandQueueLength++] = SrcPhyAddress; + + // Setup Block Start Engine Command + CommandQueueData[CommandQueueLength++] = + ((AesUcqOpcode_BlockStartEngine << AesIcqBitShift_Opcode) | + ((NumBlocks - 1) << AesIcqBitShift_BlockCount)); + + // Setup DMA finish command + CommandQueueData[CommandQueueLength++] = (AesUcqOpcode_DmaFinish << AesIcqBitShift_Opcode); + + // Wait for engine to become idle + NvAesCoreAp20WaitTillEngineIdle(Engine, pEngineVirAddr); + + // Configure command Queue control register + SECURE_HW_REGR(Engine, pEngineVirAddr, CMDQUE_CONTROL, RegValue); + + if (AesHwEngine_A == Engine) + { + RegValue |= + // Source Stream interface select, + // (SRC_STM_SEL = 0: through CIF (SDRAM)), + // and (SRC_STM_SEL = 1: through AHB (SDRAM/IRAM)). + SECURE_DRF_NUM(Engine, CMDQUE_CONTROL, SRC_STM_SEL, (SrcPhyAddress & NV_ADDRESS_MAP_IRAM_A_BASE) ? 1 : 0) | + // Destination Stream interface select, + // (DST_STM_SEL = 0: through CIF (SDRAM)), + // and (DST_STM_SEL = 1: through AHB (SDRAM/IRAM)). + SECURE_DRF_NUM(Engine, CMDQUE_CONTROL, DST_STM_SEL, (DestPhyAddress& NV_ADDRESS_MAP_IRAM_A_BASE) ? 1 : 0); + } + else + { + RegValue |= + // Source Stream interface select, + // (SRC_STM_SEL = 1: through AHB (SDRAM/IRAM)). + SECURE_DRF_NUM(Engine, CMDQUE_CONTROL, SRC_STM_SEL, 1) | + // Destination Stream interface select, + // (DST_STM_SEL = 1: through AHB (SDRAM/IRAM)). + SECURE_DRF_NUM(Engine, CMDQUE_CONTROL, DST_STM_SEL, 1); + } + + // Update the Command Queue control register + SECURE_HW_REGW(Engine, pEngineVirAddr, CMDQUE_CONTROL, RegValue); + + RegValue = SECURE_DRF_NUM(Engine, BSE_CONFIG, BSE_MODE_SEL, 0) | + // Endian conversion enable for the bit stream + // (ENDIAN_ENB = 1: little Endian stream) + SECURE_DRF_NUM(Engine, BSE_CONFIG, ENDIAN_ENB, 1); + + // Update the BSE config register + SECURE_HW_REGW(Engine, pEngineVirAddr, BSE_CONFIG, RegValue); + + // Read the AES config register + SECURE_HW_REGR(Engine, pEngineVirAddr, SECURE_CONFIG_EXT, RegValue); + + // Set counter offset to '0' + SECURE_DRF_SET_VAL(Engine, SECURE_CONFIG_EXT, SECURE_OFFSET_CNT, 0, RegValue); + SECURE_HW_REGW(Engine, pEngineVirAddr, SECURE_CONFIG_EXT, RegValue); + + // Configure the AES extension register for KEY and IV select + SECURE_HW_REGR(Engine, pEngineVirAddr, SECURE_INPUT_SELECT, RegValue); + SECURE_DRF_SET_VAL(Engine, SECURE_INPUT_SELECT, SECURE_IV_SELECT, 1, RegValue); + + // Select AES operation mode for configuring the AES config register + ////////////////////////////////////////////////////////////////////////// + switch (OpMode) + { + case NvDdkAesOperationalMode_Cbc: + // Configuration for CBC mode of operation: + // ---------------------------------------------------------------------- + // | Encryption | Decryption + //----------------------------------------------------------------------- + // SECURE_XOR_POS | 10b (top) | 11b (bottom) + // SECURE_INPUT_SEL | 00b (AHB) | 00b (AHB) + // SECURE_VCTRAM_SEL | 10b (IV + AES Output) | 11b (IV_PreAHB) + // SECURE_CORE_SEL | 1b (AES) | 0b (inverse AES) + ////////////////////////////////////////////////////////////////////////// + /* AES configuration for Encryption/Decryption */ + // AES XOR position 10b = '2': top, before AES + // AES XOR position 11b = '3': bottom, after AES + SECURE_DRF_SET_VAL(Engine, SECURE_INPUT_SELECT, SECURE_XOR_POS, (IsEncryption ? 2 : 3), RegValue); + // AES input select 0?b = '00' or '01': From AHB input vector + SECURE_DRF_SET_VAL(Engine, SECURE_INPUT_SELECT, SECURE_INPUT_SEL, 0, RegValue); + // Vector RAM select 10b = '2': Init Vector for first round and AES + // output for the rest rounds. + // Vector RAM select 11b = '3': Init Vector for the first round + // and previous AHB input for the rest rounds + SECURE_DRF_SET_VAL(Engine, SECURE_INPUT_SELECT, SECURE_VCTRAM_SEL, (IsEncryption ? 2 : 3), RegValue); + // AES core selection 1b = '1': Encryption + // Inverse AES core selection 0b = '0': Decryption + SECURE_DRF_SET_VAL(Engine, SECURE_INPUT_SELECT, SECURE_CORE_SEL, (IsEncryption ? 1 : 0), RegValue); + // Disable the random number generator + SECURE_DRF_SET_VAL(Engine, SECURE_INPUT_SELECT, SECURE_RNG_ENB, 0, RegValue); + break; + case NvDdkAesOperationalMode_Ecb: + // Configuration for ECB mode of operation: + // ---------------------------------------------------------------------- + // | Encryption | Decryption + //----------------------------------------------------------------------- + // SECURE_XOR_POS | 0X (bypass) | 0X (bypass) + // SECURE_INPUT_SEL | 00b (AHB) | 00b (AHB) + // SECURE_VCTRAM_SEL | XX(don’t care) | XX(don’t care) + // SECURE_CORE_SEL | 1b (AES) | 0b (inverse AES) + ////////////////////////////////////////////////////////////////////////// + /* AES configuration for Encryption/Decryption */ + // For ECB mode, XOR position shoud be bypassed + SECURE_DRF_SET_VAL(Engine, SECURE_INPUT_SELECT, SECURE_XOR_POS, 0, RegValue); + // AES input select is zero + SECURE_DRF_SET_VAL(Engine, SECURE_INPUT_SELECT, SECURE_INPUT_SEL, 0, RegValue); + // AES core selection 1b = '1': Encryption + // Inverse AES core selection 0b = '0': Decryption + SECURE_DRF_SET_VAL(Engine, SECURE_INPUT_SELECT, SECURE_CORE_SEL, (IsEncryption ? 1 : 0), RegValue); + // Disable the random number generator + SECURE_DRF_SET_VAL(Engine, SECURE_INPUT_SELECT, SECURE_RNG_ENB, 0, RegValue); + break; + case NvDdkAesOperationalMode_AnsiX931: + // For ECB mode, XOR position shoud be bypassed + SECURE_DRF_SET_VAL(Engine, SECURE_INPUT_SELECT, SECURE_XOR_POS, 0, RegValue); + // AES input select is zero + SECURE_DRF_SET_VAL(Engine, SECURE_INPUT_SELECT, SECURE_INPUT_SEL, 0, RegValue); + // AES core selection 1b = '1': Encryption + // Inverse AES core selection 0b = '0': Decryption + SECURE_DRF_SET_VAL(Engine, SECURE_INPUT_SELECT, SECURE_CORE_SEL, (IsEncryption ? 1 : 0), RegValue); + // To generate a random number, enable the random number generator + SECURE_DRF_SET_VAL(Engine, SECURE_INPUT_SELECT, SECURE_RNG_ENB, 1, RegValue); + break; + default: + return; + } + + SECURE_DRF_SET_VAL(Engine, SECURE_INPUT_SELECT, SECURE_HASH_ENB, 0, RegValue); + SECURE_HW_REGW(Engine, pEngineVirAddr, SECURE_INPUT_SELECT, RegValue); + + // Update the AES destination physical address + SECURE_HW_REGW(Engine, pEngineVirAddr, SECURE_DEST_ADDR, DestPhyAddress); + + // Issue the AES commands to the ICQ + for (i = 0; i < CommandQueueLength; i++) + { + // Wait till engine becomes IDLE before issuing any command + do + { + SECURE_HW_REGR(Engine, pEngineVirAddr, INTR_STATUS, RegValue); + SECURE_DRF_READ_VAL(Engine, INTR_STATUS, ENGINE_BUSY, RegValue, EngBusy); + SECURE_DRF_READ_VAL(Engine, INTR_STATUS, ICQ_EMPTY, RegValue, IcqEmpty); + } while ((EngBusy) && ~(IcqEmpty)); + // Write the command to the ICQ register + SECURE_HW_REGW(Engine, pEngineVirAddr, ICMDQUE_WR, CommandQueueData[i]); + } + + // Wait for engine to become idle + NvAesCoreAp20WaitTillEngineIdle(Engine, pEngineVirAddr); +} + +void +NvAesCoreAp20ProcessBuffer( + const AesHwEngine Engine, + const NvU32 *const pEngineVirAddr, + const NvU32 SrcPhyAddress, + const NvU32 DestPhyAddress, + const NvU32 DataSize, + const NvU32 DmaPhyAddr, + const NvBool IsEncryption, + const NvU32 OpMode) +{ + NvU32 TotalBytes = DataSize; + NvU32 BytesToProcess = 0; + NvU32 *pSrcVirAddr = NULL; + NvU32 *pDestVirAddr = NULL; + NvU32 *pDmaVirAddr = NULL; + NvU32 NumBlocks = 0; + NvError e = NvRmPhysicalMemMap( + SrcPhyAddress, + DataSize, + NVOS_MEM_READ_WRITE, + NvOsMemAttribute_Uncached, + (void **)&pSrcVirAddr); + if (e != NvSuccess) + return; + + e = NvRmPhysicalMemMap( + DestPhyAddress, + DataSize, + NVOS_MEM_READ_WRITE, + NvOsMemAttribute_Uncached, + (void **)&pDestVirAddr); + if (e != NvSuccess) + { + NvRmPhysicalMemUnmap(pSrcVirAddr, DataSize); + return; + } + + NV_CHECK_ERROR_CLEANUP(NvRmPhysicalMemMap( + DmaPhyAddr, + AES_HW_DMA_BUFFER_SIZE_BYTES, + NVOS_MEM_READ_WRITE, + NvOsMemAttribute_Uncached, + (void **)&pDmaVirAddr)); + + while (TotalBytes) + { + if (TotalBytes > AES_HW_DMA_BUFFER_SIZE_BYTES) + BytesToProcess = AES_HW_DMA_BUFFER_SIZE_BYTES; + else + BytesToProcess = TotalBytes; + + // Copy data to the DMA buffer from the client buffer + NvOsMemcpy((void *)pDmaVirAddr, (void *)pSrcVirAddr, BytesToProcess); + + NumBlocks = BytesToProcess / NvDdkAesConst_BlockLengthBytes; + + AesHwPrivProcessBuffer(Engine, pEngineVirAddr, DmaPhyAddr, DmaPhyAddr, NumBlocks, IsEncryption, OpMode); + + // Copy data from the DMA buffer to the client buffer + NvOsMemcpy((void *)pDestVirAddr, (void *)pDmaVirAddr, BytesToProcess); + + // Increment the buffer pointer + pSrcVirAddr += BytesToProcess; + pDestVirAddr += BytesToProcess; + TotalBytes -= BytesToProcess; + } + + // UnMap the virtual address + NvRmPhysicalMemUnmap(pDmaVirAddr, DataSize); + +fail: + NvRmPhysicalMemUnmap(pDestVirAddr, DataSize); + NvRmPhysicalMemUnmap(pSrcVirAddr, DataSize); +} + +void +NvAesCoreAp20LoadSskToSecureScratchAndLock( + const NvU32 PmicBaseAddr, + const NvU32 *const pKey, + const size_t Size) +{ + NvU32 *pSecureScratch = NULL; + NvU32 *pPmicBaseAddr = NULL; + + NvRmPhysicalMemMap( + PmicBaseAddr, + Size, + NVOS_MEM_READ_WRITE, + NvOsMemAttribute_Uncached, + (void **)&pPmicBaseAddr); + + // Get the secure scratch base address + pSecureScratch = pPmicBaseAddr + (APBDEV_PMC_SECURE_SCRATCH0_0 / 4); + + // If key is supplied then load it into the scratch registers + if (pKey) + { + NvU32 i; + + // Load the SSK into the secure scratch registers + for (i = 0; i < AES_HW_KEY_LENGTH; i++) + { + NV_WRITE32(pSecureScratch, pKey[i]); + pSecureScratch++; + } + } + + // Disable write access to the secure scratch register + NV_WRITE32((pPmicBaseAddr) + (APBDEV_PMC_SEC_DISABLE_0 / 4), (NV_DRF_DEF(APBDEV_PMC, SEC_DISABLE, WRITE, ON))); + + // UnMap the virtual address + NvRmPhysicalMemUnmap(pPmicBaseAddr, Size); +} + +void +NvAesCoreAp20GetIvReadPermissions( + const AesHwEngine Engine, + const NvU32 *const pEngineVirAddr, + NvBool *const pReadPermissions) +{ + AesHwKeySlot KeySlot; + NvU32 RegValue = 0; + + NV_ASSERT(pReadPermissions); + + for (KeySlot = AesHwKeySlot_0; KeySlot < AesHwKeySlot_NumExt; KeySlot++) + { + SECURE_INDEXED_REGR(Engine, pEngineVirAddr, SECURE_SEC_SEL0, KeySlot,RegValue); + SECURE_DRF_READ_VAL(Engine, SECURE_SEC_SEL0, IVREAD_ENB0, RegValue, pReadPermissions[KeySlot]); + } +} diff --git a/arch/arm/mach-tegra/nvddk/nvddk_aes_core_ap20.h b/arch/arm/mach-tegra/nvddk/nvddk_aes_core_ap20.h new file mode 100644 index 000000000000..3840efd41bed --- /dev/null +++ b/arch/arm/mach-tegra/nvddk/nvddk_aes_core_ap20.h @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2007-2009 NVIDIA Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of the NVIDIA Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef INCLUDED_NVDDK_AES_CORE_AP20_H +#define INCLUDED_NVDDK_AES_CORE_AP20_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Disable the selected AES engine. No further operations can be + * performed using the AES engine until the entire chip is reset. + * + * @param Engine AES engine to disable. + * @param pEngineVirAddr AES engine virtual address. + * + * @retval NvSuccess if engine successfully disabled else NvError_AesDisableCryptoFailed. + */ +NvError NvAesCoreAp20DisableEngine(const AesHwEngine Engine, const NvU32 *const pEngineVirAddr); + +/** + * Read the AES engine disable status. + * + * @param Engine AES engine to disable. + * @param pEngineVirAddr AES engine virtual address. + * + * @retval NV_TRUE if engine is disabled else NV_FALSE. + */ +NvBool NvAesCoreAp20IsEngineDisabled(const AesHwEngine Engine, const NvU32 *const pEngineVirAddr); + +/** + * Wait till the engine is idle. + * + * @param Engine The engine which needs to be in idle state. + * @param pEngineVirAddr AES engine virtual address. + * + * @retval None. + */ +void NvAesCoreAp20WaitTillEngineIdle(const AesHwEngine Engine, const NvU32 *const pEngineVirAddr); + +/** + * Set up the key table. + * + * @param Engine The AES engine to setup the Key table. + * @param pEngineVirAddr AES engine virtual address. + * @param KeyTablePhyAddr The physical address of the keytable. + * @param Slot AES Key slot to use for setting up the key table. + * + * @retval None. + */ +void +NvAesCoreAp20SetupTable( + const AesHwEngine Engine, + const NvU32 *const pEngineVirAddr, + const NvU32 KeyTablePhyAddr, + const NvU32 Slot); + +/** + * Select the Key slot for updating the IV vectors. + * + * @param Engine The AES engine to be used. + * @param pEngineVirAddr AES engine virtual address. + * @param Slot The slot to be selected. + * + * @retval None. + */ +void NvAesCoreAp20SelectKeyIvSlot(const AesHwEngine Engine, const NvU32 *const pEngineVirAddr, const NvU32 Slot); + +/** + * Set the IV in key table. + * + * @param Engine The AES engine to be used. + * @param pEngineVirAddr AES engine virtual address. + * @param Slot The slot of the engine to be used. + * @param Start The start location within the keytable. + * @param End The end location of keytable. + * @param pKeyTable The physical address of the engine keytable. + * @param KeyTableSize Size of key table in bytes. + * @param pIvAddress The IV to set, if NULL then the IV is cleared. + * + * @retval None. + */ +void +NvAesCoreAp20SetIv( + const AesHwEngine Engine, + const NvU32 *const pEngineVirAddr, + const NvU32 Slot, + const NvU32 Start, + const NvU32 End, + const NvU32 *const pKeyTable, + const NvU32 KeyTableSize, + const NvU32 *const pIvAddress); + +/** + * Get the IV. + * + * @param Engine The AES engine to be used. + * @param pEngineVirAddr AES engine virtual address. + * @param Slot The slot of the engine to be used. + * @param Start The start location within the keytable. + * @param End The end location of keytable. + * @param pIvAddress The pointer to the location where the IV will be stored. + * + * @retval None. + */ +void +NvAesCoreAp20GetIv( + const AesHwEngine Engine, + const NvU32 *const pEngineVirAddr, + const NvU32 Slot, + const NvU32 Start, + const NvU32 End, + const NvU32 *const pIvAddress); + +/** + * Enable/Disable the key schedule generation in hardware. + * + * @param Engine The engine for which the key generation needs to be disabled. + * @param pEngineVirAddr AES engine virtual address. + * @param IsEnabled NV_TRUE to enable the key schedule generation, NV_FALSE otherwise. + * + * @retval None. + */ +void +NvAesCoreAp20ControlKeyScheduleGeneration( + const AesHwEngine Engine, + const NvU32 *const pEngineVirAddr, + const NvBool IsEnabled); + +/** + * Lock down the permissions for SSK. + * + * @param Engine The engine which needs to be locked. + * @param pEngineVirAddr AES engine virtual address. + * + * @retval None. + */ +void NvAesCoreAp20LockSskReadWrites(const AesHwEngine Engine, const NvU32 *const pEngineVirAddr); + +/** + * Encrypt/Decrypt blocks of data. + * + * @param Engine The engine to be used. + * @param pEngineVirAddr AES engine virtual address. + * @param SrcPhyAddress The physical address of source buffer. + * @param DestPhyAddress The physical address of destination buffer. + * @param DataSize The size of buffer. + * @param DmaPhyAddr The physical address of the DMA. + * @param IsEncryption NV_TRUE if encryption else NV_FALSE. + * @param OpMode Specifies the AES operational mode. + * + * @retval None. + */ +void +NvAesCoreAp20ProcessBuffer( + const AesHwEngine Engine, + const NvU32 *const pEngineVirAddr, + const NvU32 SrcPhyAddress, + const NvU32 DestPhyAddress, + const NvU32 DataSize, + const NvU32 DmaPhyAddr, + const NvBool IsEncryption, + const NvU32 OpMode); + +/** + * Load the SSK key into secure scratch resgister and disables the write permissions. + * + * @param pPmicBaseAddr Pointer to the PMIC base address. + * @param pKey Pointer to the key. + * @param Size Length of the aperture in bytes. + * + * @retval None. + */ +void +NvAesCoreAp20LoadSskToSecureScratchAndLock( + const NvU32 PmicBaseAddr, + const NvU32 *const pKey, + const size_t Size); + +/** + * Get the read permissions for IV for each key slot of an engine. + * + * @param Engine AES Engine for which Iv permissions for an engine are sought. + * @param pEngineVirAddr AES engine virtual address. + * @param pReadPermissions Pointer to read permissions. + * + * @retval None. + */ +void +NvAesCoreAp20GetIvReadPermissions( + const AesHwEngine Engine, + const NvU32 *const pEngineVirAddr, + NvBool *const pReadPermissions); + +#ifdef __cplusplus +}; +#endif + +#endif // #define INCLUDED_NVDDK_AES_CORE_AP20_H diff --git a/arch/arm/mach-tegra/nvddk/nvddk_aes_dispatch.c b/arch/arm/mach-tegra/nvddk/nvddk_aes_dispatch.c new file mode 100644 index 000000000000..983597a3677f --- /dev/null +++ b/arch/arm/mach-tegra/nvddk/nvddk_aes_dispatch.c @@ -0,0 +1,715 @@ + +#define NV_IDL_IS_DISPATCH + +/* + * Copyright (c) 2007-2009 NVIDIA Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of the NVIDIA Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "nvcommon.h" +#include "nvos.h" +#include "nvassert.h" +#include "nvreftrack.h" +#include "nvidlcmd.h" +#include "nvddk_aes.h" + +#define OFFSET( s, e ) (NvU32)(void *)(&(((s*)0)->e)) + + +typedef struct NvDdkAesDisableCrypto_in_t +{ + NvU32 package_; + NvU32 function_; + NvDdkAesHandle hAes; +} NV_ALIGN(4) NvDdkAesDisableCrypto_in; + +typedef struct NvDdkAesDisableCrypto_inout_t +{ + NvU32 dummy_; +} NV_ALIGN(4) NvDdkAesDisableCrypto_inout; + +typedef struct NvDdkAesDisableCrypto_out_t +{ + NvError ret_; +} NV_ALIGN(4) NvDdkAesDisableCrypto_out; + +typedef struct NvDdkAesDisableCrypto_params_t +{ + NvDdkAesDisableCrypto_in in; + NvDdkAesDisableCrypto_inout inout; + NvDdkAesDisableCrypto_out out; +} NvDdkAesDisableCrypto_params; + +typedef struct NvDdkAesSetAndLockSecureStorageKey_in_t +{ + NvU32 package_; + NvU32 function_; + NvDdkAesHandle hAes; + NvDdkAesKeySize KeyLength; + NvU8 * pSecureStorageKey; +} NV_ALIGN(4) NvDdkAesSetAndLockSecureStorageKey_in; + +typedef struct NvDdkAesSetAndLockSecureStorageKey_inout_t +{ + NvU32 dummy_; +} NV_ALIGN(4) NvDdkAesSetAndLockSecureStorageKey_inout; + +typedef struct NvDdkAesSetAndLockSecureStorageKey_out_t +{ + NvError ret_; +} NV_ALIGN(4) NvDdkAesSetAndLockSecureStorageKey_out; + +typedef struct NvDdkAesSetAndLockSecureStorageKey_params_t +{ + NvDdkAesSetAndLockSecureStorageKey_in in; + NvDdkAesSetAndLockSecureStorageKey_inout inout; + NvDdkAesSetAndLockSecureStorageKey_out out; +} NvDdkAesSetAndLockSecureStorageKey_params; + +typedef struct NvDdkAesLockSecureStorageKey_in_t +{ + NvU32 package_; + NvU32 function_; + NvDdkAesHandle hAes; +} NV_ALIGN(4) NvDdkAesLockSecureStorageKey_in; + +typedef struct NvDdkAesLockSecureStorageKey_inout_t +{ + NvU32 dummy_; +} NV_ALIGN(4) NvDdkAesLockSecureStorageKey_inout; + +typedef struct NvDdkAesLockSecureStorageKey_out_t +{ + NvError ret_; +} NV_ALIGN(4) NvDdkAesLockSecureStorageKey_out; + +typedef struct NvDdkAesLockSecureStorageKey_params_t +{ + NvDdkAesLockSecureStorageKey_in in; + NvDdkAesLockSecureStorageKey_inout inout; + NvDdkAesLockSecureStorageKey_out out; +} NvDdkAesLockSecureStorageKey_params; + +typedef struct NvDdkAesClearSecureBootKey_in_t +{ + NvU32 package_; + NvU32 function_; + NvDdkAesHandle hAes; +} NV_ALIGN(4) NvDdkAesClearSecureBootKey_in; + +typedef struct NvDdkAesClearSecureBootKey_inout_t +{ + NvU32 dummy_; +} NV_ALIGN(4) NvDdkAesClearSecureBootKey_inout; + +typedef struct NvDdkAesClearSecureBootKey_out_t +{ + NvError ret_; +} NV_ALIGN(4) NvDdkAesClearSecureBootKey_out; + +typedef struct NvDdkAesClearSecureBootKey_params_t +{ + NvDdkAesClearSecureBootKey_in in; + NvDdkAesClearSecureBootKey_inout inout; + NvDdkAesClearSecureBootKey_out out; +} NvDdkAesClearSecureBootKey_params; + +typedef struct NvDdkAesGetCapabilities_in_t +{ + NvU32 package_; + NvU32 function_; + NvDdkAesHandle hAes; +} NV_ALIGN(4) NvDdkAesGetCapabilities_in; + +typedef struct NvDdkAesGetCapabilities_inout_t +{ + NvDdkAesCapabilities pCapabilities; +} NV_ALIGN(4) NvDdkAesGetCapabilities_inout; + +typedef struct NvDdkAesGetCapabilities_out_t +{ + NvError ret_; +} NV_ALIGN(4) NvDdkAesGetCapabilities_out; + +typedef struct NvDdkAesGetCapabilities_params_t +{ + NvDdkAesGetCapabilities_in in; + NvDdkAesGetCapabilities_inout inout; + NvDdkAesGetCapabilities_out out; +} NvDdkAesGetCapabilities_params; + +typedef struct NvDdkAesProcessBuffer_in_t +{ + NvU32 package_; + NvU32 function_; + NvDdkAesHandle hAes; + NvU32 SrcBufferSize; + NvU32 DestBufferSize; + NvU8 * pSrcBuffer; + NvU8 * pDestBuffer; +} NV_ALIGN(4) NvDdkAesProcessBuffer_in; + +typedef struct NvDdkAesProcessBuffer_inout_t +{ + NvU32 dummy_; +} NV_ALIGN(4) NvDdkAesProcessBuffer_inout; + +typedef struct NvDdkAesProcessBuffer_out_t +{ + NvError ret_; +} NV_ALIGN(4) NvDdkAesProcessBuffer_out; + +typedef struct NvDdkAesProcessBuffer_params_t +{ + NvDdkAesProcessBuffer_in in; + NvDdkAesProcessBuffer_inout inout; + NvDdkAesProcessBuffer_out out; +} NvDdkAesProcessBuffer_params; + +typedef struct NvDdkAesGetInitialVector_in_t +{ + NvU32 package_; + NvU32 function_; + NvDdkAesHandle hAes; + NvU32 VectorSize; + NvU8 * pInitialVector; +} NV_ALIGN(4) NvDdkAesGetInitialVector_in; + +typedef struct NvDdkAesGetInitialVector_inout_t +{ + NvU32 dummy_; +} NV_ALIGN(4) NvDdkAesGetInitialVector_inout; + +typedef struct NvDdkAesGetInitialVector_out_t +{ + NvError ret_; +} NV_ALIGN(4) NvDdkAesGetInitialVector_out; + +typedef struct NvDdkAesGetInitialVector_params_t +{ + NvDdkAesGetInitialVector_in in; + NvDdkAesGetInitialVector_inout inout; + NvDdkAesGetInitialVector_out out; +} NvDdkAesGetInitialVector_params; + +typedef struct NvDdkAesSetInitialVector_in_t +{ + NvU32 package_; + NvU32 function_; + NvDdkAesHandle hAes; + NvU8 * pInitialVector; + NvU32 VectorSize; +} NV_ALIGN(4) NvDdkAesSetInitialVector_in; + +typedef struct NvDdkAesSetInitialVector_inout_t +{ + NvU32 dummy_; +} NV_ALIGN(4) NvDdkAesSetInitialVector_inout; + +typedef struct NvDdkAesSetInitialVector_out_t +{ + NvError ret_; +} NV_ALIGN(4) NvDdkAesSetInitialVector_out; + +typedef struct NvDdkAesSetInitialVector_params_t +{ + NvDdkAesSetInitialVector_in in; + NvDdkAesSetInitialVector_inout inout; + NvDdkAesSetInitialVector_out out; +} NvDdkAesSetInitialVector_params; + +typedef struct NvDdkAesSelectOperation_in_t +{ + NvU32 package_; + NvU32 function_; + NvDdkAesHandle hAes; + NvDdkAesOperation pOperation; +} NV_ALIGN(4) NvDdkAesSelectOperation_in; + +typedef struct NvDdkAesSelectOperation_inout_t +{ + NvU32 dummy_; +} NV_ALIGN(4) NvDdkAesSelectOperation_inout; + +typedef struct NvDdkAesSelectOperation_out_t +{ + NvError ret_; +} NV_ALIGN(4) NvDdkAesSelectOperation_out; + +typedef struct NvDdkAesSelectOperation_params_t +{ + NvDdkAesSelectOperation_in in; + NvDdkAesSelectOperation_inout inout; + NvDdkAesSelectOperation_out out; +} NvDdkAesSelectOperation_params; + +typedef struct NvDdkAesSelectKey_in_t +{ + NvU32 package_; + NvU32 function_; + NvDdkAesHandle hAes; + NvDdkAesKeyInfo pKeyInfo; +} NV_ALIGN(4) NvDdkAesSelectKey_in; + +typedef struct NvDdkAesSelectKey_inout_t +{ + NvU32 dummy_; +} NV_ALIGN(4) NvDdkAesSelectKey_inout; + +typedef struct NvDdkAesSelectKey_out_t +{ + NvError ret_; +} NV_ALIGN(4) NvDdkAesSelectKey_out; + +typedef struct NvDdkAesSelectKey_params_t +{ + NvDdkAesSelectKey_in in; + NvDdkAesSelectKey_inout inout; + NvDdkAesSelectKey_out out; +} NvDdkAesSelectKey_params; + +typedef struct NvDdkAesClose_in_t +{ + NvU32 package_; + NvU32 function_; + NvDdkAesHandle hAes; +} NV_ALIGN(4) NvDdkAesClose_in; + +typedef struct NvDdkAesClose_inout_t +{ + NvU32 dummy_; +} NV_ALIGN(4) NvDdkAesClose_inout; + +typedef struct NvDdkAesClose_out_t +{ + NvU32 dummy_; +} NV_ALIGN(4) NvDdkAesClose_out; + +typedef struct NvDdkAesClose_params_t +{ + NvDdkAesClose_in in; + NvDdkAesClose_inout inout; + NvDdkAesClose_out out; +} NvDdkAesClose_params; + +typedef struct NvDdkAesOpen_in_t +{ + NvU32 package_; + NvU32 function_; + NvU32 InstanceId; +} NV_ALIGN(4) NvDdkAesOpen_in; + +typedef struct NvDdkAesOpen_inout_t +{ + NvU32 dummy_; +} NV_ALIGN(4) NvDdkAesOpen_inout; + +typedef struct NvDdkAesOpen_out_t +{ + NvError ret_; + NvDdkAesHandle phAes; +} NV_ALIGN(4) NvDdkAesOpen_out; + +typedef struct NvDdkAesOpen_params_t +{ + NvDdkAesOpen_in in; + NvDdkAesOpen_inout inout; + NvDdkAesOpen_out out; +} NvDdkAesOpen_params; + +static NvError NvDdkAesDisableCrypto_dispatch_( void *InBuffer, NvU32 InSize, void *OutBuffer, NvU32 OutSize, NvDispatchCtx* Ctx ) +{ + NvError err_ = NvSuccess; + NvDdkAesDisableCrypto_in *p_in; + NvDdkAesDisableCrypto_out *p_out; + + p_in = (NvDdkAesDisableCrypto_in *)InBuffer; + p_out = (NvDdkAesDisableCrypto_out *)((NvU8 *)OutBuffer + OFFSET(NvDdkAesDisableCrypto_params, out) - OFFSET(NvDdkAesDisableCrypto_params, inout)); + + + p_out->ret_ = NvDdkAesDisableCrypto( p_in->hAes ); + + return err_; +} + +static NvError NvDdkAesSetAndLockSecureStorageKey_dispatch_( void *InBuffer, NvU32 InSize, void *OutBuffer, NvU32 OutSize, NvDispatchCtx* Ctx ) +{ + NvError err_ = NvSuccess; + NvDdkAesSetAndLockSecureStorageKey_in *p_in; + NvDdkAesSetAndLockSecureStorageKey_out *p_out; + NvU8 *pSecureStorageKey = NULL; + + p_in = (NvDdkAesSetAndLockSecureStorageKey_in *)InBuffer; + p_out = (NvDdkAesSetAndLockSecureStorageKey_out *)((NvU8 *)OutBuffer + OFFSET(NvDdkAesSetAndLockSecureStorageKey_params, out) - OFFSET(NvDdkAesSetAndLockSecureStorageKey_params, inout)); + + if( p_in->KeyLength && p_in->pSecureStorageKey ) + { + pSecureStorageKey = (NvU8 *)NvOsAlloc( p_in->KeyLength * sizeof( NvU8 ) ); + if( !pSecureStorageKey ) + { + err_ = NvError_InsufficientMemory; + goto clean; + } + if( p_in->pSecureStorageKey ) + { + err_ = NvOsCopyIn( pSecureStorageKey, p_in->pSecureStorageKey, p_in->KeyLength * sizeof( NvU8 ) ); + if( err_ != NvSuccess ) + { + err_ = NvError_BadParameter; + goto clean; + } + } + } + + p_out->ret_ = NvDdkAesSetAndLockSecureStorageKey( p_in->hAes, p_in->KeyLength, pSecureStorageKey ); + +clean: + NvOsFree( pSecureStorageKey ); + return err_; +} + +static NvError NvDdkAesLockSecureStorageKey_dispatch_( void *InBuffer, NvU32 InSize, void *OutBuffer, NvU32 OutSize, NvDispatchCtx* Ctx ) +{ + NvError err_ = NvSuccess; + NvDdkAesLockSecureStorageKey_in *p_in; + NvDdkAesLockSecureStorageKey_out *p_out; + + p_in = (NvDdkAesLockSecureStorageKey_in *)InBuffer; + p_out = (NvDdkAesLockSecureStorageKey_out *)((NvU8 *)OutBuffer + OFFSET(NvDdkAesLockSecureStorageKey_params, out) - OFFSET(NvDdkAesLockSecureStorageKey_params, inout)); + + + p_out->ret_ = NvDdkAesLockSecureStorageKey( p_in->hAes ); + + return err_; +} + +static NvError NvDdkAesClearSecureBootKey_dispatch_( void *InBuffer, NvU32 InSize, void *OutBuffer, NvU32 OutSize, NvDispatchCtx* Ctx ) +{ + NvError err_ = NvSuccess; + NvDdkAesClearSecureBootKey_in *p_in; + NvDdkAesClearSecureBootKey_out *p_out; + + p_in = (NvDdkAesClearSecureBootKey_in *)InBuffer; + p_out = (NvDdkAesClearSecureBootKey_out *)((NvU8 *)OutBuffer + OFFSET(NvDdkAesClearSecureBootKey_params, out) - OFFSET(NvDdkAesClearSecureBootKey_params, inout)); + + + p_out->ret_ = NvDdkAesClearSecureBootKey( p_in->hAes ); + + return err_; +} + +static NvError NvDdkAesGetCapabilities_dispatch_( void *InBuffer, NvU32 InSize, void *OutBuffer, NvU32 OutSize, NvDispatchCtx* Ctx ) +{ + NvError err_ = NvSuccess; + NvDdkAesGetCapabilities_in *p_in; + NvDdkAesGetCapabilities_inout *p_inout; + NvDdkAesGetCapabilities_out *p_out; + NvDdkAesGetCapabilities_inout inout; + + p_in = (NvDdkAesGetCapabilities_in *)InBuffer; + p_inout = (NvDdkAesGetCapabilities_inout *)((NvU8 *)InBuffer + OFFSET(NvDdkAesGetCapabilities_params, inout)); + p_out = (NvDdkAesGetCapabilities_out *)((NvU8 *)OutBuffer + OFFSET(NvDdkAesGetCapabilities_params, out) - OFFSET(NvDdkAesGetCapabilities_params, inout)); + + (void)inout; + inout.pCapabilities = p_inout->pCapabilities; + + p_out->ret_ = NvDdkAesGetCapabilities( p_in->hAes, &inout.pCapabilities ); + + + p_inout = (NvDdkAesGetCapabilities_inout *)OutBuffer; + p_inout->pCapabilities = inout.pCapabilities; + return err_; +} + +static NvError NvDdkAesProcessBuffer_dispatch_( void *InBuffer, NvU32 InSize, void *OutBuffer, NvU32 OutSize, NvDispatchCtx* Ctx ) +{ + NvError err_ = NvSuccess; + NvDdkAesProcessBuffer_in *p_in; + NvDdkAesProcessBuffer_out *p_out; + NvU8 *pSrcBuffer = NULL; + NvU8 *pDestBuffer = NULL; + + p_in = (NvDdkAesProcessBuffer_in *)InBuffer; + p_out = (NvDdkAesProcessBuffer_out *)((NvU8 *)OutBuffer + OFFSET(NvDdkAesProcessBuffer_params, out) - OFFSET(NvDdkAesProcessBuffer_params, inout)); + + if( p_in->SrcBufferSize && p_in->pSrcBuffer ) + { + pSrcBuffer = (NvU8 *)NvOsAlloc( p_in->SrcBufferSize * sizeof( NvU8 ) ); + if( !pSrcBuffer ) + { + err_ = NvError_InsufficientMemory; + goto clean; + } + if( p_in->pSrcBuffer ) + { + err_ = NvOsCopyIn( pSrcBuffer, p_in->pSrcBuffer, p_in->SrcBufferSize * sizeof( NvU8 ) ); + if( err_ != NvSuccess ) + { + err_ = NvError_BadParameter; + goto clean; + } + } + } + if( p_in->DestBufferSize && p_in->pDestBuffer ) + { + pDestBuffer = (NvU8 *)NvOsAlloc( p_in->DestBufferSize * sizeof( NvU8 ) ); + if( !pDestBuffer ) + { + err_ = NvError_InsufficientMemory; + goto clean; + } + if( p_in->pDestBuffer ) + { + err_ = NvOsCopyIn( pDestBuffer, p_in->pDestBuffer, p_in->DestBufferSize * sizeof( NvU8 ) ); + if( err_ != NvSuccess ) + { + err_ = NvError_BadParameter; + goto clean; + } + } + } + + p_out->ret_ = NvDdkAesProcessBuffer( p_in->hAes, p_in->SrcBufferSize, p_in->DestBufferSize, pSrcBuffer, pDestBuffer ); + + if(p_in->pDestBuffer && pDestBuffer) + { + err_ = NvOsCopyOut( p_in->pDestBuffer, pDestBuffer, p_in->DestBufferSize * sizeof( NvU8 ) ); + if( err_ != NvSuccess ) + { + err_ = NvError_BadParameter; + } + } +clean: + NvOsFree( pSrcBuffer ); + NvOsFree( pDestBuffer ); + return err_; +} + +static NvError NvDdkAesGetInitialVector_dispatch_( void *InBuffer, NvU32 InSize, void *OutBuffer, NvU32 OutSize, NvDispatchCtx* Ctx ) +{ + NvError err_ = NvSuccess; + NvDdkAesGetInitialVector_in *p_in; + NvDdkAesGetInitialVector_out *p_out; + NvU8 *pInitialVector = NULL; + + p_in = (NvDdkAesGetInitialVector_in *)InBuffer; + p_out = (NvDdkAesGetInitialVector_out *)((NvU8 *)OutBuffer + OFFSET(NvDdkAesGetInitialVector_params, out) - OFFSET(NvDdkAesGetInitialVector_params, inout)); + + if( p_in->VectorSize && p_in->pInitialVector ) + { + pInitialVector = (NvU8 *)NvOsAlloc( p_in->VectorSize * sizeof( NvU8 ) ); + if( !pInitialVector ) + { + err_ = NvError_InsufficientMemory; + goto clean; + } + if( p_in->pInitialVector ) + { + err_ = NvOsCopyIn( pInitialVector, p_in->pInitialVector, p_in->VectorSize * sizeof( NvU8 ) ); + if( err_ != NvSuccess ) + { + err_ = NvError_BadParameter; + goto clean; + } + } + } + + p_out->ret_ = NvDdkAesGetInitialVector( p_in->hAes, p_in->VectorSize, pInitialVector ); + + if(p_in->pInitialVector && pInitialVector) + { + err_ = NvOsCopyOut( p_in->pInitialVector, pInitialVector, p_in->VectorSize * sizeof( NvU8 ) ); + if( err_ != NvSuccess ) + { + err_ = NvError_BadParameter; + } + } +clean: + NvOsFree( pInitialVector ); + return err_; +} + +static NvError NvDdkAesSetInitialVector_dispatch_( void *InBuffer, NvU32 InSize, void *OutBuffer, NvU32 OutSize, NvDispatchCtx* Ctx ) +{ + NvError err_ = NvSuccess; + NvDdkAesSetInitialVector_in *p_in; + NvDdkAesSetInitialVector_out *p_out; + NvU8 *pInitialVector = NULL; + + p_in = (NvDdkAesSetInitialVector_in *)InBuffer; + p_out = (NvDdkAesSetInitialVector_out *)((NvU8 *)OutBuffer + OFFSET(NvDdkAesSetInitialVector_params, out) - OFFSET(NvDdkAesSetInitialVector_params, inout)); + + if( p_in->VectorSize && p_in->pInitialVector ) + { + pInitialVector = (NvU8 *)NvOsAlloc( p_in->VectorSize * sizeof( NvU8 ) ); + if( !pInitialVector ) + { + err_ = NvError_InsufficientMemory; + goto clean; + } + if( p_in->pInitialVector ) + { + err_ = NvOsCopyIn( pInitialVector, p_in->pInitialVector, p_in->VectorSize * sizeof( NvU8 ) ); + if( err_ != NvSuccess ) + { + err_ = NvError_BadParameter; + goto clean; + } + } + } + + p_out->ret_ = NvDdkAesSetInitialVector( p_in->hAes, pInitialVector, p_in->VectorSize ); + +clean: + NvOsFree( pInitialVector ); + return err_; +} + +static NvError NvDdkAesSelectOperation_dispatch_( void *InBuffer, NvU32 InSize, void *OutBuffer, NvU32 OutSize, NvDispatchCtx* Ctx ) +{ + NvError err_ = NvSuccess; + NvDdkAesSelectOperation_in *p_in; + NvDdkAesSelectOperation_out *p_out; + + p_in = (NvDdkAesSelectOperation_in *)InBuffer; + p_out = (NvDdkAesSelectOperation_out *)((NvU8 *)OutBuffer + OFFSET(NvDdkAesSelectOperation_params, out) - OFFSET(NvDdkAesSelectOperation_params, inout)); + + + p_out->ret_ = NvDdkAesSelectOperation( p_in->hAes, &p_in->pOperation ); + + return err_; +} + +static NvError NvDdkAesSelectKey_dispatch_( void *InBuffer, NvU32 InSize, void *OutBuffer, NvU32 OutSize, NvDispatchCtx* Ctx ) +{ + NvError err_ = NvSuccess; + NvDdkAesSelectKey_in *p_in; + NvDdkAesSelectKey_out *p_out; + + p_in = (NvDdkAesSelectKey_in *)InBuffer; + p_out = (NvDdkAesSelectKey_out *)((NvU8 *)OutBuffer + OFFSET(NvDdkAesSelectKey_params, out) - OFFSET(NvDdkAesSelectKey_params, inout)); + + + p_out->ret_ = NvDdkAesSelectKey( p_in->hAes, &p_in->pKeyInfo ); + + return err_; +} + +static NvError NvDdkAesClose_dispatch_( void *InBuffer, NvU32 InSize, void *OutBuffer, NvU32 OutSize, NvDispatchCtx* Ctx ) +{ + NvError err_ = NvSuccess; + NvDdkAesClose_in *p_in; + + p_in = (NvDdkAesClose_in *)InBuffer; + + if (p_in->hAes != NULL) NvRtFreeObjRef(Ctx, NvRtObjType_NvDdkAes_NvDdkAesHandle, p_in->hAes); + + NvDdkAesClose( p_in->hAes ); + + return err_; +} + +static NvError NvDdkAesOpen_dispatch_( void *InBuffer, NvU32 InSize, void *OutBuffer, NvU32 OutSize, NvDispatchCtx* Ctx ) +{ + NvError err_ = NvSuccess; + NvDdkAesOpen_in *p_in; + NvDdkAesOpen_out *p_out; + NvRtObjRefHandle ref_phAes = 0; + + p_in = (NvDdkAesOpen_in *)InBuffer; + p_out = (NvDdkAesOpen_out *)((NvU8 *)OutBuffer + OFFSET(NvDdkAesOpen_params, out) - OFFSET(NvDdkAesOpen_params, inout)); + + err_ = NvRtAllocObjRef(Ctx, &ref_phAes); + if (err_ != NvSuccess) + { + goto clean; + } + + p_out->ret_ = NvDdkAesOpen( p_in->InstanceId, &p_out->phAes ); + + if ( p_out->ret_ == NvSuccess ) + { + NvRtStoreObjRef(Ctx, ref_phAes, NvRtObjType_NvDdkAes_NvDdkAesHandle, p_out->phAes); + ref_phAes = 0; + } +clean: + if (ref_phAes) NvRtDiscardObjRef(Ctx, ref_phAes); + return err_; +} + +NvError nvddk_aes_Dispatch( NvU32 function, void *InBuffer, NvU32 InSize, void *OutBuffer, NvU32 OutSize, NvDispatchCtx* Ctx ); +NvError nvddk_aes_Dispatch( NvU32 function, void *InBuffer, NvU32 InSize, void *OutBuffer, NvU32 OutSize, NvDispatchCtx* Ctx ) +{ + NvError err_ = NvSuccess; + + switch( function ) { + case 11: + err_ = NvDdkAesDisableCrypto_dispatch_( InBuffer, InSize, OutBuffer, OutSize, Ctx ); + break; + case 10: + err_ = NvDdkAesSetAndLockSecureStorageKey_dispatch_( InBuffer, InSize, OutBuffer, OutSize, Ctx ); + break; + case 9: + err_ = NvDdkAesLockSecureStorageKey_dispatch_( InBuffer, InSize, OutBuffer, OutSize, Ctx ); + break; + case 8: + err_ = NvDdkAesClearSecureBootKey_dispatch_( InBuffer, InSize, OutBuffer, OutSize, Ctx ); + break; + case 7: + err_ = NvDdkAesGetCapabilities_dispatch_( InBuffer, InSize, OutBuffer, OutSize, Ctx ); + break; + case 6: + err_ = NvDdkAesProcessBuffer_dispatch_( InBuffer, InSize, OutBuffer, OutSize, Ctx ); + break; + case 5: + err_ = NvDdkAesGetInitialVector_dispatch_( InBuffer, InSize, OutBuffer, OutSize, Ctx ); + break; + case 4: + err_ = NvDdkAesSetInitialVector_dispatch_( InBuffer, InSize, OutBuffer, OutSize, Ctx ); + break; + case 3: + err_ = NvDdkAesSelectOperation_dispatch_( InBuffer, InSize, OutBuffer, OutSize, Ctx ); + break; + case 2: + err_ = NvDdkAesSelectKey_dispatch_( InBuffer, InSize, OutBuffer, OutSize, Ctx ); + break; + case 1: + err_ = NvDdkAesClose_dispatch_( InBuffer, InSize, OutBuffer, OutSize, Ctx ); + break; + case 0: + err_ = NvDdkAesOpen_dispatch_( InBuffer, InSize, OutBuffer, OutSize, Ctx ); + break; + default: + err_ = NvError_BadParameter; + break; + } + + return err_; +} diff --git a/arch/arm/mach-tegra/nvddk/nvddk_aes_hw.h b/arch/arm/mach-tegra/nvddk/nvddk_aes_hw.h new file mode 100644 index 000000000000..bbdb2750a106 --- /dev/null +++ b/arch/arm/mach-tegra/nvddk/nvddk_aes_hw.h @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2007-2009 NVIDIA Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of the NVIDIA Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef INCLUDED_NVDDK_AES_HW_H +#define INCLUDED_NVDDK_AES_HW_H + +#include "nverror.h" +#include "nvcommon.h" + +#ifndef NV_OAL +#define NV_OAL 0 +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + +/** + * The key table length is 64 bytes. + * (This includes first upto 32 bytes key + 16 bytes original initial + * vector and 16 bytes updated initial vector) + */ +enum {AES_HW_KEY_TABLE_LENGTH_BYTES = 64}; + +/** + * Keytable array, this must be in the IRAM. + */ +enum {AES_HW_KEY_TABLE_ADDR_ALIGNMENT = 256}; + +/** + * The key Table length is 256 bytes = 64 words, (32 bit each word). + * (This includes first 16 bytes key + 224 bytes + * Key expantion data + 16 bytes Initial vector) + */ +enum {AES_HW_KEY_SCHEDULE_LENGTH = 64}; + +/** + * The key Table length is 64 bytes = 16 words, (32 bit each word). + */ +enum {AES_HW_KEY_TABLE_LENGTH = 16}; + +#if NV_OAL +/* + * Key table address must be in the IRAM. + */ +enum {NVBL_AES_KEY_TABLE_ADDR = 0x40001d00}; + +/** + * DMA Buffer size for processing the encryption and decryption with H/W. + * Each engine is allocated 4 Kilo Bytes buffer for data processing. + * This buffer is shared for both input data and out put data. + */ +enum {AES_HW_DMA_BUFFER_SIZE_BYTES = 0x1000}; + +#else + +/* + * Key table address must be in the IRAM. + */ +enum {NVBL_AES_KEY_TABLE_OFFSET = 0x1d00}; + +/** + * DMA Buffer size for processing the encryption and decryption with H/W. + * Each engine is allocated 32 Kilo Bytes buffer for data processing. + * This buffer is shared for both input data and out put data. + */ +enum {AES_HW_DMA_BUFFER_SIZE_BYTES = 0x8000}; + +/** + * Define AES engine Max process bytes size in one go, which takes 1 msec. + * AES engine spends about 176 cycles/16-bytes or 11 cycles/byte + * The duration CPU can use the BSE to 1 msec, then the number of available + * cycles of AVP/BSE is 216K. In this duration, AES can process 216/11 ~= 19 KBytes + * Based on this AES_HW_MAX_PROCESS_SIZE_BYTES is configured to 16KB. + */ +enum {AES_HW_MAX_PROCESS_SIZE_BYTES = 0x4000}; + +#endif // NV_OAL + +/** + * DMA data buffer address alignment. + */ +enum {AES_HW_DMA_ADDR_ALIGNMENT = 16}; + +/** + * The Initial Vector length in the 32 bit words. (128 bits = 4 words) + */ +enum {AES_HW_IV_LENGTH = 4}; + +/** + * The Initial Vector length in the 32 bit words. (128 bits = 4 words) + */ +enum {AES_HW_KEY_LENGTH = 4}; + +/** + * Define AES block length in the 32 bit words (128-bits = 4 words) + */ +enum {AES_HW_BLOCK_LENGTH = 4}; + +/** + * Define AES block length in log2 bytes = 2^4 = 16 bytes. + */ +enum {AES_HW_BLOCK_LENGTH_LOG2 = 4}; + +/** + * AES Key (128 bits). + */ +typedef struct AesHwKeyRec +{ + NvU32 key[AES_HW_KEY_LENGTH]; +} AesHwKey; + +/** + * AES Initial Vector (128 bits). + */ +typedef struct AesHwIvRec +{ + NvU32 iv[AES_HW_IV_LENGTH]; +} AesHwIv; + +#if defined(__cplusplus) +} +#endif + +#endif // INCLUDED_AES_HW_H diff --git a/arch/arm/mach-tegra/nvddk/nvddk_aes_intf_ap20.c b/arch/arm/mach-tegra/nvddk/nvddk_aes_intf_ap20.c new file mode 100644 index 000000000000..2e86e6e0ae27 --- /dev/null +++ b/arch/arm/mach-tegra/nvddk/nvddk_aes_intf_ap20.c @@ -0,0 +1,701 @@ +/* + * Copyright (c) 2007-2009 NVIDIA Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of the NVIDIA Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "nvos.h" +#include "nvassert.h" +#include "nvrm_drf.h" +#include "nvrm_hardware_access.h" +#include "nvrm_init.h" +#include "ap20/arvde_bsev_aes.h" +#include "ap20/aravp_bsea_aes.h" +#include "nvddk_aes_common.h" +#include "nvddk_aes_priv.h" +#include "nvddk_aes_core_ap20.h" + +/** + * SBK and SSK settings. + */ +enum {AES_SBK_ENGINE_A = AesHwEngine_A}; +enum {AES_SBK_ENGINE_B = AesHwEngine_B}; +enum {AES_SBK_ENCRYPT_SLOT = AesHwKeySlot_0}; +enum {AES_SBK_DECRYPT_SLOT = AES_SBK_ENCRYPT_SLOT}; + +enum {AES_SSK_ENGINE_A = AesHwEngine_A}; +enum {AES_SSK_ENGINE_B = AesHwEngine_B}; +enum {AES_SSK_ENCRYPT_SLOT = AesHwKeySlot_4}; +enum {AES_SSK_DECRYPT_SLOT = AES_SSK_ENCRYPT_SLOT}; + +static void +Ap20AesSetupTable( + const AesHwEngine Engine, + const AesHwKeySlot Slot, + AesHwContext *const pAesHwCtxt); +static void +Ap20AesHwSelectKeyIvSlot( + const AesHwEngine Engine, + const AesHwKeySlot Slot, + AesHwContext *const pAesHwCtxt); +static void +Ap20AesHwClearKeyAndIv( + const AesHwEngine Engine, + const AesHwKeySlot Slot, + AesHwContext *const pAesHwCtxt); +static void +Ap20AesHwClearIv( + const AesHwEngine Engine, + const AesHwKeySlot Slot, + AesHwContext *const pAesHwCtxt); +static void +Ap20AesHwGetIv( + const AesHwContext *const pAesHwCtxt, + const AesHwEngine Engine, + const AesHwKeySlot Slot, + AesHwIv *const pIv); +static void +Ap20AesHwLockSskReadWrites( + const AesHwContext *const pAesHwCtxt, + const AesHwEngine SskEngine); +static void +Ap20AesHwLoadSskToSecureScratchAndLock( + const NvRmPhysAddr PmicBaseAddr, + const AesHwKey *const pKey, + const size_t Size); +static void Ap20AesHwGetUsedSlots(AesCoreEngine *const pAesCoreEngine); +static void Ap20AesHwGetIvReadPermissions(const AesHwEngine Engine, AesHwContext *const pAesHwCtxt); +static void +Ap20AesHwSetKeyAndIv( + const AesHwEngine Engine, + const AesHwKeySlot Slot, + const AesHwKey *const pKey, + const AesHwIv *const pIv, + const NvBool IsEncryption, + AesHwContext *const pAesHwCtxt); + +static NvBool Ap20AesHwIsEngineDisabled(const AesHwContext *const pAesHwCtxt, const AesHwEngine Engine); + +static NvError Ap20AesHwDisableEngine(const AesHwContext *const pAesHwCtxt, const AesHwEngine Engine); +static NvError +Ap20AesHwStartEngine( + const AesHwEngine Engine, + const NvU32 DataSize, + const NvU8 *const pSrc, + const NvBool IsEncryption, + const NvDdkAesOperationalMode OpMode, + NvU8 *const pDest, + AesHwContext *const pAesHwCtxt); +static NvError +Ap20AesHwSetIv( + const AesHwEngine Engine, + const AesHwKeySlot Slot, + const AesHwIv *const pIv, + AesHwContext *const pAesHwCtxt); + +/** + * Set the Setup Table command required for the AES engine. + * + * @param Engine AES engine to setup the Key table. + * @param Slot AES Key slot to use for setting up the key table. + * @param pAesHwCtxt Pointer to the AES H/W context. + * + * @retval None. + */ +void +Ap20AesSetupTable( + const AesHwEngine Engine, + const AesHwKeySlot Slot, + AesHwContext *const pAesHwCtxt) +{ + NV_ASSERT(pAesHwCtxt); + + NvAesCoreAp20SetupTable(Engine, pAesHwCtxt->pVirAdr[Engine], pAesHwCtxt->KeyTablePhyAddr[Engine], Slot); + + NvOsMemcpy(&pAesHwCtxt->IvContext[Engine].CurIv[Slot], + (void *)(&pAesHwCtxt->pKeyTableVirAddr[Engine][AES_HW_KEY_TABLE_LENGTH - AES_HW_IV_LENGTH]), + NvDdkAesConst_BlockLengthBytes); + + // Clear key table in the memory after updating the H/W + NvOsMemset(pAesHwCtxt->pKeyTableVirAddr[Engine], 0, pAesHwCtxt->KeyTableSize[Engine]); +} + +/** + * Select the key and iv from the internal key table for a specified key slot. + * + * @param Engine AES engine. + * @param Slot Key slot for which key and IV needs to be selected. + * @param pAesHwCtxt Pointer to the AES H/W context. + * + * @retval None. + */ +void +Ap20AesHwSelectKeyIvSlot( + const AesHwEngine Engine, + const AesHwKeySlot Slot, + AesHwContext *const pAesHwCtxt) +{ + NV_ASSERT(pAesHwCtxt); + + NvOsMutexLock(pAesHwCtxt->Mutex[Engine]); + + // Wait till engine becomes IDLE + NvAesCoreAp20WaitTillEngineIdle(Engine, pAesHwCtxt->pVirAdr[Engine]); + + // Allow or disallow X9.31 operations + pAesHwCtxt->IsX931OpsDisallowed = !pAesHwCtxt->IvContext[Engine].IsIvReadable[Slot]; + + // Select the KEY slot for updating the IV vectors + NvAesCoreAp20SelectKeyIvSlot(Engine, pAesHwCtxt->pVirAdr[Engine], Slot); + + pAesHwCtxt->IvContext[Engine].CurKeySlot = Slot; + + NvOsMutexUnlock(pAesHwCtxt->Mutex[Engine]); +} + +/** + * Disable the selected AES engine. No further operations can be + * performed using the AES engine until the entire chip is reset. + * + * @param pAesHwCtxt Pointer to the AES H/W context. + * @param Engine AES engine to disable. + * + * @retval NvSuccess if engine successfully disabled else NvError_AesDisableCryptoFailed. + */ +NvError Ap20AesHwDisableEngine(const AesHwContext *const pAesHwCtxt, const AesHwEngine Engine) +{ + NvError e; + + NV_ASSERT(pAesHwCtxt); + + NvOsMutexLock(pAesHwCtxt->Mutex[Engine]); + + // Wait till engine becomes IDLE + NvAesCoreAp20WaitTillEngineIdle(Engine, pAesHwCtxt->pVirAdr[Engine]); + + e = NvAesCoreAp20DisableEngine(Engine, pAesHwCtxt->pVirAdr[Engine]); + + NvOsMutexUnlock(pAesHwCtxt->Mutex[Engine]); + + return e; +} + +/** + * Over-write the key schedule and Initial Vector in the in the specified + * key slot with zeroes. Convenient for preventing subsequent callers from + * gaining access to a previously-used key. + * + * @param Engine AES engine. + * @param Slot key slot to clear. + * @param pAesHwCtxt Pointer to the AES H/W context. + * + * @retval None. + */ +void +Ap20AesHwClearKeyAndIv( + const AesHwEngine Engine, + const AesHwKeySlot Slot, + AesHwContext *const pAesHwCtxt) +{ + NV_ASSERT(pAesHwCtxt); + + NvOsMutexLock(pAesHwCtxt->Mutex[Engine]); + + // Wait till engine becomes IDLE + NvAesCoreAp20WaitTillEngineIdle(Engine, pAesHwCtxt->pVirAdr[Engine]); + + // Clear Key table this clears both Key Schedule and IV in key table + NvOsMemset(pAesHwCtxt->pKeyTableVirAddr[Engine], 0, pAesHwCtxt->KeyTableSize[Engine]); + + // Setup the key table with Zero key and Zero Iv + Ap20AesHwSelectKeyIvSlot(Engine, Slot, pAesHwCtxt); + Ap20AesSetupTable(Engine, Slot, pAesHwCtxt); + + NvOsMutexUnlock(pAesHwCtxt->Mutex[Engine]); +} + +/** + * Over-write the initial vector in the specified AES engine with zeroes. + * Convenient to prevent subsequent callers from gaining access to a + * previously-used initial vector. + * + * @param Engine AES engine. + * @param Slot Key slot for which Iv needs to be cleared. + * @param pAesHwCtxt Pointer to the AES H/W context. + * + * @retval None. + */ +void +Ap20AesHwClearIv( + const AesHwEngine Engine, + const AesHwKeySlot Slot, + AesHwContext *const pAesHwCtxt) +{ + NV_ASSERT(pAesHwCtxt); + NV_ASSERT(pAesHwCtxt->pKeyTableVirAddr[Engine]); + + NvOsMemset((void *)pAesHwCtxt->pKeyTableVirAddr[Engine], 0, NvDdkAesConst_IVLengthBytes); + + Ap20AesHwStartEngine( + Engine, + NvDdkAesConst_IVLengthBytes, + pAesHwCtxt->pKeyTableVirAddr[Engine], + NV_FALSE, + NvDdkAesOperationalMode_Cbc, + pAesHwCtxt->pKeyTableVirAddr[Engine], + pAesHwCtxt); +} + +/** + * Compute key schedule for the given key, then load key schedule and + * initial vector into the specified key slot. + * + * @param Engine AES engine. + * @param Slot Key slot to load. + * @param pKey Pointer to the key. + * @param pIv Pointer to the iv. + * @param IsEncryption If set to NV_TRUE indicates key schedule computation + * is for encryption else for decryption. + * @param pAesHwCtxt Pointer to the AES H/W context. + * + * @retval None. + */ +void +Ap20AesHwSetKeyAndIv( + const AesHwEngine Engine, + const AesHwKeySlot Slot, + const AesHwKey *const pKey, + const AesHwIv *const pIv, + const NvBool IsEncryption, + AesHwContext *const pAesHwCtxt) +{ + NV_ASSERT(pAesHwCtxt); + NV_ASSERT(pKey); + NV_ASSERT(pIv); + + NvOsMutexLock(pAesHwCtxt->Mutex[Engine]); + + // Wait till engine becomes IDLE + NvAesCoreAp20WaitTillEngineIdle(Engine, pAesHwCtxt->pVirAdr[Engine]); + + NvAesCoreAp20ControlKeyScheduleGeneration(Engine, pAesHwCtxt->pVirAdr[Engine], NV_TRUE); + + Ap20AesHwSelectKeyIvSlot(Engine, Slot, pAesHwCtxt); + // Clear key table first before expanding the Key + NvOsMemset(pAesHwCtxt->pKeyTableVirAddr[Engine], 0, AES_HW_KEY_TABLE_LENGTH_BYTES); + NvOsMemcpy(&pAesHwCtxt->pKeyTableVirAddr[Engine][0], &pKey->key[0], sizeof(AesHwKey)); + + NvOsMemcpy( + &pAesHwCtxt->pKeyTableVirAddr[Engine][NvDdkAesConst_MaxKeyLengthBytes + NvDdkAesConst_IVLengthBytes], + &pIv->iv[0], + sizeof(AesHwIv)); + + Ap20AesSetupTable(Engine, Slot, pAesHwCtxt); + + NvOsMutexUnlock(pAesHwCtxt->Mutex[Engine]); +} + +/** + * Load an initial vector into the specified AES engine for using it + * during encryption or decryption. + * + * @param Engine AES engine. + * @param Slot Key slot for which Iv needs to be set. + * @param pIv Pointer to the initial vector. + * @param pAesHwCtxt Pointer to the AES H/W context. + * + * @retval NvSuccess if Iv was set correctly. + * NvError_InvalidState if operation is not allowed. + */ +NvError +Ap20AesHwSetIv( + const AesHwEngine Engine, + const AesHwKeySlot Slot, + const AesHwIv *const pIv, + AesHwContext *const pAesHwCtxt) +{ + NvError e; + + NV_ASSERT(pAesHwCtxt); + NV_ASSERT(pIv); + + e = Ap20AesHwStartEngine( + Engine, + NvDdkAesConst_IVLengthBytes, + (NvU8 *)(&pIv->iv[0]), + NV_FALSE, + NvDdkAesOperationalMode_Cbc, + pAesHwCtxt->pKeyTableVirAddr[Engine], + pAesHwCtxt); + + NV_ASSERT(pAesHwCtxt->pKeyTableVirAddr[Engine]); + + NvOsMemset((void *)pAesHwCtxt->pKeyTableVirAddr[Engine], 0, AES_HW_KEY_TABLE_LENGTH); + + return e; +} + +/** + * Retrieve the initial vector for the specified AES engine. + * + * @param pAesHwCtxt Pointer to the AES H/W context. + * @param Engine AES engine. + * @param Slot Key slot for which Iv is to be retrieved. + * @param pIv Pointer to the initial vector. + * + * @retval None. + */ +void +Ap20AesHwGetIv( + const AesHwContext *const pAesHwCtxt, + const AesHwEngine Engine, + const AesHwKeySlot Slot, + AesHwIv *const pIv) +{ + NV_ASSERT(pAesHwCtxt); + NV_ASSERT(pIv); + + NvOsMutexLock(pAesHwCtxt->Mutex[Engine]); + + NvOsMemcpy(&pIv->iv[0], &pAesHwCtxt->IvContext[Engine].CurIv[Slot], NvDdkAesConst_BlockLengthBytes); + + NvOsMutexUnlock(pAesHwCtxt->Mutex[Engine]); +} + +/** + * Lock the Secure Session Key (SSK) slots. + * This API disables the read/write permissions to the secure key slots. + * + * @param pAesHwCtxt Pointer to the AES H/W context. + * @param SskEngine SSK engine number. + * + * @retval None. + */ +void +Ap20AesHwLockSskReadWrites( + const AesHwContext *const pAesHwCtxt, + const AesHwEngine SskEngine) +{ + NV_ASSERT(pAesHwCtxt); + + NvOsMutexLock(pAesHwCtxt->Mutex[SskEngine]); + + NvAesCoreAp20LockSskReadWrites(SskEngine, pAesHwCtxt->pVirAdr[SskEngine]); + + NvOsMutexUnlock(pAesHwCtxt->Mutex[SskEngine]); +} + +/** + * Encrypt/Decrypt a specified number of blocks of cyphertext using + * Cipher Block Chaining (CBC) mode. A block is 16 bytes. + * This is non-blocking API and need to call AesHwEngineIdle() + * to check the engine status to confirm the AES engine operation is + * done and comes out of the BUSY state. + * Also make sure before calling this API engine must be IDLE. + * + * @param Engine AES engine. + * @param DataSize Number of blocks of ciphertext to process. + * One block is 16 bytes. Max number of blocks possible = 0xFFFFF. + * @param pSrc Pointer to nblock blocks of ciphertext/plaintext depending on the + * IsEncryption status; ciphertext/plaintext is not modified (input). + * @param IsEncryption If set to NV_TRUE indicates AES engine to start + * encryption on the source data to give cipher text else starts + * decryption on the source cipher data to give plain text. + * @param OpMode Specifies the AES operational mode. + * @param pDest Pointer to nblock blocks of cleartext/ciphertext (output) + * depending on the IsEncryption. + * @param pAesHwCtxt Pointer to the AES H/W context. + * + * @retval NvSuccess if AES operation is successful. + * @retval NvError_InvalidState if operation mode is not supported. + */ +NvError +Ap20AesHwStartEngine( + const AesHwEngine Engine, + const NvU32 DataSize, + const NvU8 *const pSrc, + const NvBool IsEncryption, + const NvDdkAesOperationalMode OpMode, + NvU8 *const pDest, + AesHwContext *const pAesHwCtxt) +{ + NvRmMemHandle hSrcMemBuf = NULL; + NvRmMemHandle hDestMemBuf = NULL; + NvRmPhysAddr SrcBufferPhyAddr = 0; + NvRmPhysAddr DestBufferPhyAddr = 0; + NvU32 *pSrcBufferVirtAddr = NULL; + NvU32 *pDestBufferVirtAddr = NULL; + NvError e; + + NV_ASSERT(pAesHwCtxt); + NV_ASSERT(pSrc); + NV_ASSERT(pDest); + + switch (OpMode) + { + case NvDdkAesOperationalMode_AnsiX931: + { + // If Iv is not readable, don't allow operations to be performed. + // Since setting the Iv also uses this API, it should be enough to + // disallow operations here. + if (pAesHwCtxt->IsX931OpsDisallowed) + return NvError_InvalidState; + } + case NvDdkAesOperationalMode_Cbc: + case NvDdkAesOperationalMode_Ecb: + break; + default: + return NvError_InvalidState; + } + + NV_CHECK_ERROR_CLEANUP(NvRmMemHandleCreate(pAesHwCtxt->hRmDevice, &hSrcMemBuf, DataSize)); + if (!hSrcMemBuf) + { + goto fail; + } + + e = NvRmMemHandleCreate(pAesHwCtxt->hRmDevice, &hDestMemBuf, DataSize); + if (!hDestMemBuf || (e != NvSuccess)) + { + goto fail1; + } + + e = NvRmMemAlloc(hSrcMemBuf,0, 0, 4, NvOsMemAttribute_Uncached); + if (e != NvSuccess) + { + goto fail2; + } + + e = NvRmMemAlloc(hDestMemBuf,0, 0, 4, NvOsMemAttribute_Uncached); + if (e != NvSuccess) + { + goto fail2; + } + + SrcBufferPhyAddr = NvRmMemPin(hSrcMemBuf); + DestBufferPhyAddr = NvRmMemPin(hDestMemBuf); + + e = NvRmPhysicalMemMap( + SrcBufferPhyAddr, + DataSize, + NVOS_MEM_READ_WRITE, + NvOsMemAttribute_Uncached, + (void **)&pSrcBufferVirtAddr); + if (e != NvSuccess) + { + goto fail3; + } + + e = NvRmPhysicalMemMap( + DestBufferPhyAddr, + DataSize, + NVOS_MEM_READ_WRITE, + NvOsMemAttribute_Uncached, + (void **)&pDestBufferVirtAddr); + if (e != NvSuccess) + { + goto fail4; + } + + NvOsMutexLock(pAesHwCtxt->Mutex[Engine]); + + NvOsMemcpy((NvU8 *)pSrcBufferVirtAddr, pSrc, DataSize); + + if (DataSize && (!IsEncryption)) + { + NvOsMemcpy(&pAesHwCtxt->IvContext[Engine].CurIv[pAesHwCtxt->IvContext[Engine].CurKeySlot], + (pSrc + DataSize - NvDdkAesConst_BlockLengthBytes), + NvDdkAesConst_BlockLengthBytes); + } + + NvAesCoreAp20ProcessBuffer( + Engine, + pAesHwCtxt->pVirAdr[Engine], + SrcBufferPhyAddr, + DestBufferPhyAddr, + DataSize, + pAesHwCtxt->DmaPhyAddr[Engine], + IsEncryption, + OpMode); + + NvOsMemcpy(pDest, (NvU8 *)pDestBufferVirtAddr, DataSize); + + /** + * If DataSize is zero, Iv would remain unchanged. + * For an encryption operation, the current Iv will be the last block of + * ciphertext. + */ + if (DataSize && IsEncryption) + { + NvOsMemcpy(&pAesHwCtxt->IvContext[Engine].CurIv[pAesHwCtxt->IvContext[Engine].CurKeySlot], + (pDest + DataSize - NvDdkAesConst_BlockLengthBytes), + NvDdkAesConst_BlockLengthBytes); + } + + NvOsMutexUnlock(pAesHwCtxt->Mutex[Engine]); + + NvOsMemset(pSrcBufferVirtAddr, 0, DataSize); + NvOsMemset(pDestBufferVirtAddr, 0, DataSize); + + // Unpinning the Memory + NvRmPhysicalMemUnmap(pDestBufferVirtAddr, DataSize); + +fail4: + NvRmPhysicalMemUnmap(pSrcBufferVirtAddr, DataSize); + +fail3: + // Unpinning the Memory + NvRmMemUnpin(hSrcMemBuf); + + // Unpinning the Memory + NvRmMemUnpin(hDestMemBuf); + +fail2: + NvRmMemHandleFree(hDestMemBuf); +fail1: + NvRmMemHandleFree(hSrcMemBuf); +fail: + return e; +} + +/** + * Load the SSK key into secure scratch resgister and disables the write permissions. + * Note: If Key is not specified then this API locks the Secure Scratch registers. + * + * @param PmicBaseAddr PMIC base address. + * @param pKey Pointer to the key. If pKey=NULL then key will not be set to the + * secure scratch registers, but locks the Secure scratch register. + * @param Size Length of the aperture in bytes. + * + * @retval None. + */ +void +Ap20AesHwLoadSskToSecureScratchAndLock( + const NvRmPhysAddr PmicBaseAddr, + const AesHwKey *const pKey, + const size_t Size) +{ + NV_ASSERT(pKey); + NvAesCoreAp20LoadSskToSecureScratchAndLock(PmicBaseAddr, (pKey ? pKey->key : 0), Size); +} + +/** + * Mark all dedicated slots as used. + * + * @param pAesCoreEngine Pointer to AES Core Engine. + * + * @retval None. + */ +void Ap20AesHwGetUsedSlots(AesCoreEngine *const pAesCoreEngine) +{ + NV_ASSERT(pAesCoreEngine); + + // For ap20, SBK and SSK reside on both engines + pAesCoreEngine->SbkEngine[0] = AES_SBK_ENGINE_A; + pAesCoreEngine->SbkEncryptSlot = AES_SBK_ENCRYPT_SLOT; + pAesCoreEngine->SbkDecryptSlot = AES_SBK_DECRYPT_SLOT; + pAesCoreEngine->IsKeySlotUsed[AES_SBK_ENGINE_A][AES_SBK_ENCRYPT_SLOT] = NV_TRUE; + + pAesCoreEngine->SbkEngine[1] = AES_SBK_ENGINE_B; + pAesCoreEngine->IsKeySlotUsed[AES_SBK_ENGINE_B][AES_SBK_DECRYPT_SLOT] = NV_TRUE; + + pAesCoreEngine->SskEngine[0] = AES_SSK_ENGINE_A; + pAesCoreEngine->SskEncryptSlot = AES_SSK_ENCRYPT_SLOT; + pAesCoreEngine->SskDecryptSlot = AES_SSK_DECRYPT_SLOT; + pAesCoreEngine->IsKeySlotUsed[AES_SSK_ENGINE_A][AES_SSK_ENCRYPT_SLOT] = NV_TRUE; + + pAesCoreEngine->SskEngine[1] = AES_SSK_ENGINE_B; + pAesCoreEngine->IsKeySlotUsed[AES_SSK_ENGINE_B][AES_SSK_DECRYPT_SLOT] = NV_TRUE; +} + +/** + * Read the AES engine disable status. + * + * @param pAesHwCtxt Pointer to the AES H/W context. + * @param Engine AES engine to disable. + * + * @return NV_TRUE if engine is disabled else NV_FALSE. + * + */ +NvBool Ap20AesHwIsEngineDisabled(const AesHwContext *const pAesHwCtxt, const AesHwEngine Engine) +{ + NvBool IsEngineDisabled = NV_FALSE; + + NV_ASSERT(pAesHwCtxt); + + NvOsMutexLock(pAesHwCtxt->Mutex[Engine]); + + IsEngineDisabled = NvAesCoreAp20IsEngineDisabled(Engine, pAesHwCtxt->pVirAdr[Engine]); + + NvOsMutexUnlock(pAesHwCtxt->Mutex[Engine]); + + return IsEngineDisabled; +} + +/** + * Get the read permissions for IV for each key slot of an engine. + * + * @param Engine AES Engine for which Iv permissions for an engine are sought. + * @param pAesHwCtxt Pointer to the AES H/W context. + * + * @retval None. + * + */ +void Ap20AesHwGetIvReadPermissions(const AesHwEngine Engine, AesHwContext *const pAesHwCtxt) +{ + NV_ASSERT(pAesHwCtxt); + + NvOsMutexLock(pAesHwCtxt->Mutex[Engine]); + + NvAesCoreAp20GetIvReadPermissions( + Engine, + pAesHwCtxt->pVirAdr[Engine], + &pAesHwCtxt->IvContext[Engine].IsIvReadable[0]); + + NvOsMutexUnlock(pAesHwCtxt->Mutex[Engine]); +} + +void NvAesIntfAp20GetHwInterface(AesHwInterface *const pAp20AesHw) +{ + NV_ASSERT(pAp20AesHw); + + pAp20AesHw->AesHwDisableEngine = Ap20AesHwDisableEngine; + pAp20AesHw->AesHwClearKeyAndIv = Ap20AesHwClearKeyAndIv; + pAp20AesHw->AesHwClearIv = Ap20AesHwClearIv; + pAp20AesHw->AesHwSetKeyAndIv = Ap20AesHwSetKeyAndIv; + pAp20AesHw->AesHwSetIv = Ap20AesHwSetIv; + pAp20AesHw->AesHwGetIv = Ap20AesHwGetIv; + pAp20AesHw->AesHwLockSskReadWrites = Ap20AesHwLockSskReadWrites; + pAp20AesHw->AesHwSelectKeyIvSlot = Ap20AesHwSelectKeyIvSlot; + pAp20AesHw->AesHwStartEngine = Ap20AesHwStartEngine; + pAp20AesHw->AesHwLoadSskToSecureScratchAndLock = Ap20AesHwLoadSskToSecureScratchAndLock; + pAp20AesHw->AesHwGetUsedSlots = Ap20AesHwGetUsedSlots; + pAp20AesHw->AesHwIsEngineDisabled = Ap20AesHwIsEngineDisabled; + pAp20AesHw->AesHwGetIvReadPermissions = Ap20AesHwGetIvReadPermissions; +} diff --git a/arch/arm/mach-tegra/nvddk/nvddk_aes_priv.h b/arch/arm/mach-tegra/nvddk/nvddk_aes_priv.h new file mode 100644 index 000000000000..bebbebe1900d --- /dev/null +++ b/arch/arm/mach-tegra/nvddk/nvddk_aes_priv.h @@ -0,0 +1,436 @@ +/* + * Copyright (c) 2007-2009 NVIDIA Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of the NVIDIA Corporation nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef INCLUDED_NVDDK_AES_PRIV_H +#define INCLUDED_NVDDK_AES_PRIV_H + +#include "nverror.h" +#include "nvcommon.h" +#include "nvrm_memmgr.h" +#include "nvddk_aes_hw.h" + +#if defined(__cplusplus) +extern "C" { +#endif + +// As of now only 5 commands are used for AES encryption/decryption +#define AES_HW_MAX_ICQ_LENGTH 5 + +// AES RFC 3394 initial vector length, in bytes +#define AES_RFC_IV_LENGTH_BYTES 8 + +/** + * AES Engine instances. + */ +typedef enum +{ + // AES Engine "A" BSEV + AesHwEngine_A, + // AES Engine "B" BSEA + AesHwEngine_B, + AesHwEngine_Num, + AesHwEngine_Force32 = 0x7FFFFFFF +} AesHwEngine; + +/** + * AES Key Slot instances (per AES engine). + */ +typedef enum +{ + AesHwKeySlot_0, + AesHwKeySlot_1, + AesHwKeySlot_2, + AesHwKeySlot_3, + AesHwKeySlot_Num, + AesHwKeySlot_4 = AesHwKeySlot_Num, + AesHwKeySlot_5, + AesHwKeySlot_6, + AesHwKeySlot_7, + AesHwKeySlot_NumExt, + AesHwKeySlot_Force32 = 0x7FFFFFFF +} AesHwKeySlot; + +// Iv Context +typedef struct AesIvContextRec +{ + // Updated/current Iv for each key slot + NvU32 CurIv[AesHwKeySlot_NumExt][AES_HW_IV_LENGTH]; + // Iv read permissions for each key slot + NvBool IsIvReadable[AesHwKeySlot_NumExt]; + // The current key slot in use + AesHwKeySlot CurKeySlot; +} AesIvContext; + +typedef struct AesHwInterfaceRec AesHwInterface; + +// AES engine capabilities +typedef struct AesHwCapabilitiesRec +{ + // Number of slots supported in each AES instance + AesHwKeySlot NumSlotsSupported; + // Key schedule generation in hardware to be supported + NvBool IsHwKeySchedGenSupported; + // Size needed for key scheduling + NvU32 HwKeySchedLengthBytes; + // Hashing to be supported within the engine + NvBool IsHashSupported; + // Minimum Alignment for the key table/schedule buffer in IRAM or VRAM + NvU32 MinKeyTableAlignment; + // Min Input/Output buffer alignment for AES + NvU32 MinBufferAlignment; + // Pointer to the AES engine low level interface + AesHwInterface *pAesInterf; +} AesHwCapabilities; + +// H/W Context +typedef struct AesHwContextRec +{ + // Capabilities + AesHwCapabilities **ppEngineCaps; + // Mutex to support concurrent operation on the AES engine + NvOsMutexHandle Mutex[AesHwEngine_Num]; + // RM device handle + NvRmDeviceHandle hRmDevice; + // Controller registers physical base address + NvRmPhysAddr PhysAdr[AesHwEngine_Num]; + // Holds the virtual address for accessing registers + NvU32 *pVirAdr[AesHwEngine_Num]; + // Holds the register map size + NvU32 BankSize[AesHwEngine_Num]; + // Memory handle to the key table + NvRmMemHandle hKeyTableMemBuf; + // Pointer to the key table virtual buffer + NvU8 *pKeyTableVirAddr[AesHwEngine_Num]; + // Key table physical addr + NvRmPhysAddr KeyTablePhyAddr[AesHwEngine_Num]; + // Key table size in bytes + NvU32 KeyTableSize[AesHwEngine_Num]; + // Memory handle to the AES H/W Buffer + NvRmMemHandle hDmaMemBuf; + // Contains the physical Address of the H/W buffer + NvRmPhysAddr DmaPhyAddr[AesHwEngine_Num]; + // Virtual pointer to the AES buffer + NvU8 *pDmaVirAddr[AesHwEngine_Num]; + // Icq commands length + NvU32 CommandQueueLength[AesHwEngine_Num]; + // Holds the Icq commands for the AES operation + NvU32 CommandQueueData[AesHwEngine_Num][AES_HW_MAX_ICQ_LENGTH]; + // Iv Context for each AES engine + AesIvContext IvContext[AesHwEngine_Num]; + // Indicates whether X9.31 operations are allowed or not + NvBool IsX931OpsDisallowed; +} AesHwContext; + +// AES Core Engine record +typedef struct AesCoreEngineRec +{ + // Keeps the count of open handles + NvU32 OpenCount; + // Id returned from driver's registration with Power Manager + NvU32 RmPwrClientId[AesHwEngine_Num]; + // Indicates whether key slot is used or not + NvBool IsKeySlotUsed[AesHwEngine_Num][AesHwKeySlot_NumExt]; + // SSK engine where SSK is stored + AesHwEngine SskEngine[AesHwEngine_Num]; + // SSK encrypt key slot + AesHwKeySlot SskEncryptSlot; + // SSK Decrypt key slot + AesHwKeySlot SskDecryptSlot; + // SBK engine where SBK is stored + AesHwEngine SbkEngine[AesHwEngine_Num]; + // SBK encrypt key slot + AesHwKeySlot SbkEncryptSlot; + // SSK Decrypt key slot + AesHwKeySlot SbkDecryptSlot; + // Aes H/W Engine context + AesHwContext AesHwCtxt; + // Indicates whether engine is disabled or not + NvBool IsEngineDisabled; +} AesCoreEngine; + +// Set of function pointers to be used to access the hardware interface for +// the AES engines. +struct AesHwInterfaceRec +{ + /** + * Disable the selected AES engine. No further operations can be + * performed using the AES engine until the entire chip is reset. + * + * @param pAesHwCtxt Pointer to the AES H/W context. + * @param Engine AES engine to disable. + * + * @retval NvSuccess if engine successfully disabled else NvError_AesDisableCryptoFailed. + */ + NvError (*AesHwDisableEngine)( + const AesHwContext *const pAesHwCtxt, + const AesHwEngine Engine); + + /** + * Over-write the key schedule and Initial Vector in the in the specified + * key slot with zeroes.Convenient for preventing subsequent callers from + * gaining access to a previously-used key. + * + * @param Engine AES engine. + * @param Slot key slot to clear. + * @param pAesHwCtxt Pointer to the AES H/W context. + * + * @retval None. + */ + void (*AesHwClearKeyAndIv)( + const AesHwEngine Engine, + const AesHwKeySlot Slot, + AesHwContext *const pAesHwCtxt); + + /** + * Over-write the initial vector in the specified AES engine with zeroes. + * Convenient to prevent subsequent callers from gaining access to a + * previously-used initial vector. + * + * @param Engine AES engine. + * @param Slot Key slot for which Iv needs to be cleared. + * @param pAesHwCtxt Pointer to the AES H/W context. + * + * @retval None. + */ + void (*AesHwClearIv)( + const AesHwEngine Engine, + const AesHwKeySlot Slot, + AesHwContext *const pAesHwCtxt); + + /** + * Compute key schedule for the given key, then load key schedule and + * initial vector into the specified key slot. + * + * @param Engine AES engine. + * @param Slot Key slot to load. + * @param pKey Pointer to the key. + * @param pIv Pointer to the iv. + * @param IsEncryption If set to NV_TRUE indicates key schedule computation + * is for encryption else for decryption. + * @param pAesHwCtxt Pointer to the AES H/W context. + * + * @retval None. + */ + void (*AesHwSetKeyAndIv)( + const AesHwEngine Engine, + const AesHwKeySlot Slot, + const AesHwKey *const pKey, + const AesHwIv *const pIv, + const NvBool IsEncryption, + AesHwContext *const pAesHwCtxt); + + /** + * Load an initial vector into the specified AES engine for using it + * during encryption or decryption. + * + * @param Engine AES engine. + * @param Slot Key slot for which Iv needs to be set. + * @param pIv Pointer to the initial vector. + * @param pAesHwCtxt Pointer to the AES H/W context. + * + * @retval NvSuccess if Iv was set correctly. + * NvError_InvalidState if operation is not allowed. + */ + NvError (*AesHwSetIv)( + const AesHwEngine Engine, + const AesHwKeySlot Slot, + const AesHwIv *const pIv, + AesHwContext *const pAesHwCtxt); + + /** + * Retrieve the initial vector for the specified AES engine. + * + * @param pAesHwCtxt Pointer to the AES H/W context. + * @param Engine AES engine. + * @param Slot Key slot for which Iv is to be retrieved. + * @param pIv Pointer to the initial vector. + * + * @retval None. + */ + void (*AesHwGetIv)( + const AesHwContext *const pAesHwCtxt, + const AesHwEngine Engine, + const AesHwKeySlot Slot, + AesHwIv *const pIv); + + /** + * Lock the Secure Session Key (SSK) slots. + * This API disables the read/write permissions to the secure key slots. + * + * @param pAesHwCtxt Pointer to the AES H/W context. + * @param SskEngine SSK engine number. + * + * @retval None. + */ + void (*AesHwLockSskReadWrites)( + const AesHwContext *const pAesHwCtxt, + const AesHwEngine SskEngine); + + /** + * Select the key and iv from the internal key table for a specified key slot. + * + * @param Engine AES engine. + * @param Slot Key slot for which key and IV needs to be selected. + * @param pAesHwCtxt Pointer to the AES H/W context. + * + * @retval None. + */ + void (*AesHwSelectKeyIvSlot)( + const AesHwEngine Engine, + const AesHwKeySlot Slot, + AesHwContext *const pAesHwCtxt); + + /** + * Encrypt/Decrypt a specified number of blocks of cyphertext using + * Cipher Block Chaining (CBC) mode. A block is 16 bytes. + * This is non-blocking API and need to call AesHwEngineIdle() + * to check the engine status to confirm the AES engine operation is + * done and comes out of the BUSY state. + * Also make sure before calling this API engine must be IDLE. + * + * @param Engine AES engine. + * @param DataSize Number of blocks of ciphertext to process. + * One block is 16 bytes. Max number of blocks possible = 0xFFFFF. + * @param pSrc Pointer to nblock blocks of ciphertext/plaintext depending on the + * IsEncryption status; ciphertext/plaintext is not modified (input). + * @param IsEncryption If set to NV_TRUE indicates AES engine to start + * encryption on the source data to give cipher text else starts + * decryption on the source cipher data to give plain text. + * @param OpMode Specifies the AES operational mode. + * @param pDest Pointer to nblock blocks of cleartext/ciphertext (output) + * depending on the IsEncryption. + * @param pAesHwCtxt Pointer to the AES H/W context. + * + * @retval NvSuccess if AES operation is successful. + * @retval NvError_InvalidState if operation mode is not supported. + */ + NvError (*AesHwStartEngine)( + const AesHwEngine Engine, + const NvU32 DataSize, + const NvU8 *const pSrc, + const NvBool IsEncryption, + const NvDdkAesOperationalMode OpMode, + NvU8 *const pDest, + AesHwContext *const pAesHwCtxt); + + /** + * Load the SSK key into secure scratch resgister and disable the write permissions. + * Note: If Key is not specified then this API locks the Secure Scratch registers. + * + * @param PmicBaseAddr PMIC base address. + * @param pKey Pointer to the key. If pKey=NULL then key will not be set to the + * secure scratch registers, but locks the Secure scratch register. + * @param Size Length of the aperture in bytes. + * + * @retval None. + */ + void (*AesHwLoadSskToSecureScratchAndLock)( + const NvRmPhysAddr PmicBaseAddr, + const AesHwKey *const pKey, + const size_t Size); + + /** + * Mark all dedicated slots as used. + * + * @param pAesCoreEngine Pointer to AES Core Engine. + * + * @retval None. + */ + void (*AesHwGetUsedSlots)(AesCoreEngine *const pAesCoreEngine); + + /** + * Read the AES engine disable status. + * + * @param pAesHwCtxt Pointer to the AES H/W context. + * @param Engine AES engine to disable. + * + * @return NV_TRUE if engine is disabled else NV_FALSE. + */ + NvBool (*AesHwIsEngineDisabled)(const AesHwContext *const pAesHwCtxt, const AesHwEngine Engine); + + /** + * Get the read permissions for IV for each key slot of an engine. + * + * @param Engine AES Engine for which Iv permissions for an engine are sought. + * @param pAesHwCtxt Pointer to the AES H/W context. + * + * @retval None. + */ + void (*AesHwGetIvReadPermissions)(const AesHwEngine Engine, AesHwContext *const pAesHwCtxt); +}; + +// AES client state: this structure is common to all clients +typedef struct NvDdkAesRec +{ + // Algorithm type set for this client + NvDdkAesOperationalMode OpMode; + // Select key type -- SBK, SSK or user-specified + NvDdkAesKeyType KeyType; + // AES key length; must be 128Bit for SBK or SSK + NvDdkAesKeySize KeySize; + // Specified AES key value if KeyType is user-specified; else ignored + NvU8 Key[NvDdkAesConst_MaxKeyLengthBytes]; + // Initial vector to use when encrypting/decrypting last IV will be stored + NvU8 Iv[NvDdkAesConst_IVLengthBytes]; + // Initial vector to use in RFC3394 key unwrapping + NvU8 WrappedIv[AES_RFC_IV_LENGTH_BYTES]; + // Client selected AES engine, depends on the key slot selected + AesHwEngine Engine; + // Client selected Key slot + AesHwKeySlot KeySlot; + // Operation type selected + NvBool IsEncryption; + // If user key is specified client can tell to use the dedicated slot + // If set to NV_TRUE then key slot is dedicated else shared with other keys + NvBool IsDedicatedSlot; + // Pointer to the AES core engine + AesCoreEngine *pAesCoreEngine; + // Client's user id + uid_t uid; + // Client's group id + gid_t gid; +} NvDdkAes; + +/** + * Return the interface to be used for AP20 AES engine. + * + * @param pAp20AesHw Pointer to the interface. + * + * @retval None. + */ +void NvAesIntfAp20GetHwInterface(AesHwInterface *const pAp20AesHw); + +#if defined(__cplusplus) +} +#endif + +#endif // INCLUDED_NVDDK_AES_PRIV_H |