807 lines
26 KiB
C
807 lines
26 KiB
C
#include <armv7-r/cache.h>
|
|
#include <board.h>
|
|
#include <common.h>
|
|
#include <debug.h>
|
|
#include <fuse_bin.h>
|
|
#include <mailbox/sdrv_crypto_mailbox_common.h>
|
|
#include <mailbox/sdrv_crypto_mailbox_ske_basic.h>
|
|
#include <param.h>
|
|
#include <reg.h>
|
|
#include <regs_base.h>
|
|
#include <sd_boot_img/sd_boot_img.h>
|
|
#include <sdrv_crypto_init.h>
|
|
#include <sdrv_fuse.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
typedef enum {
|
|
E_ACTION_FUSE_DIRECT_PROGRAM = 1,
|
|
E_ACTION_FUSE_GEN_AND_PROGRAM = 2,
|
|
E_ACTION_FUSE_OR_OPR_PROGRAM = 3,
|
|
E_ACTION_FUSE_LOCK = 4,
|
|
E_ACTION_FUSE_SSRK_PROGRAM = 9,
|
|
E_ACTION_FUSE_TSRK_PROGRAM = 10,
|
|
E_ACTION_FUSE_KCRC_PROGRAM = 11,
|
|
} ACTION_TYPE;
|
|
|
|
#define ACTION_SEQ_TAG (0xE101)
|
|
#define ACTION_ITEM_TAG (0xF001)
|
|
#define ACTION_SEQ_VER (0x0001)
|
|
#define ACTION_ITEM_VER (0x0001)
|
|
|
|
#define EFUSE_FSRK_INDEX (48)
|
|
#define EFUSE_EHSM_CFG_INDEX (192)
|
|
#define EFUSE_NVM_ALG_MASK (0xC00)
|
|
#define EFUSE_NVM_ALG_OFFSET (10)
|
|
#define EFUSE_NVM_ALG_AES_128_ECB (0x1)
|
|
|
|
#define EFUSE_FSRK_KEY_ID (1)
|
|
#define EFUSE_SSRK_KEY_ID (3)
|
|
|
|
#define IS_NEED_TRANS(ADDR) \
|
|
(((uint32_t)(ADDR) >= IRAM1_BASE - 0x20000 && \
|
|
(uint32_t)(ADDR) < IRAM1_BASE) \
|
|
? 1 \
|
|
: 0)
|
|
|
|
#define OFFSET_BASE(ADDR) ((uint32_t)(ADDR) + 0x20000 - IRAM1_BASE)
|
|
|
|
#define TRANS_ADDR(ADDR) \
|
|
((OFFSET_BASE(ADDR) > 0x10000) \
|
|
? (R5_SF_TCM_R5_SF_TCMB_BASE - 0x10000 + OFFSET_BASE(ADDR)) \
|
|
: (R5_SF_TCM_R5_SF_TCMB_BASE + 0x10000 + OFFSET_BASE(ADDR)))
|
|
|
|
#define TRANS_TO_SEIP_ACCESS_ADDR(ADDR) \
|
|
((IS_NEED_TRANS(ADDR)) ? TRANS_ADDR(ADDR) : (uint32_t)(ADDR))
|
|
|
|
#define REAL_FUSE_NOT_SHADOW_REGISTER 1
|
|
#define NVM_ALG_AES_128_ECB_TEST 0
|
|
|
|
typedef struct {
|
|
uint16_t nTag;
|
|
uint16_t nVer;
|
|
uint16_t nCount; // action count
|
|
uint8_t bReserved[18];
|
|
uint32_t nSize; // total fuse bin size
|
|
uint32_t nCrc32;
|
|
} ACTION_SEQ_T;
|
|
|
|
typedef struct {
|
|
uint16_t nTag;
|
|
uint16_t nVer;
|
|
uint16_t nActionType;
|
|
uint16_t nLen; // 1 action and 1 item
|
|
uint8_t bReserved[8];
|
|
} ACTION_ITEM_T;
|
|
|
|
typedef struct {
|
|
uint32_t nFuseType;
|
|
uint16_t nFuseIndex;
|
|
uint16_t nFuseLen; // fuse data len
|
|
uint8_t *lpData;
|
|
} FUSE_BURN_ITEM_T;
|
|
|
|
typedef struct {
|
|
uint32_t nFuseType;
|
|
uint16_t nFuseIndex;
|
|
uint16_t nFuseLen;
|
|
uint16_t nKeyIndex;
|
|
uint16_t nKeyLen;
|
|
} FUSE_KCRC_ITEM_T;
|
|
|
|
typedef struct {
|
|
uint16_t nBankID;
|
|
uint16_t nLockType;
|
|
uint32_t nDomainType;
|
|
} FUSE_LOCK_ITEM_T;
|
|
|
|
#define htonl(A) \
|
|
((((uint32_t)(A)&0xFF000000) >> 24) | (((uint32_t)(A)&0x00FF0000) >> 8) | \
|
|
(((uint32_t)(A)&0x0000FF00) << 8) | (((uint32_t)(A)&0x000000FF) << 24))
|
|
|
|
#define ONE_KEY_INDEX_LENGTH (4)
|
|
#define ONE_FUSE_INDEX_BYTE_LENGTH (4)
|
|
|
|
static FUSE_ERR_CODE_E fuse_program_with_readback_verify(uint32_t index,
|
|
uint32_t value)
|
|
{
|
|
FUSE_ERR_CODE_E err = ERR_FUSE_BIN_NONE;
|
|
uint32_t read_value = 0;
|
|
if (0 != sdrv_fuse_sense(index, &read_value)) {
|
|
ssdk_printf(SSDK_ERR, "Failed to read fuse %d\n", index);
|
|
err = ERR_FUSE_BIN_READ_FAIL;
|
|
goto end;
|
|
}
|
|
|
|
if ((read_value & value) != value) {
|
|
read_value |= value;
|
|
ssdk_printf(SSDK_ERR, "write fuse %d val 0x%08x\n", index, read_value);
|
|
|
|
if (0 != sdrv_fuse_program(index, read_value)) {
|
|
ssdk_printf(SSDK_ERR, "Failed to write fuse %d val 0x%08x\n", index,
|
|
read_value);
|
|
err = ERR_FUSE_BIN_WRITE_FAIL;
|
|
goto end;
|
|
}
|
|
|
|
read_value = 0;
|
|
|
|
if (0 != sdrv_fuse_sense(index, &read_value)) {
|
|
ssdk_printf(SSDK_ERR, "Failed to read fuse %d\n", index);
|
|
err = ERR_FUSE_BIN_READ_FAIL;
|
|
goto end;
|
|
}
|
|
|
|
ssdk_printf(SSDK_DEBUG, "read back fuse %d val 0x%08x\n", index,
|
|
read_value);
|
|
|
|
if ((read_value & value) != value) {
|
|
ssdk_printf(SSDK_ERR, "read back error, fuse %d val 0x%08x\n",
|
|
index, read_value);
|
|
err = ERR_FUSE_BIN_READBACK_VERIFY_FAIL;
|
|
goto end;
|
|
}
|
|
} else {
|
|
ssdk_printf(SSDK_DEBUG, "no need to fuse\n");
|
|
}
|
|
|
|
end:
|
|
return err;
|
|
}
|
|
|
|
static FUSE_ERR_CODE_E fuse_seip(uint32_t index, uint32_t length,
|
|
uint32_t *value)
|
|
{
|
|
FUSE_ERR_CODE_E err = ERR_FUSE_BIN_NONE;
|
|
for (uint32_t i = 0; i < length / ONE_KEY_INDEX_LENGTH; i++) {
|
|
index += ONE_KEY_INDEX_LENGTH * i;
|
|
value = (value + ONE_KEY_INDEX_LENGTH * i);
|
|
for (uint32_t j = 0; j < ONE_KEY_INDEX_LENGTH; j++) {
|
|
ssdk_printf(SSDK_CRIT, "write cipher index:0x%08x val:0x%08x\r\n",
|
|
index + j,
|
|
htonl(*(value + ONE_KEY_INDEX_LENGTH - 1 - j)));
|
|
#if REAL_FUSE_NOT_SHADOW_REGISTER
|
|
err = fuse_program_with_readback_verify(
|
|
index + j, htonl(*(value + ONE_KEY_INDEX_LENGTH - 1 - j)));
|
|
if (err != ERR_FUSE_BIN_NONE) {
|
|
return err;
|
|
}
|
|
#else
|
|
writel(htonl(*(value + ONE_KEY_INDEX_LENGTH - 1 - j)),
|
|
APB_EFUSEC_BASE + FUSE0_OFFSET +
|
|
ONE_FUSE_INDEX_BYTE_LENGTH * (index + j));
|
|
#endif
|
|
}
|
|
}
|
|
return ERR_FUSE_BIN_NONE;
|
|
}
|
|
|
|
uint32_t get_fuse_bin_size(ACTION_SEQ_T *p_action_seq)
|
|
{
|
|
uint32_t offset = 3 * sizeof(uint16_t) + 18 * sizeof(uint8_t);
|
|
return *(uint32_t *)((uint8_t *)p_action_seq + offset);
|
|
}
|
|
|
|
uint32_t get_fuse_bin_crc(ACTION_SEQ_T *p_action_seq)
|
|
{
|
|
uint32_t offset =
|
|
3 * sizeof(uint16_t) + 18 * sizeof(uint8_t) + sizeof(uint32_t);
|
|
return *(uint32_t *)((uint8_t *)p_action_seq + offset);
|
|
}
|
|
|
|
FUSE_ERR_CODE_E verify_fuse_bin_crc(void *data)
|
|
{
|
|
uint32_t crc_calc =
|
|
sfs_crc32(0, (uint8_t *)data, sizeof(ACTION_SEQ_T) - sizeof(uint32_t));
|
|
uint32_t size = get_fuse_bin_size((ACTION_SEQ_T *)data);
|
|
crc_calc = sfs_crc32(crc_calc, (uint8_t *)data + sizeof(ACTION_SEQ_T),
|
|
size - sizeof(ACTION_SEQ_T));
|
|
uint32_t crc_recieved = get_fuse_bin_crc((ACTION_SEQ_T *)data);
|
|
if (crc_calc == crc_recieved) {
|
|
return ERR_FUSE_BIN_NONE;
|
|
} else {
|
|
return ERR_FUSE_BIN_CRC_CHECK_FAIL;
|
|
}
|
|
}
|
|
|
|
uint16_t get_action_count(ACTION_SEQ_T *p_action_seq)
|
|
{
|
|
uint32_t offset = 2 * sizeof(uint16_t);
|
|
return *(uint16_t *)((uint8_t *)p_action_seq + offset);
|
|
}
|
|
|
|
uint16_t get_action_type(ACTION_ITEM_T *p_action_item)
|
|
{
|
|
uint32_t offset = 2 * sizeof(uint16_t);
|
|
return *(uint16_t *)((uint8_t *)p_action_item + offset);
|
|
}
|
|
|
|
uint16_t get_action_length(ACTION_ITEM_T *p_action_item)
|
|
{
|
|
uint32_t offset = 3 * sizeof(uint16_t);
|
|
return *(uint16_t *)((uint8_t *)p_action_item + offset);
|
|
}
|
|
|
|
uint32_t get_fuse_type(FUSE_BURN_ITEM_T *p_fuse_item)
|
|
{
|
|
return *(uint32_t *)(p_fuse_item);
|
|
}
|
|
|
|
uint16_t get_fuse_index(FUSE_BURN_ITEM_T *p_fuse_item)
|
|
{
|
|
uint32_t offset = sizeof(uint32_t);
|
|
return *(uint16_t *)((uint8_t *)p_fuse_item + offset);
|
|
}
|
|
|
|
uint16_t get_fuse_length(FUSE_BURN_ITEM_T *p_fuse_item)
|
|
{
|
|
uint32_t offset = sizeof(uint32_t) + sizeof(uint16_t);
|
|
return *(uint16_t *)((uint8_t *)p_fuse_item + offset);
|
|
}
|
|
|
|
uint32_t *get_fuse_value(FUSE_BURN_ITEM_T *p_fuse_item)
|
|
{
|
|
uint32_t offset = sizeof(uint32_t) + 2 * sizeof(uint16_t);
|
|
return (uint32_t *)((uint8_t *)p_fuse_item + offset);
|
|
}
|
|
|
|
FUSE_ERR_CODE_E fuse_gen_and_program(FUSE_BURN_ITEM_T *p_fuse_item)
|
|
{
|
|
ssdk_printf(SSDK_CRIT, "fuse_gen_and_program\r\n");
|
|
FUSE_ERR_CODE_E err = ERR_FUSE_BIN_NONE;
|
|
int32_t ret;
|
|
uint16_t index, length;
|
|
uint8_t *value, *value_align, *value_align_seip;
|
|
length = get_fuse_length(p_fuse_item);
|
|
if (length % ONE_FUSE_INDEX_BYTE_LENGTH != 0)
|
|
return ERR_FUSE_BIN_LENGTH_CHECK_FAIL;
|
|
index = get_fuse_index(p_fuse_item);
|
|
|
|
value = (uint8_t *)malloc(CONFIG_ARCH_CACHE_LINE +
|
|
ROUNDUP(length, CONFIG_ARCH_CACHE_LINE));
|
|
if (!value) {
|
|
err = ERR_FUSE_BIN_MALLOC_FAIL;
|
|
goto end;
|
|
}
|
|
|
|
value_align = (uint8_t *)ROUNDUP((uint32_t)value, CONFIG_ARCH_CACHE_LINE);
|
|
|
|
board_mpu_init();
|
|
if (sdrv_crypto_init()) {
|
|
err = ERR_FUSE_BIN_ENC_INIT_FAIL;
|
|
goto end;
|
|
}
|
|
|
|
arch_invalidate_cache_range((addr_t)value_align,
|
|
ROUNDUP(length, CONFIG_ARCH_CACHE_LINE));
|
|
value_align_seip = (uint8_t *)TRANS_TO_SEIP_ACCESS_ADDR(value_align);
|
|
ssdk_printf(SSDK_CRIT, "value_align:0x%08x value_align_seip:0x%08x\r\n",
|
|
value_align, value_align_seip);
|
|
ret = cmd_trng_get_rand((uint8_t *)value_align_seip, length);
|
|
if (ret != 0) {
|
|
err = ERR_FUSE_BIN_GEN_DATA_FAIL;
|
|
goto end;
|
|
}
|
|
for (uint32_t i = 0; i < length / ONE_FUSE_INDEX_BYTE_LENGTH; i++) {
|
|
ssdk_printf(
|
|
SSDK_CRIT, "write index:0x%08x val:0x%08x\r\n", index + i,
|
|
*(uint32_t *)(value_align + ONE_FUSE_INDEX_BYTE_LENGTH * i));
|
|
#if REAL_FUSE_NOT_SHADOW_REGISTER
|
|
err = fuse_program_with_readback_verify(index + i, *(value_align + i));
|
|
if (err != ERR_FUSE_BIN_NONE) {
|
|
goto end;
|
|
}
|
|
#else
|
|
writel(*(value_align + i),
|
|
APB_EFUSEC_BASE + FUSE0_OFFSET +
|
|
ONE_FUSE_INDEX_BYTE_LENGTH * (index + i));
|
|
#endif
|
|
}
|
|
end:
|
|
if (value)
|
|
free(value);
|
|
return err;
|
|
}
|
|
|
|
FUSE_ERR_CODE_E fuse_oropr_program(FUSE_BURN_ITEM_T *p_fuse_item)
|
|
{
|
|
ssdk_printf(SSDK_CRIT, "fuse_oropr_program\r\n");
|
|
FUSE_ERR_CODE_E err = ERR_FUSE_BIN_NONE;
|
|
int32_t ret;
|
|
uint16_t index, length;
|
|
uint32_t *p_value;
|
|
length = get_fuse_length(p_fuse_item);
|
|
if (length % ONE_FUSE_INDEX_BYTE_LENGTH != 0)
|
|
return ERR_FUSE_BIN_LENGTH_CHECK_FAIL;
|
|
index = get_fuse_index(p_fuse_item);
|
|
p_value = get_fuse_value(p_fuse_item);
|
|
for (uint32_t i = 0; i < length / ONE_FUSE_INDEX_BYTE_LENGTH; i++) {
|
|
uint32_t read_value = 0;
|
|
ret = sdrv_fuse_sense(index + i, &read_value);
|
|
if (ret != 0)
|
|
return ERR_FUSE_BIN_READ_FAIL;
|
|
ssdk_printf(SSDK_CRIT, "read index:0x%08x val:0x%08x\r\n", index + i,
|
|
read_value);
|
|
ssdk_printf(SSDK_CRIT, "write index:0x%08x val:0x%08x\r\n", index + i,
|
|
((*(p_value + i)) | read_value));
|
|
#if REAL_FUSE_NOT_SHADOW_REGISTER
|
|
err = fuse_program_with_readback_verify(
|
|
index + i, ((*(p_value + i)) | read_value));
|
|
if (err != ERR_FUSE_BIN_NONE) {
|
|
return err;
|
|
}
|
|
#else
|
|
writel(((*(p_value + i)) | read_value),
|
|
APB_EFUSEC_BASE + FUSE0_OFFSET +
|
|
ONE_FUSE_INDEX_BYTE_LENGTH * (index + i));
|
|
#endif
|
|
}
|
|
return ERR_FUSE_BIN_NONE;
|
|
}
|
|
|
|
FUSE_ERR_CODE_E fuse_direct_program(FUSE_BURN_ITEM_T *p_fuse_item)
|
|
{
|
|
ssdk_printf(SSDK_CRIT, "fuse_direct_program\r\n");
|
|
FUSE_ERR_CODE_E err = ERR_FUSE_BIN_NONE;
|
|
uint16_t index, length;
|
|
uint32_t *p_value;
|
|
length = get_fuse_length(p_fuse_item);
|
|
if (length % ONE_FUSE_INDEX_BYTE_LENGTH != 0)
|
|
return ERR_FUSE_BIN_LENGTH_CHECK_FAIL;
|
|
index = get_fuse_index(p_fuse_item);
|
|
p_value = get_fuse_value(p_fuse_item);
|
|
for (uint32_t i = 0; i < length / ONE_FUSE_INDEX_BYTE_LENGTH; i++) {
|
|
ssdk_printf(SSDK_CRIT, "write index:0x%08x val:0x%08x\r\n", index + i,
|
|
*(p_value + i));
|
|
#if REAL_FUSE_NOT_SHADOW_REGISTER
|
|
err = fuse_program_with_readback_verify(index + i, *(p_value + i));
|
|
if (err != ERR_FUSE_BIN_NONE) {
|
|
return err;
|
|
}
|
|
#else
|
|
writel(*(p_value + i), APB_EFUSEC_BASE + FUSE0_OFFSET +
|
|
ONE_FUSE_INDEX_BYTE_LENGTH * (index + i));
|
|
#endif
|
|
}
|
|
return ERR_FUSE_BIN_NONE;
|
|
}
|
|
|
|
FUSE_ERR_CODE_E fuse_ssrk_program(FUSE_BURN_ITEM_T *p_fuse_item)
|
|
{
|
|
ssdk_printf(SSDK_CRIT, "fuse_ssrk_program\r\n");
|
|
FUSE_ERR_CODE_E err = ERR_FUSE_BIN_NONE;
|
|
int32_t ret;
|
|
uint16_t index, length;
|
|
uint32_t *p_value;
|
|
uint32_t ehsm_cfg;
|
|
uint8_t *ssrk_plain, *ssrk_cipher;
|
|
uint8_t *ssrk_plain_align, *ssrk_cipher_align;
|
|
uint8_t *ssrk_plain_align_seip, *ssrk_cipher_align_seip;
|
|
|
|
length = get_fuse_length(p_fuse_item);
|
|
if (length != 16 && length != 32)
|
|
return ERR_FUSE_BIN_LENGTH_CHECK_FAIL;
|
|
index = get_fuse_index(p_fuse_item);
|
|
p_value = get_fuse_value(p_fuse_item);
|
|
|
|
ssrk_plain = (uint8_t *)malloc(CONFIG_ARCH_CACHE_LINE +
|
|
ROUNDUP(length, CONFIG_ARCH_CACHE_LINE));
|
|
if (!ssrk_plain) {
|
|
err = ERR_FUSE_BIN_MALLOC_FAIL;
|
|
goto end;
|
|
}
|
|
ssrk_cipher = (uint8_t *)malloc(CONFIG_ARCH_CACHE_LINE +
|
|
ROUNDUP(length, CONFIG_ARCH_CACHE_LINE));
|
|
if (!ssrk_cipher) {
|
|
err = ERR_FUSE_BIN_MALLOC_FAIL;
|
|
goto end;
|
|
}
|
|
|
|
ssrk_plain_align =
|
|
(uint8_t *)ROUNDUP((uint32_t)ssrk_plain, CONFIG_ARCH_CACHE_LINE);
|
|
ssrk_cipher_align =
|
|
(uint8_t *)ROUNDUP((uint32_t)ssrk_cipher, CONFIG_ARCH_CACHE_LINE);
|
|
|
|
memcpy((uint8_t *)ssrk_plain_align, (uint8_t *)p_value, length);
|
|
|
|
#if NVM_ALG_AES_128_ECB_TEST && !REAL_FUSE_NOT_SHADOW_REGISTER
|
|
writel(EFUSE_NVM_ALG_AES_128_ECB << EFUSE_NVM_ALG_OFFSET,
|
|
APB_EFUSEC_BASE + FUSE0_OFFSET +
|
|
ONE_FUSE_INDEX_BYTE_LENGTH * EFUSE_EHSM_CFG_INDEX);
|
|
#endif
|
|
|
|
// get ehsm cfg
|
|
#if REAL_FUSE_NOT_SHADOW_REGISTER
|
|
ret = sdrv_fuse_sense(EFUSE_EHSM_CFG_INDEX, &ehsm_cfg);
|
|
if (ret != 0) {
|
|
err = ERR_FUSE_BIN_READ_FAIL;
|
|
goto end;
|
|
}
|
|
#else
|
|
ehsm_cfg = readl(APB_EFUSEC_BASE + FUSE0_OFFSET +
|
|
ONE_FUSE_INDEX_BYTE_LENGTH * EFUSE_EHSM_CFG_INDEX);
|
|
#endif
|
|
|
|
// enc ssrk
|
|
board_mpu_init();
|
|
if (sdrv_crypto_init()) {
|
|
err = ERR_FUSE_BIN_ENC_INIT_FAIL;
|
|
goto end;
|
|
}
|
|
arch_clean_cache_range((addr_t)ssrk_plain_align,
|
|
ROUNDUP(length, CONFIG_ARCH_CACHE_LINE));
|
|
arch_invalidate_cache_range((addr_t)ssrk_cipher_align,
|
|
ROUNDUP(length, CONFIG_ARCH_CACHE_LINE));
|
|
|
|
ssrk_plain_align_seip =
|
|
(uint8_t *)TRANS_TO_SEIP_ACCESS_ADDR((uint32_t)ssrk_plain_align);
|
|
ssrk_cipher_align_seip =
|
|
(uint8_t *)TRANS_TO_SEIP_ACCESS_ADDR((uint32_t)ssrk_cipher_align);
|
|
ssdk_printf(SSDK_CRIT,
|
|
"ssrk_plain_align:0x%08x ssrk_plain_align_seip:0x%08x\r\n",
|
|
ssrk_plain_align, ssrk_plain_align_seip);
|
|
ssdk_printf(SSDK_CRIT,
|
|
"ssrk_cipher_align:0x%08x ssrk_cipher_align_seip:0x%08x\r\n",
|
|
ssrk_cipher_align, ssrk_cipher_align_seip);
|
|
|
|
if ((ehsm_cfg & EFUSE_NVM_ALG_MASK) >> EFUSE_NVM_ALG_OFFSET !=
|
|
EFUSE_NVM_ALG_AES_128_ECB) {
|
|
ssdk_printf(SSDK_CRIT, "ssrk enc by sm4 ecb\r\n");
|
|
ret =
|
|
cmd_ske_basic_enc(SKE_ALG_SM4_ECB, (uint8_t *)ssrk_plain_align_seip,
|
|
length, CMD_KEY_INTERNAL, NULL, EFUSE_FSRK_KEY_ID,
|
|
NULL, (uint8_t *)ssrk_cipher_align_seip, NULL);
|
|
} else {
|
|
ssdk_printf(SSDK_CRIT, "ssrk enc by aes 128 ecb\r\n");
|
|
ret = cmd_ske_basic_enc(
|
|
SKE_ALG_AES_128_ECB, (uint8_t *)ssrk_plain_align_seip, length,
|
|
CMD_KEY_INTERNAL, NULL, EFUSE_FSRK_KEY_ID, (uint8_t *)NULL,
|
|
(uint8_t *)ssrk_cipher_align_seip, NULL);
|
|
}
|
|
if (ret != 0) {
|
|
err = ERR_FUSE_BIN_ENC_FAIL;
|
|
goto end;
|
|
}
|
|
|
|
for (uint32_t i = 0; i < length / ONE_FUSE_INDEX_BYTE_LENGTH; i++) {
|
|
ssdk_printf(
|
|
SSDK_CRIT, "plain index:0x%08x val:0x%08x\r\n", index + i,
|
|
*(uint32_t *)(ssrk_plain_align + ONE_FUSE_INDEX_BYTE_LENGTH * i));
|
|
}
|
|
for (uint32_t i = 0; i < length / ONE_FUSE_INDEX_BYTE_LENGTH; i++) {
|
|
ssdk_printf(
|
|
SSDK_CRIT, "cipher index:0x%08x val:0x%08x\r\n", index + i,
|
|
*(uint32_t *)(ssrk_cipher_align + ONE_FUSE_INDEX_BYTE_LENGTH * i));
|
|
}
|
|
|
|
// program
|
|
err = fuse_seip(index, length / ONE_FUSE_INDEX_BYTE_LENGTH,
|
|
(uint32_t *)ssrk_cipher_align);
|
|
|
|
end:
|
|
if (ssrk_plain)
|
|
free(ssrk_plain);
|
|
if (ssrk_cipher)
|
|
free(ssrk_cipher);
|
|
|
|
return err;
|
|
}
|
|
|
|
FUSE_ERR_CODE_E fuse_tsrk_program(FUSE_BURN_ITEM_T *p_fuse_item)
|
|
{
|
|
ssdk_printf(SSDK_CRIT, "fuse_tsrk_program\r\n");
|
|
FUSE_ERR_CODE_E err = ERR_FUSE_BIN_NONE;
|
|
int32_t ret;
|
|
uint16_t index, length;
|
|
uint32_t *p_value;
|
|
uint32_t ehsm_cfg;
|
|
uint8_t *tsrk_plain, *tsrk_cipher;
|
|
uint8_t *tsrk_plain_align, *tsrk_cipher_align;
|
|
uint8_t *tsrk_plain_align_seip, *tsrk_cipher_align_seip;
|
|
|
|
length = get_fuse_length(p_fuse_item);
|
|
if (length != 16 && length != 32)
|
|
return ERR_FUSE_BIN_LENGTH_CHECK_FAIL;
|
|
index = get_fuse_index(p_fuse_item);
|
|
p_value = get_fuse_value(p_fuse_item);
|
|
|
|
tsrk_plain = (uint8_t *)malloc(CONFIG_ARCH_CACHE_LINE +
|
|
ROUNDUP(length, CONFIG_ARCH_CACHE_LINE));
|
|
if (!tsrk_plain) {
|
|
err = ERR_FUSE_BIN_MALLOC_FAIL;
|
|
goto end;
|
|
}
|
|
tsrk_cipher = (uint8_t *)malloc(CONFIG_ARCH_CACHE_LINE +
|
|
ROUNDUP(length, CONFIG_ARCH_CACHE_LINE));
|
|
if (!tsrk_cipher) {
|
|
err = ERR_FUSE_BIN_MALLOC_FAIL;
|
|
goto end;
|
|
}
|
|
|
|
tsrk_plain_align =
|
|
(uint8_t *)ROUNDUP((uint32_t)tsrk_plain, CONFIG_ARCH_CACHE_LINE);
|
|
tsrk_cipher_align =
|
|
(uint8_t *)ROUNDUP((uint32_t)tsrk_cipher, CONFIG_ARCH_CACHE_LINE);
|
|
|
|
memcpy((uint8_t *)tsrk_plain_align, (uint8_t *)p_value, length);
|
|
|
|
// get enc type
|
|
#if REAL_FUSE_NOT_SHADOW_REGISTER
|
|
ret = sdrv_fuse_sense(EFUSE_EHSM_CFG_INDEX, &ehsm_cfg);
|
|
if (ret != 0) {
|
|
err = ERR_FUSE_BIN_READ_FAIL;
|
|
goto end;
|
|
}
|
|
#else
|
|
ehsm_cfg = readl(APB_EFUSEC_BASE + FUSE0_OFFSET +
|
|
ONE_FUSE_INDEX_BYTE_LENGTH * EFUSE_EHSM_CFG_INDEX);
|
|
#endif
|
|
|
|
// enc tsrk
|
|
board_mpu_init();
|
|
if (sdrv_crypto_init()) {
|
|
err = ERR_FUSE_BIN_ENC_INIT_FAIL;
|
|
goto end;
|
|
}
|
|
|
|
arch_clean_cache_range((addr_t)tsrk_plain_align,
|
|
ROUNDUP(length, CONFIG_ARCH_CACHE_LINE));
|
|
arch_invalidate_cache_range((addr_t)tsrk_cipher_align,
|
|
ROUNDUP(length, CONFIG_ARCH_CACHE_LINE));
|
|
|
|
tsrk_plain_align_seip =
|
|
(uint8_t *)TRANS_TO_SEIP_ACCESS_ADDR((uint32_t)tsrk_plain_align);
|
|
tsrk_cipher_align_seip =
|
|
(uint8_t *)TRANS_TO_SEIP_ACCESS_ADDR((uint32_t)tsrk_cipher_align);
|
|
ssdk_printf(SSDK_CRIT,
|
|
"tsrk_plain_align:0x%08x tsrk_plain_align_seip:0x%08x\r\n",
|
|
tsrk_plain_align, tsrk_plain_align_seip);
|
|
ssdk_printf(SSDK_CRIT,
|
|
"tsrk_cipher_align:0x%08x tsrk_cipher_align_seip:0x%08x\r\n",
|
|
tsrk_cipher_align, tsrk_cipher_align_seip);
|
|
|
|
if ((ehsm_cfg & EFUSE_NVM_ALG_MASK) >> EFUSE_NVM_ALG_OFFSET !=
|
|
EFUSE_NVM_ALG_AES_128_ECB) {
|
|
ssdk_printf(SSDK_CRIT, "tsrk enc by sm4 ecb\r\n");
|
|
ret =
|
|
cmd_ske_basic_enc(SKE_ALG_SM4_ECB, (uint8_t *)tsrk_plain_align_seip,
|
|
length, CMD_KEY_INTERNAL, NULL, EFUSE_SSRK_KEY_ID,
|
|
NULL, (uint8_t *)tsrk_cipher_align_seip, NULL);
|
|
} else {
|
|
ssdk_printf(SSDK_CRIT, "tsrk enc by aes 128 ecb\r\n");
|
|
ret = cmd_ske_basic_enc(
|
|
SKE_ALG_AES_128_ECB, (uint8_t *)tsrk_plain_align_seip, length,
|
|
CMD_KEY_INTERNAL, NULL, EFUSE_SSRK_KEY_ID, (uint8_t *)NULL,
|
|
(uint8_t *)tsrk_cipher_align_seip, NULL);
|
|
}
|
|
if (ret != 0) {
|
|
err = ERR_FUSE_BIN_ENC_FAIL;
|
|
goto end;
|
|
}
|
|
|
|
for (uint32_t i = 0; i < length / ONE_FUSE_INDEX_BYTE_LENGTH; i++) {
|
|
ssdk_printf(
|
|
SSDK_CRIT, "plain index:0x%08x val:0x%08x\r\n", index + i,
|
|
*(uint32_t *)(tsrk_plain_align + ONE_FUSE_INDEX_BYTE_LENGTH * i));
|
|
}
|
|
for (uint32_t i = 0; i < length / ONE_FUSE_INDEX_BYTE_LENGTH; i++) {
|
|
ssdk_printf(
|
|
SSDK_CRIT, "cipher index:0x%08x val:0x%08x\r\n", index + i,
|
|
*(uint32_t *)(tsrk_cipher_align + ONE_FUSE_INDEX_BYTE_LENGTH * i));
|
|
}
|
|
|
|
// program
|
|
err = fuse_seip(index, length / ONE_FUSE_INDEX_BYTE_LENGTH,
|
|
(uint32_t *)tsrk_cipher_align);
|
|
|
|
end:
|
|
if (tsrk_plain)
|
|
free(tsrk_plain);
|
|
if (tsrk_cipher)
|
|
free(tsrk_cipher);
|
|
|
|
return err;
|
|
}
|
|
|
|
uint32_t get_crc_fuse_type(FUSE_KCRC_ITEM_T *p_crc_fuse_item)
|
|
{
|
|
return *(uint32_t *)(p_crc_fuse_item);
|
|
}
|
|
|
|
uint16_t get_crc_fuse_index(FUSE_KCRC_ITEM_T *p_crc_fuse_item)
|
|
{
|
|
uint32_t offset = sizeof(uint32_t);
|
|
return *(uint16_t *)((uint8_t *)p_crc_fuse_item + offset);
|
|
}
|
|
|
|
uint16_t get_crc_fuse_length(FUSE_KCRC_ITEM_T *p_crc_fuse_item)
|
|
{
|
|
uint32_t offset = sizeof(uint32_t) + sizeof(uint16_t);
|
|
return *(uint16_t *)((uint8_t *)p_crc_fuse_item + offset);
|
|
}
|
|
|
|
uint16_t get_crc_key_index(FUSE_KCRC_ITEM_T *p_crc_fuse_item)
|
|
{
|
|
uint32_t offset = sizeof(uint32_t) + 2 * sizeof(uint16_t);
|
|
return *(uint16_t *)((uint8_t *)p_crc_fuse_item + offset);
|
|
}
|
|
|
|
uint16_t get_crc_key_length(FUSE_KCRC_ITEM_T *p_crc_fuse_item)
|
|
{
|
|
uint32_t offset = sizeof(uint32_t) + 3 * sizeof(uint16_t);
|
|
return *(uint16_t *)((uint8_t *)p_crc_fuse_item + offset);
|
|
}
|
|
|
|
static uint32_t reverse(uint32_t x)
|
|
{
|
|
uint32_t result = 0;
|
|
for (int32_t i = 0; i < 32; i++) {
|
|
result <<= 1;
|
|
result |= (x & 1);
|
|
x >>= 1;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
FUSE_ERR_CODE_E fuse_kcrc_program(FUSE_KCRC_ITEM_T *p_crc_fuse_item)
|
|
{
|
|
ssdk_printf(SSDK_CRIT, "fuse_kcrc_program\r\n");
|
|
uint16_t key_index, key_length, fuse_index, fuse_length;
|
|
FUSE_ERR_CODE_E err = ERR_FUSE_BIN_NONE;
|
|
int32_t ret;
|
|
uint32_t key_value;
|
|
uint32_t crc_calc = 0;
|
|
key_length = get_crc_key_length(p_crc_fuse_item);
|
|
fuse_length = get_crc_fuse_length(p_crc_fuse_item);
|
|
if ((key_length != 16 && key_length != 32) || fuse_length != 4) {
|
|
return ERR_FUSE_BIN_LENGTH_CHECK_FAIL;
|
|
}
|
|
key_index = get_crc_key_index(p_crc_fuse_item);
|
|
for (uint32_t i = 0; i < key_length / ONE_FUSE_INDEX_BYTE_LENGTH; i++) {
|
|
// read
|
|
#if REAL_FUSE_NOT_SHADOW_REGISTER
|
|
ret = sdrv_fuse_sense(key_index + i, &key_value);
|
|
if (ret != 0) {
|
|
return ERR_FUSE_BIN_READ_FAIL;
|
|
}
|
|
#else
|
|
key_value = readl(APB_EFUSEC_BASE + FUSE0_OFFSET +
|
|
ONE_FUSE_INDEX_BYTE_LENGTH * (key_index + i));
|
|
#endif
|
|
ssdk_printf(SSDK_CRIT, "read index:0x%08x val:0x%08x\r\n",
|
|
key_index + i, key_value);
|
|
// calc crc
|
|
crc_calc = sfs_crc32(crc_calc, (uint8_t *)&key_value,
|
|
ONE_FUSE_INDEX_BYTE_LENGTH);
|
|
}
|
|
|
|
// ssrk tsrk need add 16 bytes 0 to calc;
|
|
if (key_length == 16) {
|
|
for (uint32_t i = 0; i < 16 / ONE_FUSE_INDEX_BYTE_LENGTH; i++) {
|
|
key_value = 0;
|
|
crc_calc = sfs_crc32(crc_calc, (uint8_t *)&key_value,
|
|
ONE_FUSE_INDEX_BYTE_LENGTH);
|
|
}
|
|
}
|
|
crc_calc = reverse(crc_calc);
|
|
|
|
// program
|
|
fuse_index = get_crc_fuse_index(p_crc_fuse_item);
|
|
ssdk_printf(SSDK_CRIT, "write index:0x%08x val:0x%08x\r\n", fuse_index,
|
|
crc_calc);
|
|
|
|
#if REAL_FUSE_NOT_SHADOW_REGISTER
|
|
err = fuse_program_with_readback_verify(fuse_index, crc_calc);
|
|
if (err != ERR_FUSE_BIN_NONE) {
|
|
return err;
|
|
}
|
|
#else
|
|
writel(crc_calc, APB_EFUSEC_BASE + FUSE0_OFFSET +
|
|
ONE_FUSE_INDEX_BYTE_LENGTH * fuse_index);
|
|
#endif
|
|
|
|
return ERR_FUSE_BIN_NONE;
|
|
}
|
|
|
|
uint16_t get_lock_bank_id(FUSE_LOCK_ITEM_T *p_lock_item)
|
|
{
|
|
return *(uint16_t *)(p_lock_item);
|
|
}
|
|
|
|
uint16_t get_lock_type(FUSE_LOCK_ITEM_T *p_lock_item)
|
|
{
|
|
uint32_t offset = sizeof(uint16_t);
|
|
return *(uint16_t *)((uint8_t *)p_lock_item + offset);
|
|
}
|
|
|
|
FUSE_ERR_CODE_E fuse_lock_program(FUSE_LOCK_ITEM_T *p_lock_item)
|
|
{
|
|
ssdk_printf(SSDK_CRIT, "fuse_lock_program\r\n");
|
|
int32_t ret;
|
|
uint16_t bank_id = get_lock_bank_id(p_lock_item);
|
|
uint16_t lock_type = get_lock_type(p_lock_item);
|
|
|
|
ssdk_printf(SSDK_CRIT, "write bank_id:0x%08x lock_type:0x%08x\r\n",
|
|
bank_id, lock_type);
|
|
|
|
#if REAL_FUSE_NOT_SHADOW_REGISTER
|
|
ret = sdrv_fuse_lock_bank((fuse_lock_bank_e)bank_id,
|
|
(fuse_lock_bits_e)lock_type);
|
|
if (ret != 0) {
|
|
return ERR_FUSE_BIN_WRITE_FAIL;
|
|
}
|
|
#endif
|
|
|
|
return ERR_FUSE_BIN_NONE;
|
|
}
|
|
|
|
FUSE_ERR_CODE_E fuse_bin(void *data, uint32_t sz)
|
|
{
|
|
uint16_t action_count;
|
|
uint16_t action_type, action_length;
|
|
FUSE_ERR_CODE_E err = ERR_FUSE_BIN_NONE;
|
|
|
|
// verify fuse bin size
|
|
uint32_t bin_size = get_fuse_bin_size((ACTION_SEQ_T *)data);
|
|
if (bin_size != sz) {
|
|
ssdk_printf(SSDK_CRIT,
|
|
"bin size check fail, size in bin:0x%x, recieved "
|
|
"size:0x%x\r\n",
|
|
bin_size, sz);
|
|
return ERR_FUSE_BIN_SIZE_CHECK_FAIL;
|
|
}
|
|
|
|
// verify fuse bin crc
|
|
err = verify_fuse_bin_crc((ACTION_SEQ_T *)data);
|
|
if (err != ERR_FUSE_BIN_NONE) {
|
|
return err;
|
|
}
|
|
|
|
// get action count
|
|
action_count = get_action_count((ACTION_SEQ_T *)data);
|
|
ACTION_ITEM_T *p_action_item =
|
|
(ACTION_ITEM_T *)((uint8_t *)data + sizeof(ACTION_SEQ_T));
|
|
|
|
for (uint16_t i = 0; i < action_count; i++) {
|
|
// get action type
|
|
action_type = get_action_type(p_action_item);
|
|
void *p_item = (uint8_t *)p_action_item + sizeof(ACTION_ITEM_T);
|
|
switch (action_type) {
|
|
case E_ACTION_FUSE_DIRECT_PROGRAM:
|
|
err = fuse_direct_program((FUSE_BURN_ITEM_T *)p_item);
|
|
break;
|
|
case E_ACTION_FUSE_GEN_AND_PROGRAM:
|
|
err = fuse_gen_and_program((FUSE_BURN_ITEM_T *)p_item);
|
|
break;
|
|
case E_ACTION_FUSE_OR_OPR_PROGRAM:
|
|
err = fuse_oropr_program((FUSE_BURN_ITEM_T *)p_item);
|
|
break;
|
|
case E_ACTION_FUSE_LOCK:
|
|
err = fuse_lock_program((FUSE_LOCK_ITEM_T *)p_item);
|
|
break;
|
|
case E_ACTION_FUSE_SSRK_PROGRAM:
|
|
err = fuse_ssrk_program((FUSE_BURN_ITEM_T *)p_item);
|
|
break;
|
|
case E_ACTION_FUSE_TSRK_PROGRAM:
|
|
err = fuse_tsrk_program((FUSE_BURN_ITEM_T *)p_item);
|
|
break;
|
|
case E_ACTION_FUSE_KCRC_PROGRAM:
|
|
err = fuse_kcrc_program((FUSE_KCRC_ITEM_T *)p_item);
|
|
break;
|
|
default:
|
|
err = ERR_FUSE_BIN_ACTION_TYPE_NOT_FIND;
|
|
break;
|
|
}
|
|
if (err != ERR_FUSE_BIN_NONE) {
|
|
break;
|
|
}
|
|
// get next action
|
|
action_length = get_action_length(p_action_item);
|
|
p_action_item =
|
|
(ACTION_ITEM_T *)((uint8_t *)p_action_item + action_length);
|
|
}
|
|
|
|
return err;
|
|
}
|