/*==================================================================================================
 *   Project              : RTD AUTOSAR 4.4
 *   Platform             : CORTEXM
 *   Peripheral           : S32K3XX
 *   Dependencies         : none
 *
 *   Autosar Version      : 4.4.0
 *   Autosar Revision     : ASR_REL_4_4_REV_0000
 *   Autosar Conf.Variant :
 *   SW Version           : 1.0.0
 *   Build Version        : S32K3_RTD_1_0_0_D2110_ASR_REL_4_4_REV_0000_20211007
 *
 *   (c) Copyright 2020 - 2021 NXP Semiconductors
 *   All Rights Reserved.
 *
 *   NXP Confidential. This software is owned or controlled by NXP and may only be
 *   used strictly in accordance with the applicable license terms. By expressly
 *   accepting such terms or by downloading, installing, activating and/or otherwise
 *   using the software, you are agreeing that you have read, and that you agree to
 *   comply with and are bound by, such license terms. If you do not agree to be
 *   bound by the applicable license terms, then you may not retain, install,
 *   activate or otherwise use the software.
 ==================================================================================================*/

//adkp_hash
/**
 *   @file main.c
 *
 *   @addtogroup main_module main module documentation
 *   @{
 */

/* Including necessary configuration files. */
#include "Mcal.h"

volatile int exit_code = 0;
/* User includes */

#include "string.h"
#include <bsp.h>
#include "S32K344_DCM.h"

#include "hse_interface.h"
#include "demo_app_services.h"
#include "global_variables.h"
#include "hse_host_attrs.h"
#include "hse_host.h"
#include "host_flash.h"
#include "global_defs.h"
#include "Std_Types.h"

typedef struct
{
    uint8 * ram_start; /*!< Start address of section in RAM */
    uint8 * rom_start; /*!< Start address of section in ROM */
    uint8 * rom_end;   /*!< End address of section in ROM */
} Sys_CopyLayoutType;

#define CRYPTO_START_SEC_VAR_CLEARED_UNSPECIFIED_NO_CACHEABLE
#include "Crypto_MemMap.h"
static hseAttrFwVersion_t   Hse_FwVersion;
hseAttrSmrCoreStatus_t smrCoreStatus_Get;
#define CRYPTO_STOP_SEC_VAR_CLEARED_UNSPECIFIED_NO_CACHEABLE
#include "Crypto_MemMap.h"

volatile uint8_t uart_str[512] ={0} ;
ivt_t *pIvtPassive = (ivt_t*) ( BLOCK0_IVT_ADDRESS + OTA_OFFSET);


#ifdef SECURE_BOOT_CFG
const char program_info[] = "CFG";
unsigned int __attribute__((section("._int_ivt_0"))) ivt_flash[] =
{
/*00h*/     SBAF_BOOT_MARKER /* IVT marker */ ,
/* Boot configuration word */
/*04h*/     (CM7_0_ENABLE << CM7_0_ENABLE_SHIFT) | (CM7_1_ENABLE << CM7_1_ENABLE_SHIFT) ,
/*08h*/     IVT_RESERVED /* Reserved */ ,
/*C0h*/     CM7_0_VTOR_ADDR /* CM7_0 Start address */ ,
/*10h*/     IVT_RESERVED /* Reserved */,
/*14h*/     CM7_1_VTOR_ADDR /* CM7_1 Start address , lockstep only run CM7_0 */ ,
/*18h*/     IVT_RESERVED /* Reserved */ ,
/*1ch*/     CM7_2_VTOR_ADDR /* CM7_2 Start address , lockstep only run CM7_0 */ ,
/*20h*/     XRDC_CONFIG_ADDR /* XRDC configuration pointer */ ,
/*24h*/     LF_CONFIG_ADDR /* Lifecycle configuration pointer */ ,
/*28h*/     IVT_RESERVED /* Reserved */,
/*2ch*/     HSE_FW_ADDR /* Reserved */,
/*30h*/     SECURE_BOOT_APP_ADDR ,
/*34h*/     IVT_RESERVED ,
/*38h*/     SECURE_BOOT_BACKUP_ADDR ,
/*3ch*/     IVT_RESERVED ,
/*f0h*/     IVT_GMAC ,
};
#endif

#ifdef SECURE_BOOT_APP
const char program_info[] = "APP";
/*
 * 0x100000 - 1024KB
 * 0x80000  - 512KB
 * 0x40000  - 256KB
 * 0x20000  - 128KB
 * 0x10000  -  64KB
 * */
extern uint32_t __text_start;
extern uint32_t __text_size ;
const hseAppHeader_t __attribute__((section("._app_boot_header"))) app_header =
{
        .hdrTag = 0xD5 ,
        .reserved1 = {0},
        .hdrVersion = 0x60 ,
        .pAppDestAddres = 0x00 ,
        .pAppStartEntry = (uint32_t)( &__text_start ) ,
        .codeLength = (uint32_t)( 0x80000u - APPBL_START_ADDR_OFFSET - APP_HEADER_LENGTH ),
        .coreId = 0x00u ,
        .reserved2 = {0},
};
#endif


void WrtieOtaMarker( uint8_t ota_partition );
void GetHseInfo(void);
void BackupOnPassivePartition(void);

/*!
 \brief The main function for the project.
 \details The startup initialization sequence is the following:
 * - startup asm routine
 * - main()
 */
int main(void)
{
    /* Write your code here */

    hseStatus_t HseStatus;
    hseSrvResponse_t HseResponse;

    (void) HseStatus;
    (void) HseResponse;
    /* if debug disable cache */
#if 0
    Cache_Ip_Clean(CACHE_IP_ALL,true);
    Cache_Ip_Disable(CACHE_IP_ALL);
#endif

    BSP_Init();

#ifdef SECURE_BOOT_CFG
    /*check if HSE FW usage flag is already enabled,
     * if not enabled then do not proceed */
    /* if enable MPU(RTD default) the utest can't read by core */
    while ( FALSE == checkHseFwFeatureFlagEnabled())
    {
        /* user has requested to program HSE FW feature flag */
        HseResponse = EnableHSEFWUsage();
    }
#endif

    /* HSE-FW type , interface , A or B side , etc */
    GetHseInfo( ) ;

#if 0
    /* enable utest fxosc usage and dcf clock option
     * with pll enable in ivt.beq, secure boot verification can be accelerated */
    EnableFXOSCUsage();

    ChangeDcfClockOption();
#endif

    /* Check if NVM and RAM keys already formatted */
    /* format NVM and RAM key catalog */
#if 1
    if (FALSE == HSE_CheckStatus(HSE_STATUS_INSTALL_OK) )
    {
        HseResponse = HSE_Config();
        ASSERT(HSE_SRV_RSP_OK == HseResponse );

        /* check if the user have SU rights or not, if not then request for it */
        HseResponse = Sys_Auth();
        ASSERT(HSE_SRV_RSP_OK == HseResponse);

        /* import keys for cryptographic operation and secure boot */
        HseResponse = Generic_ImportKeys();
        ASSERT(HSE_SRV_RSP_OK == HseResponse );
    }
    testStatus |= KEY_CATALOGS_FORMATTED;
#endif

#if 1

    sprintf((char*) uart_str ,"\r\n run some crypto test \r\n " );
    Lpuart_Uart_Ip_SyncSend(LPUART_UART_IP_INSTANCE_USING_0, (const uint8*)uart_str, strlen((const char*) uart_str), 1000000 );

    /*HSE crypto examples: sym/asym services; sync/async operation mode*/
    HseResponse = HSE_Crypto();

    sprintf((char*) uart_str ,"\r\n crypto test is completed \r\n " );
    Lpuart_Uart_Ip_SyncSend(LPUART_UART_IP_INSTANCE_USING_0, (const uint8*)uart_str, strlen((const char*) uart_str), 1000000 );

#endif


#ifdef SECURE_BOOT_CFG  /* config secure boot */

    sprintf((char*) uart_str ,"\r\n run secure boot config test \r\n " );
    Lpuart_Uart_Ip_SyncSend(LPUART_UART_IP_INSTANCE_USING_0, (const uint8*)uart_str, strlen((const char*) uart_str), 1000000 );

#ifdef HSE_S32K3XX_OTA_ENABLE
    /* check the ivt appbl valid */
    if( !(SBAF_BOOT_MARKER == pIvtPassive->IVT_header))
    {
        sprintf((char*) uart_str, " copy the active partition cfg and app to passive partition\r\n");
        Lpuart_Uart_Ip_SyncSend(LPUART_UART_IP_INSTANCE_USING_0, (const uint8*)uart_str, strlen((const char*) uart_str), 1000000);

        BackupOnPassivePartition();
    }
#endif//HSE_S32K3XX_OTA_ENABLE

/* write OTA marker on this partition */
#ifdef HSE_S32K3XX_OTA_ENABLE
//    WrtieOtaMarker( DCMOTAR );
#endif

    /* the active partition secure boot will configurate the passive partition app,
     * then press software reset and swap two partition, config the other side */

    /* check if the other side has cfg and app  */
#ifdef HSE_S32K3XX_OTA_ENABLE
    if( SBAF_BOOT_MARKER == pIvtPassive->IVT_header )
    {
        /* configure secure boot first */
        HseResponse = SecureBootConfiguration();
        ASSERT(HSE_SRV_RSP_OK == HseResponse );

        sprintf((char*) uart_str, "\r\n secure boot config completed! \r\n ");
        Lpuart_Uart_Ip_SyncSend(LPUART_UART_IP_INSTANCE_USING_0, (const uint8*)uart_str, strlen((const char*) uart_str), 1000000);
    }

    /* check if the other side already written auth tag */
    if(     (       ( AUTH_TAG_MARKER_HIGH_ADDRESS_VAL  == *((uint32*) (AUTH_TAG_MARKER_ADDRESS + OTA_OFFSET )) ) ||
                    ( AUTH_TAG_MARKER_LOW_ADDRESS_VAL   == *((uint32*) (AUTH_TAG_MARKER_ADDRESS + OTA_OFFSET )) )
            )&&(    ( AUTH_TAG_MARKER_HIGH_ADDRESS_VAL  == *((uint32*) (AUTH_TAG_MARKER_ADDRESS  )) ) ||
                    ( AUTH_TAG_MARKER_LOW_ADDRESS_VAL   == *((uint32*) (AUTH_TAG_MARKER_ADDRESS  )) ) )   )
    {
        /* backup non-secure ivt at flash block 1*/
        HseResponse = UpdateIvt( BLOCK1_IVT_ADDRESS + OTA_OFFSET , BLOCK0_IVT_ADDRESS + OTA_OFFSET  , NON_SECURE_IVT );
        HseResponse = UpdateIvt( BLOCK1_IVT_ADDRESS, BLOCK0_IVT_ADDRESS, NON_SECURE_IVT );

        /* update secure ivt at flash block 0 , enable secure boot flow */
        HseResponse = UpdateIvt( BLOCK0_IVT_ADDRESS + OTA_OFFSET , BLOCK0_IVT_ADDRESS + OTA_OFFSET  , SECURE_IVT );
        HseResponse = UpdateIvt( BLOCK0_IVT_ADDRESS, BLOCK0_IVT_ADDRESS, SECURE_IVT );
        ASSERT(HSE_SRV_RSP_OK == HseResponse );

        sprintf((char*) uart_str, "\r\n enable active and passive partition secure boot flow! \r\n ");
        Lpuart_Uart_Ip_SyncSend(LPUART_UART_IP_INSTANCE_USING_0, (const uint8*)uart_str, strlen((const char*) uart_str), 1000000);
    }
    else
    {
        sprintf((char*) uart_str, "\r\n the other side partition don't have auth tag,\r\n switch to passive partition and write auth tag! \r\n ");
        Lpuart_Uart_Ip_SyncSend(LPUART_UART_IP_INSTANCE_USING_0, (const uint8*)uart_str, strlen((const char*) uart_str), 1000000);
    }

#endif

#ifndef HSE_S32K3XX_OTA_ENABLE
        /* configure secure boot first */
        HseResponse = SecureBootConfiguration();

        /* enable secure boot */
        if( HSE_SRV_RSP_OK == HseResponse)
        {
            HseResponse = UpdateIvt( BLOCK1_IVT_ADDRESS, BLOCK0_IVT_ADDRESS, NON_SECURE_IVT );

            HseResponse = UpdateIvt( BLOCK0_IVT_ADDRESS, BLOCK0_IVT_ADDRESS, SECURE_IVT );

            sprintf((char*) uart_str, "\r\n secure boot config completed! \r\n ");
            Lpuart_Uart_Ip_SyncSend(LPUART_UART_IP_INSTANCE_USING_0, uart_str, strlen((const char*) uart_str), 1000000);
        }
#endif

#endif /* config secure boot */

    for (;;)
    {
        #ifdef HSE_S32K3XX_OTA_ENABLE
        if( 1 == erase_flag )
        {
            /* erase the ivt sector on other side */
            Fls_CheckStatusType write_status = FLS_JOB_FAILED;
            write_status = HostFlash_EraseByLen( BLOCK0_IVT_ADDRESS + OTA_OFFSET , 0x2000 );
            ASSERT(FLS_JOB_OK == write_status);
            erase_flag = 0 ;
        }
        #endif
        if(exit_code != 0)
        {
            break;
        }
    }
    return exit_code;
}

/* HSE-FW type , interface , A or B side , etc */
void GetHseInfo(void)
{
    hseStatus_t HseStatus;
    hseSrvResponse_t HseResponse;
    (void) HseStatus;
    (void) HseResponse;
    volatile uint8_t hse_info_str[1024];
    uint8_t hse_fw_version[] = HSE_FW_VERSION;

    /* HSE FW version , interface version */
    HseResponse = GetAttr(HSE_FW_VERSION_ATTR_ID, sizeof(hseAttrFwVersion_t), &Hse_FwVersion);

    sprintf((char*) hse_info_str, "\r\n Running Secure Boot %s program \r\n Hse-FW Version : %d.%d.%d.%d.%d.%d , %s\r\n",
            program_info,
            Hse_FwVersion.reserved,Hse_FwVersion.socTypeId, Hse_FwVersion.fwTypeId,
            Hse_FwVersion.majorVersion, Hse_FwVersion.minorVersion, Hse_FwVersion.patchVersion,
            ( 0 == Hse_FwVersion.reserved )? "full mem":"AB swap");

    sprintf((char*) hse_info_str ,"%s using interface version : %d.%d.%d.%d.%d.%d \r\n " ,
            hse_info_str,
            hse_fw_version[0],hse_fw_version[1],hse_fw_version[2],
            hse_fw_version[3],hse_fw_version[4],hse_fw_version[5] );

    Lpuart_Uart_Ip_SyncSend(LPUART_UART_IP_INSTANCE_USING_0, (const uint8*)hse_info_str, strlen((const
            char*) hse_info_str), 1000000 );
    /* HSE FW version , interface version */

#ifdef HSE_S32K3XX_OTA_ENABLE
    uint32_t DCMStat = 0u;
    uint8_t DCMOTAR = 0u; //0 -- low address, 1 -- high address
    uint8_t DCMOTAA = 0u; //0 -- inactive, 1 -- active

    DCMStat = DCM->DCMSTAT;
    if(DCMStat & DCM_DCMSTAT_DCMOTAA_MASK)
    {
        DCMOTAA = 1u;
    }
    if(DCMStat & DCM_DCMSTAT_DCMOTAR_MASK)
    {
        DCMOTAR = 1u;
    }

    sprintf((char*) hse_info_str ,
            "\r\n AB_SWAP Active State : %s ,\r\n AB_SWAP Active Region : %s \r\n ",
            ( 1 == DCMOTAA ? "Active":"Inactive" ),
            ( 1 == DCMOTAR ? "High":"Low" ));
    Lpuart_Uart_Ip_SyncSend(LPUART_UART_IP_INSTANCE_USING_0, (const uint8*)hse_info_str, strlen((const
            char*) hse_info_str), 1000000 );
#endif//HSE_S32K3XX_OTA_ENABLE

    /* HSE status */
    HseStatus = HSE_GetStatus(0);

    sprintf((char*) hse_info_str, "\r\n HseStatus : %0b \r\n", HseStatus);

    /* out put HSE status detail */
#if 1
    for (uint8_t i = 0U; i < 16U; ++i)
    {
        sprintf((char*) hse_info_str ,"%s\tbit %d\t: %d %s\n",
                hse_info_str, i,
                ( HSE_CheckStatus(1<<i) ? 1 : 0),
                ( 0 != strlen(hse_status_list[i]) ? hse_status_list[i] : "RFU")
                );
    }
#endif
    Lpuart_Uart_Ip_SyncSend(LPUART_UART_IP_INSTANCE_USING_0, (const uint8*)hse_info_str, strlen((const char*) hse_info_str), 1000000);
    /* HSE status */


    /* HSE secure boot status */
    HseResponse = GetAttr(HSE_SMR_CORE_BOOT_STATUS_ATTR_ID, sizeof(hseAttrSmrCoreStatus_t), (void*) (&smrCoreStatus_Get));

    sprintf((char*) hse_info_str,
            " smrCoreStatus_Get : \r\n smrCoreStatus[1] : %0b , smrCoreStatus[0] : %0b \r\n",
            smrCoreStatus_Get.coreBootStatus[1], smrCoreStatus_Get.coreBootStatus[0]);

    sprintf((char*) hse_info_str, "%s smrStatus[1] : %0b , smrStatus[0] : %0b \r\n",
            hse_info_str,
            smrCoreStatus_Get.smrStatus[1], smrCoreStatus_Get.smrStatus[0]);

    Lpuart_Uart_Ip_SyncSend(LPUART_UART_IP_INSTANCE_USING_0, (const uint8*)hse_info_str, strlen((const char*) hse_info_str), 1000000 );
    /* HSE secure boot status */
}

#ifdef SECURE_BOOT_CFG
void BackupOnPassivePartition(void)
{
    extern uint32_t __int_flash_app_0_size ;
    extern uint32_t __int_flash_app_bin_0_start__ ;
    extern uint32 __INIT_TABLE[];

    Fls_CheckStatusType write_status = FLS_JOB_FAILED;

    uint32_t SrcAddress ;
    uint32_t DestAddress ;
    uint32_t Length ;


    const Sys_CopyLayoutType * copy_layout;
    uint32 len = 0U;
    uint32 i = 0U;
    uint32_t codeEnd = 0;
    const uint32 * initTable_Ptr = (uint32 *)__INIT_TABLE;

    /* find cfg code end */
    len = *initTable_Ptr;
    initTable_Ptr++;
    copy_layout = (const Sys_CopyLayoutType *)initTable_Ptr;
    for(i = 0; i < len; i++)
    {
        if( (uint32)copy_layout[i].rom_end > codeEnd )
        {
            codeEnd = (uint32)copy_layout[i].rom_end ;
        }
    }
    /* find code end */
    SrcAddress = BLOCK0_IVT_ADDRESS ;
    DestAddress = (uint32_t )( BLOCK0_IVT_ADDRESS + OTA_OFFSET ) ;
    Length  = ( codeEnd - (uint32_t)(BLOCK0_IVT_ADDRESS) ) ;

    write_status = HostFlash_EraseByLen(DestAddress, Length);
    ASSERT(FLS_JOB_OK == write_status);
    write_status = HostFlash_Program(DestAddress, (uint8_t*) SrcAddress, Length);
    ASSERT(FLS_JOB_OK == write_status);

    /* copy bin */
    /* align */
    SrcAddress = ( (uint32_t)( &__int_flash_app_bin_0_start__ ) - APPBL_START_ADDR_OFFSET )  ;
    DestAddress = (uint32_t )( SrcAddress + OTA_OFFSET ) ;
    Length  = (uint32_t)( &__int_flash_app_0_size ) + APPBL_START_ADDR_OFFSET ;

    write_status = HostFlash_EraseByLen( DestAddress , Length );
    ASSERT(FLS_JOB_OK == write_status);
    write_status = HostFlash_Program( DestAddress , (uint8_t*)SrcAddress, Length ) ;
    ASSERT(FLS_JOB_OK == write_status);

#if 0
    HostFlash_EraseByLen( (uint32_t )( BLOCK0_IVT_ADDRESS + OTA_OFFSET ) , (uint32_t )(0x00040000U ) == FLS_JOB_OK );
    /*  */
    ASSERT( HostFlash_Program( 0 ,
        (uint32_t )( BLOCK0_IVT_ADDRESS + OTA_OFFSET ) ,
        (uint8_t* )( BLOCK0_IVT_ADDRESS  ),
        (uint32_t )0x00040000U )== FLS_JOB_OK);

    /* copy app bin */
    HostFlash_EraseByLen( (uint32_t )( BLOCK1_IVT_ADDRESS + OTA_OFFSET ) , (uint32_t )(0x00040000U ) == FLS_JOB_OK );

    ASSERT( HostFlash_Program( 0 ,
        (uint32_t )( BLOCK1_IVT_ADDRESS + OTA_OFFSET ) ,
        (uint8_t* )( BLOCK1_IVT_ADDRESS  ),
        (uint32_t )0x00040000U )== FLS_JOB_OK);
#endif

    /* copy bin */
}

void WrtieOtaMarker(uint8_t ota_partition )
{
    hseAppHeader_t *pAppHeaderPassive = (hseAppHeader_t*) ( pIvtPassive->AppBL );

    uint32_t app_start_addr = (uint32_t)(pAppHeaderPassive->pAppStartEntry) ;
    uint32_t app_marker_addr = (uint32_t)(app_start_addr + pAppHeaderPassive->codeLength) - 0x2000 ;

    uint32_t __attribute__((aligned(4))) markerVal[2] = { 0 };
    markerVal[1] = *((uint32*) (app_marker_addr + sizeof(markerVal[0])));
    if( 0xffffffff == markerVal[1] )
    {
        markerVal[1] = 0 ;
    }
    else
    {
        markerVal[1] += 1;
    }

    HostFlash_EraseByLen( (uint32_t )( app_marker_addr ) , (uint32_t )(0x00002000U ) );

    if( 0 == ( (DCM->DCMSTAT) & DCM_DCMSTAT_DCMOTAR_MASK ) )
    {
        /* low address */
        markerVal[0] = 0x55555555 ;
    }
    else
    {
        /* high address */
        markerVal[0] = 0xaaaaaaaa ;
    }

    ASSERT( HostFlash_Program(
            (uint32_t )( app_marker_addr ) ,
            (uint8_t* )( markerVal ),
            (uint32_t )( 8u ) )== FLS_JOB_OK);
}
#endif
/** @} */
