blob: b676caad4927bc90b4580120b6f2439ca9b68768 [file] [log] [blame]
/******************************************************************************
*
* (C)Copyright 2022 ASR. All Rights Reserved.
*
******************************************************************************/
#include "GEU_Provisioning.h"
#include "Security.h"
#include "Errors.h"
#include "platform_geu_fuse_internal.h"
#include "geu_interface.h"
#include "GEU.h"
#include "ProtocolManager.h"
#include "timer.h"
#include "kstr_fuse_config.h"
/**
* get fuse configuration spec
*/
// FixME: use generic fuse_conf_spec
static fuse_conf_spec_t GetFuseConfSpec(void* parameter)
{
return kstr_fuse_conf_spec;
}
/**
* Attention: this function must kept consistent with what is done by Boot ROM,
* for exmaple, the pack order for public key
* perform platform binding
* @parameter ptim: pointer to TIM
* @parameter parameter: should be NULL
* @return: FUSE_FuseBurnPowerNotEnabled if UsbPhy band gap is not enabled
* other error code otherwise
*
* Note: Due to the need of provisioning of non-trusted platform and minimize
* the code size, we have a dummy implementation of this function for
* non-trusted case.
*/
// FixME: set algorithm id using info form TIM
extern UINT_T GEU_LIB_BindPlatform(pTIM ptim, void* parameter)
{
UINT_T result = NoError;
UINT_T key_word_cnt, hash_data_size_in_bytes;
UINT_T data[BINDKEYSIZE] = {0};
UINT_T fusedata[DIGEST_WLEN_MAX];
UINT_T digest[DIGEST_WLEN_MAX];
struct GEU_FuseBurnStatus burn_status;
struct GEU_FuseBurnStatus* pburn_status = &burn_status;
UINT_T programmed = 0;
UINT_T i;
pSECURITY_FUNCTIONS pSFs = GetSecurityFunctionsPointer();
GEU_UARTLOG("S OEMKeyHash...\n\r");
result = GEU_ReadOemHashKeyFuseBits(fusedata, K_SHA256_SIZE);
if (result != NoError) {
return result;
}
for (i = 0; i < K_SHA256_SIZE >> 2; i++) {
if (fusedata[i] != 0) {
programmed = 1;
break;
}
}
if (ptim->pConsTIM->VersionBind.Version < (TIM_3_4_00)) {
/* do not support TIM_3_3_00 and TIM_3_2_00 anymore */
return InvalidTIMVersionError;
}
/* compute platform verification key digest */
/* after TIM version 3.2.00 all key size is in bit */
key_word_cnt = ptim->pTBTIM_DS->KeySize / 32;
hash_data_size_in_bytes = (key_word_cnt*2 + 1) * 4; // (crypto_scheme||modulus-or-X||exponent-or-Y) in bytes (*4)
// 1) Pack the crypto_scheme
//crypto_scheme: 0x0000A100 PKCSv1_SHA1_1024RSA
// 0x0000A110 PKCSv1_SHA256_1024RSA
// 0x0000A200 PKCSv1_SHA1_2048RSA
// 0x0000A210 PKCSv1_SHA256_2048RSA
if(ptim->pTBTIM_DS->HashAlgorithmID == SHA256)
data[0] = (key_word_cnt == 64) ? PKCSv1_SHA256_2048RSA : PKCSv1_SHA256_1024RSA;
else // Defaults to 160
data[0] = (key_word_cnt == 64) ? PKCSv1_SHA1_2048RSA : PKCSv1_SHA1_1024RSA;
// 2) Pack the Modulus and Exponent
for (i=0; i < key_word_cnt; i++)
{
data[i+1] = ptim->pTBTIM_DS->Rsa.RSAModulus[i];
data[i+key_word_cnt+1] = ptim->pTBTIM_DS->Rsa.RSAPublicExponent[i];
}
//Key Padding is on by default
hash_data_size_in_bytes = BINDKEYSIZE*4; // MaxKeySize*2+CryptoScheme in Bytes: 129*4 = 516
/* compute digest */
for (i = 0; i < DIGEST_WLEN_MAX; i++) {
digest[i] = 0;
}
result = pSFs->pSHAMessageDigest((UINT8_T *)data, hash_data_size_in_bytes,
(UINT8_T *)digest, ptim->pTBTIM_DS->HashAlgorithmID);
if (result != NoError) {
return result;
}
/* allow reprogramming as it is often the case during development */
if (programmed) {
for (i = 0; i < K_SHA256_SIZE >> 2; i++) {
if (fusedata[i] != digest[i]) {
return FUSE_BurnError;
}
}
return NoError;
}
/* make sure power supply required for fuse programming is enabled */
result = GEU_EnableFuseBurnPower();
if (result != NoError) {
return FUSE_FuseBurnPowerNotEnabled;
}
/* go burn the platform key hash */
result = GEU_SetActiveFuseBlock(K_OEM_FUSEBLOCK);
if (result != NoError) {
return result;
}
result = GEU_SetupOemHashKeyFuseBits(digest, 4 * DIGEST_WLEN_MAX);
if (result != NoError) {
return result;
}
result = GEU_BurnFuseBlock_OemHashKey(pburn_status);
if(pburn_status->FinalBurnStatus) {
GEU_UARTLOG("Burn status: 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n\r",
pburn_status->FinalBurnStatus,
pburn_status->CorrectedBurnStatus,
pburn_status->RawBurnStatus,
pburn_status->SavedBurnRequest,
pburn_status->DebugStatus);
}
GEU_UARTLOG("E OEMKeyHash.\n\r");
return result;
}
// This function is called from OBM
// Always returns NoError for GEU
extern UINT_T GEU_LIB_VerifyPlatform(pTIM ptim)
{
UINT_T result;
UINT_T key_word_cnt, hash_data_size_in_bytes;
UINT_T data[BINDKEYSIZE]= {0};
UINT_T fusedata[DIGEST_WLEN_MAX];
UINT_T digest[DIGEST_WLEN_MAX];
UINT_T programmed = 0;
UINT_T i;
pSECURITY_FUNCTIONS pSFs = GetSecurityFunctionsPointer();
result = GEU_ReadOemHashKeyFuseBits(fusedata, K_SHA256_SIZE);
if (result != NoError) {
return result;
}
for (i = 0; i < K_SHA256_SIZE >> 2; i++) {
if (fusedata[i] != 0) {
programmed = 1;
break;
}
}
if (ptim->pConsTIM->VersionBind.Version < (TIM_3_4_00)) {
/* do not support TIM_3_3_00 and TIM_3_2_00 anymore */
return InvalidTIMVersionError;
}
/* after TIM version 3.2.00 all key size is in bit */
key_word_cnt = ptim->pTBTIM_DS->KeySize / 32;
hash_data_size_in_bytes = (key_word_cnt*2 + 1) * 4; // (crypto_scheme||modulus-or-X||exponent-or-Y) in bytes (*4)
// 1) Pack the crypto_scheme
//crypto_scheme: 0x0000A100 PKCSv1_SHA1_1024RSA
// 0x0000A110 PKCSv1_SHA256_1024RSA
// 0x0000A200 PKCSv1_SHA1_2048RSA
// 0x0000A210 PKCSv1_SHA256_2048RSA
if(ptim->pTBTIM_DS->HashAlgorithmID == SHA256)
data[0] = (key_word_cnt == 64) ? PKCSv1_SHA256_2048RSA : PKCSv1_SHA256_1024RSA;
else // Defaults to 160
data[0] = (key_word_cnt == 64) ? PKCSv1_SHA1_2048RSA : PKCSv1_SHA1_1024RSA;
// 2) Pack the Modulus and Exponent
for (i=0; i < key_word_cnt; i++)
{
data[i+1] = ptim->pTBTIM_DS->Rsa.RSAModulus[i];
data[i+key_word_cnt+1] = ptim->pTBTIM_DS->Rsa.RSAPublicExponent[i];
}
//Key Padding is on by default
hash_data_size_in_bytes = BINDKEYSIZE*4; // MaxKeySize*2+CryptoScheme in Bytes: 129*4 = 516
/* compute digest */
for (i = 0; i < DIGEST_WLEN_MAX; i++) {
digest[i] = 0;
}
result = pSFs->pSHAMessageDigest((UINT8_T *)data, hash_data_size_in_bytes,
(UINT8_T *)digest, ptim->pTBTIM_DS->HashAlgorithmID);
if (result != NoError) {
return result;
}
/* compare fuses against TIM */
if (programmed) {
for (i = 0; i < K_SHA256_SIZE >> 2; i++) {
if (fusedata[i] != digest[i]) {
return FUSE_FuseBlockCompareFailed;
}
}
}
return NoError;
}
/**
* Not Implemented for KSTR
* @return: always NoError
*/
extern UINT_T GEU_LIB_BindJTAGKey(pTIM ptim, void* parameter)
{
return NoError;
}
/**
* Not Implemented for KSTR
* @return: always NoError
*/
extern UINT_T GEU_LIB_VerifyJTAGKey(pTIM ptim)
{
return NoError;
}
/**
* perform platform auto-configuration
* @parameter ptim: pointer to TIM
* @parameter parameter: NULL
*/
UINT_T GEU_LIB_AutoConfigPlatform(pTIM ptim, void* parameter)
{
UINT_T result = NoError;
fuse_conf_spec_t fuse_conf;
struct GEU_FuseBurnStatus burn_status;
struct GEU_FuseBurnStatus* pburn_status = &burn_status;
fuse_conf = GetFuseConfSpec(NULL);
/* make sure power supply required for fuse programming is enabled */
result = GEU_EnableFuseBurnPower();
if (result != NoError) {
return FUSE_FuseBurnPowerNotEnabled;
}
GEU_UARTLOG("S SoC Config...\n\r");
/*
* configure SoC Configs
*/
result = GEU_LIB_ProgramSocConfig(NULL, ptim);
if (result != NoError) {
return result;
}
result = GEU_BurnFuseBlock_SocConfig(pburn_status);
if(pburn_status->FinalBurnStatus) {
GEU_UARTLOG("Burn status: 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n\r",
pburn_status->FinalBurnStatus,
pburn_status->CorrectedBurnStatus,
pburn_status->RawBurnStatus,
pburn_status->SavedBurnRequest,
pburn_status->DebugStatus);
}
GEU_UARTLOG("E SoC Config...\n\r");
return result;
}
/**
* program SoC config fuse bits
*/
UINT_T GEU_LIB_ProgramSocConfig(void* parameter, pTIM ptim)
{
UINT_T result, flash_number;
fuse_conf_spec_t fuse_conf;
fuse_conf = GetFuseConfSpec(NULL);
result = GEU_SetActiveFuseBlock(K_SOC_CONFIG_FUSEBLOCK);
if (result != NoError) {
return result;
}
if (ptim != NULL) {
if (ptim->pConsTIM->VersionBind.Trusted)
fuse_conf.plat_ap_conf[2] |= (OPMODETRUSTED); // Trusted
else
fuse_conf.plat_ap_conf[2] |= (OPMODENONTRUSTED); // Non-Trusted
}
result = GEU_SetupApConfigFuseBits(&fuse_conf.plat_ap_conf[0], fuse_conf.ap_bit_cnt/8);
if( result )
GEU_UARTLOG("Setup AP Config Error: 0x%x\n\r", result);
result = GEU_SetupTopConfigFuseBits(&fuse_conf.plat_top_conf[0], fuse_conf.top_bit_cnt/8);
if( result )
GEU_UARTLOG("Setup TOP Config Error: 0x%x\n\r", result);
return result;
}
UINT_T GEU_ProgramMajorVersion(pTIM ptim)
{
UINT_T result;
UINT_T MajorVersion, PlatVersion;
struct GEU_FuseBurnStatus burn_status;
struct GEU_FuseBurnStatus* pburn_status = &burn_status;
result = GEU_SetActiveFuseBlock(K_PLAT_VERSION_FUSEBLOCK);
if (result != NoError) {
return result;
}
result = CheckAntiRollbackPackage(ptim, &MajorVersion);
if(result & MAJOR_ATRB_ENABLED == 0) /* Anti-rollback disabled */
{
GEU_UARTLOG("Get Major version error: %d\n\r", result);
return FUSE_InvalidRequest;
}
if(MajorVersion > 31)
{
GEU_UARTLOG("MajorVersion exceed valid range: %d\n\r", MajorVersion);
return NoError;
}
/* Bit0 means anti-rollback is enabled
*/
PlatVersion = (1 << MajorVersion ) | 1;
GEU_SetupPlatVersionFuseBits(&PlatVersion, K_PLAT_VERSION_FUSE_SIZE);
result = GEU_BurnFuseBlock_SocConfig(pburn_status);
if(pburn_status->FinalBurnStatus) {
GEU_UARTLOG("Burn status: 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n\r",
pburn_status->FinalBurnStatus,
pburn_status->CorrectedBurnStatus,
pburn_status->RawBurnStatus,
pburn_status->SavedBurnRequest,
pburn_status->DebugStatus);
}
return result;
}
UINT_T GEU_ProgramMiscConfig(pTIM pTIM_h)
{
UINT_T Retval = NoError;
UINT_T ApConfig[3];
UINT_T ApConfigBurned[3];
UINT_T TopConfig = 0;
UINT_T TopConfigBurned = 0;
UINT_T LifeCyle = 0;
UINT_T LifeCyleRead = 0;
UINT_T HwLock = 0;
UINT_T HwLockRead = 0;
UINT_T SoCBurnRequest = 0; /* Block 0 */
UINT_T MiscBurnRequest = 0; /* Block 6 */
pImage_FUSE_BURN pFuseBurn;
pWTP_RESERVED_AREA_HEADER pWRAH = NULL;
UINT_T FuseBurnCfg = 0;
struct GEU_FuseBurnStatus burn_status;
struct GEU_FuseBurnStatus* pburn_status = &burn_status;
memset(ApConfig, 0, sizeof(ApConfig));
memset(ApConfigBurned, 0, sizeof(ApConfigBurned));
pWRAH = FindPackageInReserved(&Retval, pTIM_h, FUSE);
if ( !( (pWRAH == NULL) || (Retval != NoError) ) )
{
pFuseBurn = (pImage_FUSE_BURN) pWRAH;
FuseBurnCfg = pFuseBurn->Enabled;
FuseBurnCfg &= ~TRUSTBOOT_BURN_EN;
}
if(FuseBurnCfg == 0)
return NoError;
#if CLOSE_ESCAPE_SEQ || CLOSE_ROM_LOG || CLOSE_ROM_USB
GEU_ReadApConfigFuseBits(ApConfigBurned, K_AP_CONFIG_FUSE_SIZE);
if(FuseBurnCfg & DISESCAPE_BURN_EN)
ApConfig[2] |= DIS_ESCAPE_SEQ;
if(FuseBurnCfg & DISROMLOG_BURN_EN)
ApConfig[2] |= UART_LOG_DISABLE;
if(FuseBurnCfg & CLOSEUSBD_BURN_EN)
ApConfig[2] |= USB_DOWNLOAD_DISABLE;
if( ApConfig[2] && ((ApConfig[2] & ApConfigBurned[2]) != ApConfig[2]) )
SoCBurnRequest |= K_AP_CONFIG_BURN_REQUEST_MASK;
#endif
#if ENABLE_LIFTCYCLE
if(FuseBurnCfg & LIFECYLE_CM_BURN_EN)
LifeCyle = LCS_CM;
if(FuseBurnCfg & LIFECYLE_DM_BURN_EN)
LifeCyle = LCS_DM;
if(FuseBurnCfg & LIFECYLE_SP_BURN_EN)
LifeCyle = LCS_SP;
if(FuseBurnCfg & LIFECYLE_RMA_BURN_EN)
LifeCyle = LCS_RMA;
LifeCyleRead = GEU_ReadLifeCycleState();
if(LifeCyle > LifeCyleRead)
MiscBurnRequest |= K_LIFECYCLE_BURN_REQUEST_MASK;
#endif
#if ENABLE_HWLOCK
if(FuseBurnCfg & BANKHWLOCK_BURN_EN) {
HwLock = (FuseBurnCfg & BANKHWLOCK_BURN_EN) >> 16;
HwLockRead = GEU_ReadHWLockState();
if(HwLock && ((HwLock & HwLockRead) != HwLock))
MiscBurnRequest |= K_HWLOCK_BURN_REQUEST_MASK;
}
#endif
#if CLOSE_JTAG
if(FuseBurnCfg & CLOSEJTAG_BURN_EN) {
if(LifeCyle != 0 && LifeCyle != LCS_SP) {
obm_printf("Requested LifeCyle mismatch with Jtag disable requirement, abort\n\r");
return NoError;
}
LifeCyle = LCS_SP;
LifeCyleRead = GEU_ReadLifeCycleState();
TopConfig |= JTAG_PORT_DISABLE;
if(LifeCyle > LifeCyleRead) {
MiscBurnRequest |= K_LIFECYCLE_BURN_REQUEST_MASK;
}
if(LifeCyle < LifeCyleRead) {
obm_printf("Current LifeCyle is: 0x%x, can not disable Jtag\n\r", LifeCyleRead);
TopConfig &= ~JTAG_PORT_DISABLE;
}
GEU_ReadTopConfigFuseBits(&TopConfigBurned, K_TOP_CONFIG_FUSE_SIZE);
if(TopConfig && ((TopConfig & TopConfigBurned) != TopConfig)) {
SoCBurnRequest |= K_TOP_CONFIG_BURN_REQUEST_MASK;
}
}
#endif
if(SoCBurnRequest == 0 && MiscBurnRequest == 0)
return NoError;
/* make sure power supply required for fuse programming is enabled */
Retval = GEU_EnableFuseBurnPower();
if (Retval != NoError) {
return FUSE_FuseBurnPowerNotEnabled;
}
GEU_UARTLOG("S Misc Config...\n\r");
if(SoCBurnRequest) {
Retval = GEU_SetActiveFuseBlock(K_APCPMP0_FUSEBLOCK);
if (Retval != NoError) {
return Retval;
}
if(SoCBurnRequest & K_AP_CONFIG_BURN_REQUEST_MASK) {
Retval = GEU_SetupApConfigFuseBits(ApConfig, K_AP_CONFIG_FUSE_SIZE);
if( Retval )
GEU_UARTLOG("Setup AP Config Error: 0x%x\n\r", Retval);
}
if(SoCBurnRequest & K_TOP_CONFIG_BURN_REQUEST_MASK) {
Retval = GEU_SetupTopConfigFuseBits(&TopConfig, K_TOP_CONFIG_FUSE_SIZE);
if( Retval )
GEU_UARTLOG("Setup TOP Config Error: 0x%x\n\r", Retval);
}
Retval = GEU_BurnFuseBlock_SocConfig(pburn_status);
if(pburn_status->FinalBurnStatus) {
GEU_UARTLOG("Bank0 Burn status: 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n\r",
pburn_status->FinalBurnStatus,
pburn_status->CorrectedBurnStatus,
pburn_status->RawBurnStatus,
pburn_status->SavedBurnRequest,
pburn_status->DebugStatus);
}
}
if(MiscBurnRequest) {
Retval = GEU_SetActiveFuseBlock(K_HWLOCK_LCS_FUSEBLOCK);
if (Retval != NoError) {
return Retval;
}
if(MiscBurnRequest & K_LIFECYCLE_BURN_REQUEST_MASK) {
Retval = GEU_SetupLifeCycleFuseBits(&LifeCyle, K_LCS_FUSE_SIZE);
if( Retval )
GEU_UARTLOG("Setup LCS Error: 0x%x\n\r", Retval);
}
if(MiscBurnRequest & K_HWLOCK_BURN_REQUEST_MASK) {
Retval = GEU_SetupLifeCycleFuseBits(&LifeCyle, K_LCS_FUSE_SIZE);
if( Retval )
GEU_UARTLOG("Setup LCS Error: 0x%x\n\r", Retval);
}
Retval = GEU_BurnFuseBlock_MISCConfig(pburn_status);
if(pburn_status->FinalBurnStatus) {
GEU_UARTLOG("Bank6 Burn status: 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n\r",
pburn_status->FinalBurnStatus,
pburn_status->CorrectedBurnStatus,
pburn_status->RawBurnStatus,
pburn_status->SavedBurnRequest,
pburn_status->DebugStatus);
}
}
GEU_UARTLOG("E Misc Config...\n\r");
return Retval;
}