/* Copyright Statement: * * This software/firmware and related documentation ("MediaTek Software") are * protected under relevant copyright laws. The information contained herein * is confidential and proprietary to MediaTek Inc. and/or its licensors. * Without the prior written permission of MediaTek inc. and/or its licensors, * any reproduction, modification, use or disclosure of MediaTek Software, * and information contained herein, in whole or in part, shall be strictly prohibited. * * MediaTek Inc. (C) 2011. All rights reserved. * * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE") * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE, * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE, * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. * * The following software/firmware and/or related documentation ("MediaTek Software") * have been modified by MediaTek Inc. All revisions are subject to any receiver's * applicable license agreements with MediaTek Inc. */ /*#include #include */ #include "sec_error.h" #include "hacc_mach.h" /****************************************************************************** * this file contains the hardware secure engine low-level operations * note that : all the functions in this file are ONLY for HACC internal usages. ******************************************************************************/ /****************************************************************************** * CONSTANT DEFINITIONS ******************************************************************************/ #define MOD "HACC" #define HACC_TEST (0) /****************************************************************************** * DEBUG ******************************************************************************/ #define SEC_DEBUG (0) #define SMSG printk #if SEC_DEBUG #define DMSG printk #else #define DMSG #endif /****************************************************************************** * LOCAL VERIABLE ******************************************************************************/ static struct hacc_context hacc_ctx; /****************************************************************************** * LOCAL FUNCTIONS ******************************************************************************/ #if HACC_TEST static void hacc_test(void) { unsigned int i, test_sz = HACC_AES_MAX_KEY_SZ * 24; unsigned int test_keysz = AES_KEY_256; unsigned char *test_src = (unsigned char *)HACC_AES_TEST_SRC; unsigned char *test_dst = (unsigned char *)HACC_AES_TEST_DST; unsigned char *test_tmp = (unsigned char *)HACC_AES_TEST_TMP; /* prepare data */ for (i = 0; i < test_sz; i++) test_src[i] = i + 1; hacc_set_key(AES_HW_WRAP_KEY, test_keysz); hacc_do_aes(AES_ENC, test_src, test_tmp, test_sz); hacc_set_key(AES_HW_WRAP_KEY, test_keysz); hacc_do_aes(AES_DEC, test_tmp, test_dst, test_sz); for (i = 0; i < test_sz; i++) { if (test_src[i] != test_dst[i]) { DMSG("[%s] test_src[%d] = 0x%x != test_dst[%d] = 0x%x\n", MOD, i, test_src[i], i, test_dst[i]); DMSG(0); } } DMSG("[%s] encrypt & descrypt unit test pass. (Key = %dbits)\n", MOD, test_keysz << 3); } #else #define hacc_test() do {} while (0) #endif /****************************************************************************** * GLOBAL FUNCTIONS ******************************************************************************/ static unsigned int hacc_set_cfg(AES_CFG *cfg) { memcpy(&hacc_ctx.cfg, cfg, sizeof(AES_CFG)); return SEC_OK; } static unsigned int hacc_set_mode(AES_MODE mode) { AES_CFG cfg; DRV_ClrReg32(HACC_ACON, HACC_AES_MODE_MASK); switch (mode) { case AES_ECB_MODE: /* no need cfg */ memset(&cfg.config[0], 0, sizeof(cfg.config)); DRV_SetReg32(HACC_ACON, HACC_AES_ECB); break; case AES_CBC_MODE: DRV_SetReg32(HACC_ACON, HACC_AES_CBC); break; default: return ERR_HACC_MODE_INVALID; } return SEC_OK; } unsigned int hacc_set_key(AES_KEY_ID id, AES_KEY key) { unsigned int i, acon = 0; unsigned int akey; unsigned char *tkey; switch (key) { case AES_KEY_128: acon |= HACC_AES_128; break; case AES_KEY_192: acon |= HACC_AES_192; break; case AES_KEY_256: acon |= HACC_AES_256; break; default: return ERR_HACC_KEY_INVALID; } /* set aes block size */ hacc_ctx.blk_sz = key; /* set aes key length */ DRV_ClrReg32(HACC_ACON, HACC_AES_TYPE_MASK); DRV_SetReg32(HACC_ACON, acon); /* clear key */ for (i = 0; i < HACC_AES_MAX_KEY_SZ; i += 4) DRV_WriteReg32(HACC_AKEY0 + i, 0); /* set aes key */ switch (id) { case AES_HW_KEY: DRV_SetReg32(HACC_ACONK, HACC_AES_BK2C); return 0; case AES_HW_WRAP_KEY: tkey = &hacc_ctx.hw_key[0]; break; case AES_SW_KEY: default: tkey = &hacc_ctx.sw_key[0]; break; } /* non hardware binding key */ DRV_ClrReg32(HACC_ACONK, HACC_AES_BK2C); /* update key. note that don't use key directly */ for (i = 0; i < HACC_AES_MAX_KEY_SZ; i += 4) { akey = (tkey[i] << 24) | (tkey[i + 1] << 16) | (tkey[i + 2] << 8) | (tkey[i + 3]); DRV_WriteReg32(HACC_AKEY0 + i, akey); } return SEC_OK; } unsigned int hacc_do_aes(AES_OPS ops, unsigned char *src, unsigned char *dst, unsigned int size) { unsigned int i; unsigned int *ds, *dt, *vt; /* make sure size is aligned to aes block size */ if ((size % AES_BLK_SZ) != 0) { SMSG("[%s] size = %d is not %d bytes alignment\n", MOD, size, AES_BLK_SZ); return ERR_HACC_DATA_UNALIGNED; } vt = (unsigned int *)&hacc_ctx.cfg.config[0]; /* erase src, cfg, out register */ DRV_SetReg32(HACC_ACON2, HACC_AES_CLR); /* set init config */ for (i = 0; i < AES_CFG_SZ; i += 4) DRV_WriteReg32(HACC_ACFG0 + i, *vt++); if (ops == AES_ENC) DRV_SetReg32(HACC_ACON, HACC_AES_ENC); else DRV_ClrReg32(HACC_ACON, HACC_AES_ENC); ds = (unsigned int *)src; dt = (unsigned int *)dst; do { /* fill in the data */ for (i = 0; i < AES_BLK_SZ; i += 4) DRV_WriteReg32(HACC_ASRC0 + i, *ds++); /* start aes engine */ DRV_SetReg32(HACC_ACON2, HACC_AES_START); /* wait for aes engine ready */ while ((DRV_Reg32(HACC_ACON2) & HACC_AES_RDY) == 0) ; /* read out the data */ for (i = 0; i < AES_BLK_SZ; i += 4) *dt++ = DRV_Reg32(HACC_AOUT0 + i); if (size == 0) goto _end; size -= AES_BLK_SZ; } while (size != 0); _end: return SEC_OK; } unsigned int hacc_deinit(void) { unsigned int ret = 0; /* clear aes module */ DRV_SetReg32(HACC_ACON2, HACC_AES_CLR); return ret; } unsigned int hacc_init(AES_KEY_SEED *keyseed) { unsigned int i = 0; unsigned int *config; unsigned int ret = 0; hacc_deinit(); /* DRV_WriteReg32(HACC_SECINIT0, HACC_SECINIT0_MAGIC); */ /* DRV_WriteReg32(HACC_SECINIT1, HACC_SECINIT1_MAGIC); */ /* DRV_WriteReg32(HACC_SECINIT2, HACC_SECINIT2_MAGIC); */ /* clear aes module */ DRV_SetReg32(HACC_ACON2, HACC_AES_CLR); /* set aes module in cbc mode with no byte order change */ DRV_ClrReg32(HACC_ACON2, HACC_AES_CHG_BO_MASK | HACC_AES_MODE_MASK); DRV_SetReg32(HACC_ACON2, HACC_AES_CHG_BO_OFF | HACC_AES_CBC); /* aes secure initialiation */ memset(&hacc_ctx, 0, sizeof(struct hacc_context)); for (i = 0; i < keyseed->size; i++) hacc_ctx.sw_key[i] = keyseed->seed[i]; config = (unsigned int *)&hacc_ctx.cfg.config[0]; *config++ = HACC_CFG_0; *config++ = HACC_CFG_1; *config++ = HACC_CFG_2; *config = HACC_CFG_3; ret = hacc_set_cfg(&hacc_ctx.cfg); if (SEC_OK != ret) goto _end; ret = hacc_set_mode(AES_CBC_MODE); if (SEC_OK != ret) goto _end; /* derive the hardware wrapper key */ ret = hacc_set_key(AES_HW_KEY, HACC_HW_KEY_SZ); if (SEC_OK != ret) goto _end; ret = hacc_do_aes(AES_ENC, &hacc_ctx.sw_key[0], &hacc_ctx.hw_key[0], AES_KEY_256); if (SEC_OK != ret) goto _end; ret = hacc_set_key(AES_HW_WRAP_KEY, AES_KEY_256); if (SEC_OK != ret) goto _end; hacc_test(); /* from now on, HACC HW wrap key can be used */ bHACC_HWWrapKeyInit = 1; /* from now on, HACC SW key can be used */ bHACC_SWKeyInit = 1; _end: return ret; }