/** nvt-opt key manager This file will Enable and disable SRAM shutdown @file nvt-otp.c @ingroup @note Copyright Novatek Microelectronics Corp. 2018. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. */ #include #include #ifndef CHKPNT #define CHKPNT printf("\033[37mCHK: %d, %s\033[0m\r\n", __LINE__, __func__) #endif #ifndef DBGD #define DBGD(x) printf("\033[0;35m%s=%d\033[0m\r\n", #x, x) #endif #ifndef DBGH #define DBGH(x) printf("\033[0;35m%s=0x%08X\033[0m\r\n", #x, x) #endif #ifndef DBG_DUMP #define DBG_DUMP(fmtstr, args...) printf(fmtstr, ##args) #endif #ifndef DBG_ERR #define DBG_ERR(fmtstr, args...) printf("\033[0;31mERR:%s() \033[0m" fmtstr, __func__, ##args) #endif #ifndef DBG_WRN #define DBG_WRN(fmtstr, args...) printf("\033[0;33mWRN:%s() \033[0m" fmtstr, __func__, ##args) #endif #if 0 #define DBG_IND(fmtstr, args...) printf("%s(): " fmtstr, __func__, ##args) #else #ifndef DBG_IND #define DBG_IND(fmtstr, args...) #endif #endif #define OUTREG32(x, y) (*((volatile UINT32*)(x)) = (y)) ///< Write 32bits IO register extern INT32 local_load(UINT32 uiRowAddress); extern INT32 local_store(UINT32 uiRowAddress); static INT32 key_program_bit(UINT32 rol, UINT32 col) { return local_store(rol | (col << 5)); } static INT32 key_write_data(UINT32 addr, UINT32 data) { UINT32 ui_bits; UINT32 ui_data; if (addr < 12 && addr != 8) { DBG_ERR("key_write_data addr = 0x%08x error(need >= 12 or == 8)\r\n", (int)addr); return EFUSE_PARAM_ERR; } ui_data = data; ui_bits = 0; while (ui_data) { ui_bits = __builtin_ctz(ui_data); ui_data &= ~(1 << ui_bits); if (key_program_bit(addr, ui_bits) != E_OK) { DBG_ERR("%s,eFuse program addr[%03lx] bit[%2d] fail\r\n", __func__, (UINT32)addr, (int)ui_bits); return EFUSE_OPS_ERR; } } return EFUSE_SUCCESS; } #define KEY_MANAGER_READ_PARAM() otp_key_manager(8) #define KEY_MANAGER_WRITE_PARAM(m) key_write_data(8, m) /* efuse_set_key_destination Destination of efuse get key field value @return IC revision of specific package revision - @b NT9666X_VER_A NT9666X version A - @b UNKNOWN_DIE_VER Unknown IC die version(system must halt) */ static ER set_key_destination(OTP_KEY_DESTINATION key_dst, SCE_KEY_SET_TO_OTP_FIELD key_field_set) { if (key_dst >= OTP_KEY_MANAGER_CNT) { DBG_ERR("key_dst out of range %d\r\n", key_dst); return EFUSE_PARAM_ERR; } if (key_dst == OTP_KEY_MANAGER_CRYPTO && key_field_set >= EFUSE_CRYPTO_ENGINE_KEY_CNT) { DBG_ERR("Dest[Crypto]=>key_field_set out of range %d > %d\r\n", key_field_set, EFUSE_CRYPTO_ENGINE_KEY_CNT); return EFUSE_PARAM_ERR; } if ((key_dst == OTP_KEY_MANAGER_RSA || key_dst == OTP_KEY_MANAGER_HASH) && key_field_set >= EFUSE_TOTAL_KEY_SET_FIELD) { DBG_ERR("Dest[RSA] or [HASH] =>key_field_set out of range %d > %d\r\n", key_field_set, EFUSE_CRYPTO_ENGINE_KEY_CNT); return EFUSE_PARAM_ERR; } OUTREG32(KEY_MANAGER_DESTINATION_ADDRESS, key_dst); OUTREG32(KEY_MANAGER_KEY_INDEX_ADDRESS, key_field_set); return E_OK; } /** otp_write_key Write specific key into specific key set (0~3) @Note: key set 0 is for secure boot use @param[in] key_set_index key set (0~3) @param[in] ucKey key (16bytes) @return Description of data returned. - @b E_OK: Success - @b E_SYS: Fail */ INT32 otp_write_key(EFUSE_OTP_KEY_SET_FIELD key_set_index, UINT8 *uc_key) { INT32 result = EFUSE_SUCCESS; UINT32 key_data; UINT32 u32_key = (UINT32)(uc_key); UINT32 data[4]; UINT32 key_field_start_index = 16; UINT32 index_cnt; UINT32 enable_secure_number = 32; switch (key_set_index) { //Note: >>>1st Key set is dedicate for secure boot usage<<< case EFUSE_OTP_1ST_KEY_SET_FIELD: key_field_start_index = 16; if (is_1st_key_programmed() == 1) { result = EFUSE_FREEZE_ERR; } else { enable_secure_number = SECUREBOOT_1ST_KEY_SET_PROGRAMMED; } break; case EFUSE_OTP_2ND_KEY_SET_FIELD: key_field_start_index = 20; if (is_2nd_key_programmed() == 1) { result = EFUSE_FREEZE_ERR; } else { enable_secure_number = SECUREBOOT_2ND_KEY_SET_PROGRAMMED; } break; case EFUSE_OTP_3RD_KEY_SET_FIELD: key_field_start_index = 24; if (is_3rd_key_programmed() == 1) { result = EFUSE_FREEZE_ERR; } else { enable_secure_number = SECUREBOOT_3RD_KEY_SET_PROGRAMMED; } break; case EFUSE_OTP_4TH_KEY_SET_FIELD: key_field_start_index = 28; if (is_4th_key_programmed() == 1) { result = EFUSE_FREEZE_ERR; } else { enable_secure_number = SECUREBOOT_4TH_KEY_SET_PROGRAMMED; } break; case EFUSE_OTP_5TH_KEY_SET_FIELD: key_field_start_index = 12; if (is_5th_key_programmed() == 1) { result = EFUSE_FREEZE_ERR; } else { enable_secure_number = SECUREBOOT_5TH_KEY_SET_PROGRAMMED; } break; default: DBG_ERR("Unknow key set[%d] => should be 0~4\r\n", (int)key_set_index + 1); result = EFUSE_OPS_ERR; break; } if (result != EFUSE_SUCCESS) { if (result == EFUSE_FREEZE_ERR) { DBG_ERR("key set[%d], key field not enpty\r\n", (int)key_set_index); } return result; } //Need porting data[0] = *(UINT32 *)(u32_key + 0); data[1] = *(UINT32 *)(u32_key + 4); data[2] = *(UINT32 *)(u32_key + 8); data[3] = *(UINT32 *)(u32_key + 12); for (index_cnt = 0; index_cnt < EFUSE_OTP_KEY_FIELD_CNT; index_cnt++) { result = key_write_data(key_field_start_index + index_cnt, data[index_cnt]); if (result < 0) { DBG_ERR("[%d]set key => write addr[%2d][0x%08lx] fail\r\n", (int)(((key_field_start_index - 16) / 4) + 1), (int)(key_field_start_index + index_cnt), (UINT32)data[index_cnt]); break; } else { key_data = otp_key_manager(key_field_start_index + index_cnt); if(key_data != data[index_cnt]) { DBG_ERR("[%d]set key => write addr[%2d][0x%08lx] fail\r\n", (int)(((key_field_start_index - 16) / 4) + 1), (int)(key_field_start_index + index_cnt), (UINT32)data[index_cnt]); result = EFUSE_CONTENT_ERR; break; } } } if(result == EFUSE_SUCCESS) { enable_secure_boot(enable_secure_number); } return result; } /** otp_set_key_destination Durung encrypt or decrypt, configure specific key set as AES key(0~3) to crypto engine @Note: key set 0 is for secure boot use @param[in] key_set_index key set (0~4) @return Description of data returned. - @b E_OK: Success */ INT32 otp_set_key_destination(EFUSE_OTP_KEY_SET_FIELD key_set_index) { UINT32 key_field_start_index = 16; switch (key_set_index) { //Note: >>>1st Key set is dedicate for secure boot usage<<< case EFUSE_OTP_1ST_KEY_SET_FIELD: key_field_start_index = 16; break; case EFUSE_OTP_2ND_KEY_SET_FIELD: key_field_start_index = 20; break; case EFUSE_OTP_3RD_KEY_SET_FIELD: key_field_start_index = 24; break; case EFUSE_OTP_4TH_KEY_SET_FIELD: key_field_start_index = 28; break; case EFUSE_OTP_5TH_KEY_SET_FIELD: key_field_start_index = 12; break; default: DBG_ERR("Unknow key set[%d] => should be 0~4\r\n", (int)key_set_index); return EFUSE_OPS_ERR; } set_key_destination(OTP_KEY_MANAGER_CRYPTO, 0); otp_key_manager(key_field_start_index); set_key_destination(OTP_KEY_MANAGER_CRYPTO, 1); otp_key_manager(key_field_start_index + 1); set_key_destination(OTP_KEY_MANAGER_CRYPTO, 2); otp_key_manager(key_field_start_index + 2); set_key_destination(OTP_KEY_MANAGER_CRYPTO, 3); otp_key_manager(key_field_start_index + 3); return E_OK; } //Bit[0] & Bit[5] == 1 /** quary_secure_boot Quary now is what kind of secure boot type @Note: key set 0 is for secure boot use @param[in] scu_status status @return Description of data returned. - @b TRUE: enabled - @b FALSE: disabled */ BOOL quary_secure_boot(SECUREBOOT_STATUS scu_status) { UINT32 sec; BOOL result = FALSE; sec = KEY_MANAGER_READ_PARAM(); switch (scu_status) { case SECUREBOOT_SECURE_EN: if ((sec & (OTP_HW_SECURE_EN | OTP_FW_SECURE_EN)) == (OTP_HW_SECURE_EN | OTP_FW_SECURE_EN)) { result = TRUE; } break; case SECUREBOOT_DATA_AREA_ENCRYPT: if ((sec & OTP_DATA_ENCRYPT_EN) == OTP_DATA_ENCRYPT_EN) { result = TRUE; } break; case SECUREBOOT_SIGN_RSA: if ((sec & OTP_SIGNATURE_RSA) == OTP_SIGNATURE_RSA) { result = TRUE; } break; case SECUREBOOT_SIGN_RSA_CHK: if ((sec & OTP_SIGNATURE_RSA_CHK_EN) == OTP_SIGNATURE_RSA_CHK_EN) { result = TRUE; } break; case SECUREBOOT_JTAG_DISABLE_EN: if ((sec & OTP_JTAG_DISABLE_EN) == OTP_JTAG_DISABLE_EN) { result = TRUE; } break; case SECUREBOOT_1ST_KEY_SET_PROGRAMMED: if ((sec & OTP_1ST_KEY_PROGRAMMED) == OTP_1ST_KEY_PROGRAMMED) { result = TRUE; } break; case SECUREBOOT_2ND_KEY_SET_PROGRAMMED: if ((sec & OTP_2ND_KEY_PROGRAMMED) == OTP_2ND_KEY_PROGRAMMED) { result = TRUE; } break; case SECUREBOOT_3RD_KEY_SET_PROGRAMMED: if ((sec & OTP_3RD_KEY_PROGRAMMED) == OTP_3RD_KEY_PROGRAMMED) { result = TRUE; } break; case SECUREBOOT_4TH_KEY_SET_PROGRAMMED: if ((sec & OTP_4TH_KEY_PROGRAMMED) == OTP_4TH_KEY_PROGRAMMED) { result = TRUE; } break; case SECUREBOOT_5TH_KEY_SET_PROGRAMMED: if ((sec & OTP_5TH_KEY_PROGRAMMED) == OTP_5TH_KEY_PROGRAMMED) { result = TRUE; } break; default: break; } return result; } /** set_secure_boot Quary now is what kind of secure boot type @Note: key set 0 is for secure boot use @param[in] scu_status status @return Description of data returned. - @b TRUE: enabled - @b FALSE: something wrong(already configured) */ BOOL enable_secure_boot(SECUREBOOT_STATUS scu_status) { UINT32 sec; BOOL result = FALSE; sec = KEY_MANAGER_READ_PARAM(); switch (scu_status) { case SECUREBOOT_SECURE_EN: if ((sec & (OTP_HW_SECURE_EN | OTP_FW_SECURE_EN)) != 0x0) { DBG_ERR("Secure already enabled ..."); } else { result = TRUE; KEY_MANAGER_WRITE_PARAM((OTP_HW_SECURE_EN | OTP_FW_SECURE_EN)); } break; case SECUREBOOT_DATA_AREA_ENCRYPT: if ((sec & OTP_DATA_ENCRYPT_EN) != 0x0) { DBG_ERR("Data area encrypted bit already set ..."); } else { result = TRUE; KEY_MANAGER_WRITE_PARAM(OTP_DATA_ENCRYPT_EN); } break; case SECUREBOOT_SIGN_RSA: if ((sec & OTP_SIGNATURE_RSA) != 0x0) { DBG_ERR("Signature use RSA bit already set ..."); } else { result = TRUE; KEY_MANAGER_WRITE_PARAM(OTP_SIGNATURE_RSA); } break; case SECUREBOOT_SIGN_RSA_CHK: if ((sec & OTP_SIGNATURE_RSA_CHK_EN) != 0x0) { DBG_ERR("Signature use RSA and process hash checksum bit already set ...\r\n"); } else { result = TRUE; KEY_MANAGER_WRITE_PARAM(OTP_SIGNATURE_RSA_CHK_EN); } break; case SECUREBOOT_JTAG_DISABLE_EN: KEY_MANAGER_WRITE_PARAM(OTP_JTAG_DISABLE_EN); result = TRUE; break; case SECUREBOOT_1ST_KEY_SET_PROGRAMMED: KEY_MANAGER_WRITE_PARAM(OTP_1ST_KEY_PROGRAMMED); result = TRUE; break; case SECUREBOOT_2ND_KEY_SET_PROGRAMMED: KEY_MANAGER_WRITE_PARAM(OTP_2ND_KEY_PROGRAMMED); result = TRUE; break; case SECUREBOOT_3RD_KEY_SET_PROGRAMMED: KEY_MANAGER_WRITE_PARAM(OTP_3RD_KEY_PROGRAMMED); result = TRUE; break; case SECUREBOOT_4TH_KEY_SET_PROGRAMMED: KEY_MANAGER_WRITE_PARAM(OTP_4TH_KEY_PROGRAMMED); result = TRUE; break; case SECUREBOOT_5TH_KEY_SET_PROGRAMMED: KEY_MANAGER_WRITE_PARAM(OTP_5TH_KEY_PROGRAMMED); result = TRUE; break; default: break; } return result; } /* otp read data Read specific eFuse addressing(32bits/per time) ^ |-- (row address) @param[in] rowAddress row address @return read half-word efuse data - @b Positive: Valid data - @b E_SYS : Invalid data */ UINT32 otp_key_manager(UINT32 rowAddress) { INT32 uiData; uiData = local_load(rowAddress); return uiData; }