/***********************************************************************************************************************
 *  FILE DESCRIPTION
 *  ------------------------------------------------------------------------------------------------------------------*/
/** \file
 *  \brief         Application dependent routines
 *
 *  \note          Please note, that this file contains a collection of callback functions to be used with the
 *                 Flash Bootloader. These functions may influence the behavior of the bootloader in principle.
 *                 Therefore, great care must be taken to verify the correctness of the implementation.
 *                 The contents of the originally delivered files are only examples resp. implementation proposals.
 *                 With regard to the fact that these functions are meant for demonstration purposes only, Vector
 *                 Informatik's liability shall be expressly excluded in cases of ordinary negligence, to the extent
 *                 admissible by law or statute.
 *
 *  --------------------------------------------------------------------------------------------------------------------
 *  COPYRIGHT
 *  --------------------------------------------------------------------------------------------------------------------
 *  \par Copyright
 *  \verbatim
 *  Copyright (c) 2025 by Vector Informatik GmbH.                                                  All rights reserved.
 *
 *                This software is copyright protected and proprietary to Vector Informatik GmbH.
 *                Vector Informatik GmbH grants to you only those rights as set out in the license conditions.
 *                All other rights remain with Vector Informatik GmbH.
 *  \endverbatim
 */
/**********************************************************************************************************************/

/***********************************************************************************************************************
 *  REVISION HISTORY
 *  --------------------------------------------------------------------------------------------------------------------
 *  Version    Date        Author  Change Id        Description
 *  --------------------------------------------------------------------------------------------------------------------
 *  01.00.00   2019-01-28  visrie  -                Initial version
 *  01.01.00   2019-02-18  vismvi  ESCAN00102171    Variable declared but never referenced
 *                         visrie  ESCAN00102310    Added callout to check reprogramming flag
 *  01.01.01   2019-03-07  visrie  ESCAN00102386    Fixed compiler error in ApplFbl_DetEntryHandler
 *                                 ESCAN00102399    Check NvPattern only for non-RAM blocks
 *  02.00.00   2019-05-02  visrie  ESCAN00102518    Added support to read block/application validity from NV-Memory
 *                                 ESCAN00102761    Added support for 3rd Party Tricore HSM
 *                                 ESCAN00103026    Provide BmHeader instead of StartAddress to ApplFblBmStartSoftware
 *  03.00.00   2019-07-17  visrie  ESCAN00103750    Removed target order list configuration
 *  03.01.00   2019-08-14  visrie  FBL-487          Exclude callouts if overwritten by OEM/HW layer
 *  03.01.01   2019-09-04  visrcn  ESCAN00103607    Memory qualifier mismatch
 *  04.00.00   2019-12-04  visrie  FBL-456          Updated to new LibSecBoot interface
 *                                 ESCAN00105135    Added support for new BRS API
 *  04.01.00   2020-01-16  visrie  FBL-524          Added support for vHsm SecBoot library
 *  05.00.00   2020-04-09  visrie  FBL-1016         Support new vBaseEnv, added support for VTT
 *  05.01.00   2020-04-29  vistmo  FBL-1584         Added OTA startup support
 *  05.02.00   2020-08-13  vistmo  FBL-1489         Added support for OTA swap activation
 *  05.02.01   2021-03-17  vishor  ESCAN00108386    ApplFblBmIsValidBlock implementation does not consider
 *                                                   all possible use cases
 *                                 FBL-3018         No changes
 *  05.03.00   2021-08-11  visrie  FBL-3394         Move default implementation of CheckReprogFlag into FblBm_Ap
 *  05.04.00   2021-09-17  visjdn  FBL-3865         Add default SecBoot implementation for GHS/Escrypt
 *  05.04.01   2022-04-06  vismix  FBL-4773         Support THUMB mode
 *  05.05.00   2022-04-07  vishor  FBL-4822         Add support for new MagicFlag value and Swap API
 *  05.05.01   2022-06-23  vismix  ESCAN00111879    Boot manager does not wait for HSM update recovery
 *  05.06.00   2022-07-13  vismix  FBL-5391         Add callout for missing optional dependency
 *  05.06.01   2022-11-29  vishor  ESCAN00112986    Compiler error: Undefined symbols
 *                                                   ApplFblPreMemDriver/ApplFblPostMemDriver
 *  05.07.00   2023-06-29  vistbe  FBL-7052         Add evaluation of ActivationPending
 *  05.07.01   2023-12-18  visrie  ESCAN00104829    Compiler error: Det.h missing in GENy based standalone BM
 *                                 ESCAN00111036    Compiler error: 'kFblApplicationValid' may be undeclared
 *                                 ESCAN00115752    No changes
 *  05.08.00   2024-05-16  vishor  FBL-8602         Add support for OEM updater solution
 *  05.09.00   2025-05-23  dganesh FBL-9715         Extend presence pattern to connect validity information
 **********************************************************************************************************************/

#define BM_AP_SOURCE

/***********************************************************************************************************************
 *  INCLUDES
 **********************************************************************************************************************/
#include "bm_ap.h"
#include "bm_main.h"
#include "fbl_inc.h"

#include "fbl_main_types.h"

#if defined( FBLNVPATTERN_ENABLE_SIGN_PRESENCE_PATTERN )
# include "Csm.h"
#endif /* FBLNVPATTERN_ENABLE_SIGN_PRESENCE_PATTERN */
# if defined( FBLBM_ENABLE_STANDALONE_MODE )
#  include "Det.h"
# endif
#if defined( FBLBM_ENABLE_SECURE_BOOT )
# include "fbl_secboot.h"
#  include "Csm.h"
#  include "Crypto_30_vHsm.h"
#endif /* FBLBM_AP_ENABLE_3RD_PARTY_TRICORE_HSM_USED */

# include "BrsHw.h"

/***********************************************************************************************************************
 *  VERSION
 **********************************************************************************************************************/

#if ( FBLBM_AP_VERSION != 0x0509u ) || \
    ( FBLBM_AP_RELEASE_VERSION != 0x00u )
# error "Error in bm_ap.c: Source and Header file are inconsistent!"
#endif

/***********************************************************************************************************************
 *  DEFINES
 **********************************************************************************************************************/

#if defined( _MICROSOFT_C_VTT_ )
# define FBLBM_AP_ENABLE_VTT_USECASE
#endif /* _MICROSOFT_C_VTT_ */

/* If no explicit LB for the LBT exists use the bootloader LB */
#if !defined( FBL_MTAB_LBT_BLOCK_NUMBER )
# define FBL_MTAB_LBT_BLOCK_NUMBER                       FBL_MTAB_BOOTLOADER_BLOCK_NUMBER
#endif /* FBL_MTAB_LBT_BLOCK_NUMBER */

/* Helper macro to get number of array entries */
#if defined( FBLBMAP_ARRAY_SIZE )
#else
# define FBLBMAP_ARRAY_SIZE(arr)                         (sizeof(arr) / sizeof((arr)[0])) /* PRQA S 3453 */ /* MD_MSR_FctLikeMacro */
#endif

#if defined( FBLBM_AP_CALLOUT_CHECK_TARGET_VALIDITY ) && \
    !defined( FBL_ENABLE_PRESENCE_PATTERN )
/** Compatibility define in case OEM layer uses different macro scheme */
# if !defined( kFblApplicationValid )
#  if defined( kEepApplConsistent )
#   define kFblApplicationValid                           kEepApplConsistent
#  else
#   error "kFblApplicationValid not defined or can't be mapped to an equivalent define/value."
/* TODO_CUSTOMER: Adjust the following define to map kFblApplicationValid to the correct value/define used by the OEM */
/* #define kFblApplicationValid <value/define> */
#  endif
# endif /* !kFblApplicationValid */
#endif /* FBLBM_AP_CALLOUT_CHECK_TARGET_VALIDITY && !FBL_ENABLE_PRESENCE_PATTERN */

#if defined( FBLNVPATTERN_ENABLE_SIGN_PRESENCE_PATTERN )
/** Key size of signed presence pattern */
# define FBLBM_SIGNED_PP_KEY_SIZE                         0x10u
#endif /* FBLNVPATTERN_ENABLE_SIGN_PRESENCE_PATTERN */
/***********************************************************************************************************************
 *  LOCAL DATA
 **********************************************************************************************************************/

#define FBLBMAP_START_SEC_VAR
#include "MemMap.h" /* PRQA S 5087 */ /* MD_MSR_MemMap */

#if defined( FBLBM_ENABLE_UPDATER_FAILSAFE )
V_MEMRAM0 static V_MEMRAM1 vuintx V_MEMRAM2 g_ApplFblBmSearchUpdaterHeaderIndex;
#endif /* FBLBM_ENABLE_UPDATER_FAILSAFE */

#define FBLBMAP_STOP_SEC_VAR
#include "MemMap.h" /* PRQA S 5087 */ /* MD_MSR_MemMap */

/***********************************************************************************************************************
 *  LOCAL FUNCTION PROTOTYPES
 **********************************************************************************************************************/

#if defined( FBLBM_ENABLE_SECURE_BOOT )
#  define FBLBMAP_RAMCODE_START_SEC_CODE
#  include "MemMap.h" /* PRQA S 5087 */ /* MD_MSR_MemMap */
static void ApplFblBmWaitForHsm(void);
#  define FBLBMAP_RAMCODE_STOP_SEC_CODE
#  include "MemMap.h" /* PRQA S 5087 */ /* MD_MSR_MemMap */
#endif /* FBLBM_ENABLE_SECURE_BOOT */

/***********************************************************************************************************************
 *  LOCAL FUNCTIONS
 **********************************************************************************************************************/

#if defined( FBLBM_ENABLE_SECURE_BOOT )
#  define FBLBMAP_RAMCODE_START_SEC_CODE
#  include "MemMap.h" /* PRQA S 5087 */ /* MD_MSR_MemMap */
/***********************************************************************************************************************
 *  ApplFblBmWaitForHsm
 **********************************************************************************************************************/
/*! \brief        Wait until vHSM is ready
 **********************************************************************************************************************/
static void ApplFblBmWaitForHsm(void)
{
   Std_ReturnType retVal;
   uint32 keyLength;
   uint32 hsm2host;
   uint32 host2hsm;

   /* Wait until vHsm has been started */
   do
   {
      keyLength = 4u;
      retVal = Csm_KeyElementGet(0u, CRYPTO_KE_CUSTOM_VHSM_STATUS_HSM2HOST, (uint8 *)&hsm2host, &keyLength);
      assertFblUser(retVal == E_OK, kFblSysAssertDet);
   } while (hsm2host == 0u);

   /* When a vHsmUpd is pending */
   if ((hsm2host & (1uL << CRYPTO_30_VHSM_HSM2HOST_UPDATERRUNNING)) == (1uL << CRYPTO_30_VHSM_HSM2HOST_UPDATERRUNNING))
   {
      keyLength = 4u;
#   error "Comment this line if vHsmUpdater is not used. If vHsmUpdater is used, please assign the value <vHsmUpd_Ext/vHsmUpd_ExtGeneral/vHsmUpd_ExtIpc/vHsmUpd_ExtIpcWaitMask> configured in the vHsm-updater to host2hsm below"
      host2hsm = 0x80000000u;
      /* Set configured Bit pattern to signalize the vHsmUpd that update can be started */
      retVal = Csm_KeyElementSet(0u, CRYPTO_KE_CUSTOM_VHSM_STATUS_HOST2HSM, (uint8 *)&host2hsm, keyLength);
      assertFblUser(retVal == E_OK, kFblSysAssertDet);

      /* Wait until vHsmUpd has been finished */
      do
      {
         FblLookForWatchdogVoid();

         keyLength = 4u;
         retVal = Csm_KeyElementGet(0u, CRYPTO_KE_CUSTOM_VHSM_STATUS_HSM2HOST, (uint8 *)&hsm2host, &keyLength);
         assertFblUser(retVal == E_OK, kFblSysAssertDet);
      } while ((hsm2host & ((1u << CRYPTO_30_VHSM_HSM2HOST_READY) | (1u << CRYPTO_30_VHSM_HSM2HOST_ACTIVE))) != ((1u << CRYPTO_30_VHSM_HSM2HOST_READY) | (1u << CRYPTO_30_VHSM_HSM2HOST_ACTIVE)));
   }

   /* Wait until vHsm is ready */
   Crypto_30_vHsm_WaitForHsmRam();
}
#  define FBLBMAP_RAMCODE_STOP_SEC_CODE
#  include "MemMap.h" /* PRQA S 5087 */ /* MD_MSR_MemMap */
#endif /* FBLBM_ENABLE_SECURE_BOOT */

/***********************************************************************************************************************
 *  GLOBAL FUNCTIONS
 **********************************************************************************************************************/

#define FBLBMAP_START_SEC_CODE
#include "MemMap.h" /* PRQA S 5087 */ /* MD_MSR_MemMap */

/***********************************************************************************************************************
 *  ApplFblBmPowerOnPre
 **********************************************************************************************************************/
/*! \brief        Initialization callout
 **********************************************************************************************************************/
void ApplFblBmPowerOnPre( void )
{

}

/***********************************************************************************************************************
 *  ApplFblBmPowerOnPost
 **********************************************************************************************************************/
/*! \brief        Initialization callout
 **********************************************************************************************************************/
void ApplFblBmPowerOnPost( void )
{
#if defined( FBL_ENABLE_OTA )
   vOtaM_InitMemory();
#endif /* FBL_ENABLE_OTA */
}

/***********************************************************************************************************************
 *  ApplFblBmInitPre
 **********************************************************************************************************************/
/*! \brief        Initialization callout
 **********************************************************************************************************************/
void ApplFblBmInitPre( void )
{
# if defined( BRS_FBL_LEGACY )
#  if defined( BRSHW_PREINIT_AVAILABLE )
   /* HW specific pre-initialization. */
   BrsHwPreInitPowerOn();
#  endif /* BRSHW_PREINIT_AVAILABLE */

#  if defined( BRS_ENABLE_WATCHDOG )
   /* Disable Watchdog */
   BrsHwWatchdogInitPowerOn();
#  endif /* BRS_ENABLE_WATCHDOG */

#  if defined( BRS_ENABLE_PLLCLOCKS )
   /* Initialize the PLLs. */
   BrsHwPllInitPowerOn();
#  endif /* BRS_ENABLE_PLLCLOCKS */

#  if defined( BRSHW_DISABLE_ECC_AVAILABLE )
   /* Disable Flash ECC error reporting. */
   BrsHwDisableEccErrorReporting();
#  endif /* BRSHW_DISABLE_ECC_AVAILABLE */

#  if defined( FBL_ENABLE_PRE_TIMERINIT )
   /* Timer is stopped by mode switch and has to be re-initialized. */
   FblTimerInit();
#  endif /* FBL_ENABLE_PRE_TIMERINIT */
# endif /* BRS_FBL_LEGACY */
}

/***********************************************************************************************************************
 *  ApplFblBmInitPost
 **********************************************************************************************************************/
/*! \brief        Initialization callout
 **********************************************************************************************************************/
void ApplFblBmInitPost( void )
{
#if defined( FBLBM_ENABLE_SECURE_BOOT )
   volatile vuint8 executeTestcode = kFblOk;

   /* Wait until vHSM is ready */
   ApplFblBmWaitForHsm();

   if (executeTestcode == kFblOk) /* Testcode to initialize RAM key, to simulate written key */
   {
      Std_ReturnType retVal;
      uint8 version[3u] = {0u};
      uint32 versionLength = sizeof( version );
      Crypto_VerifyResultType result = CRYPTO_E_VER_NOT_OK;
      const uint8 key[16u] = {0u};
      uint8 mac[16u] = {0u};
      const uint8 data[16u] = {0u};
      uint32 length = sizeof( mac );

      /* Get the Version of the vHsm Firmware */
      retVal = Crypto_30_vHsm_KeyElementGet( CryptoConf_CryptoKey_vHsm_Info, CRYPTO_KE_CUSTOM_VHSM_VERSION, version, &versionLength );

      /* Fill the key used for the CMAC and set it to valid */
      retVal |= Csm_KeyElementSet( CsmConf_CsmKey_CsmKey_SymmetricKey, CRYPTO_KE_MAC_KEY, key, sizeof( key ) );
      retVal |= Csm_KeySetValid( CsmConf_CsmKey_CsmKey_SymmetricKey );

      /* Generate the CMAC with the software implementation on the vHsm */
      retVal |= Csm_MacGenerate( CsmConf_CsmJob_CsmJob_MacGen_Key1, CRYPTO_OPERATIONMODE_SINGLECALL, data, sizeof( data ), mac, &length );
      retVal |= Csm_MacVerify( CsmConf_CsmJob_CsmJob_MacVer_Key1, CRYPTO_OPERATIONMODE_SINGLECALL, data, sizeof( data ), mac, sizeof( mac ) * 8u, &result );

      if (retVal != E_OK)
      {
         while (1u)
         {
            ;
         }
      }
   }
#endif /* FBLBM_ENABLE_SECURE_BOOT */
#if defined( FBL_ENABLE_OTA )
   if (vOtaM_Init() != E_OK)
   {
      /* PRQA S 2741, 4558 1 */ /* MD_FblBmAp_2741_4558 */
      assertFblUser(0u, kFblSysAssertInitializationFailed);
   }
#endif /* FBL_ENABLE_OTA */
}

#if defined( FBLBM_AP_CALLOUT_RESET )
/***********************************************************************************************************************
 *  ApplFblBmReset
 **********************************************************************************************************************/
/*! \brief        Issue Reset
 **********************************************************************************************************************/
void ApplFblBmReset(void)
{
   /* Reset ECU */
   BrsHwSoftwareResetECU();
}
#endif /* FBLBM_AP_CALLOUT_RESET */

#if defined( FBLBM_AP_CALLOUT_CHECK_TARGET_VALIDITY )
/***********************************************************************************************************************
 *  ApplFblBmCheckTargetValidity
 **********************************************************************************************************************/
/*! \brief        Checks the validity of the target (Usually: Is the Application Validity Presence Pattern set)
 *  \param[in]    targetHandle Target handle (e.g. Bootloader, Application, Updater)
 *  \return       Result of operation
 *                   kFblOk when operation succeeded
 *                   kFblFailed otherwise
 **********************************************************************************************************************/
/* PRQA S 6080 1 */ /* MD_MSR_STMIF */
tFblResult ApplFblBmCheckTargetValidity(tFblBmHdrTargetHandle targetHandle)
{
   tFblResult result;
# if defined( FBL_ENABLE_PRESENCE_PATTERN )
   vuint8 blockNo;
   tBlockDescriptor blockDescriptor;
   vuint8 device;
# else
   vuint8 applValidity;
# endif

   /* Check overall application validity for Application target */
   if (targetHandle == FBLBMHDR_TARGET_APPL)
   {
      result = kFblFailed;

# if defined( FBL_ENABLE_PRESENCE_PATTERN )
      /* Check if any PP for appl validity is set */
      blockNo = 0u;

      while ((blockNo < FblLbtGetBlockCount()) && (result != kFblOk))
      {
         if (kFblOk == FblLbtGetBlockDescriptorByNr(blockNo, &blockDescriptor))
         {
            if (kFblOk == FblMemGetDeviceByRange(blockDescriptor.blockStartAddress, blockDescriptor.blockLength, &device))
            {
#  if defined( kMioDeviceRam )
               /* Do not check the presence pattern for RAM */
               if (device != kMioDeviceRam)
#  endif
               {
                  result = FblNvPatternGet(&blockDescriptor, kFblNvPatternId_ApplValidity);
               }
            }
         }

         /* Prepare index for next loop */
         blockNo++;
      }
# else
      /* Read validity from NV-memory */
      if (ApplFblNvReadApplValidity(&applValidity) == kFblOk)
      {
         if (applValidity == kFblApplicationValid)
         {
            result = kFblOk;
         }
      }
# endif
   }
   else
   {
      /* For all other targets, no overall validity is necessary */
      result = kFblOk;
   }

   return result;
}
#endif /* FBLBM_AP_CALLOUT_CHECK_TARGET_VALIDITY */


#if defined( FBLBM_AP_CALLOUT_IS_VALIDBLOCK )
/***********************************************************************************************************************
 *  ApplFblBmIsValidBlock
 **********************************************************************************************************************/
/*! \brief        Checks the preconditions of a specific target
 *  \param[in]    targetHandle Target handle (e.g. Bootloader, Application)
 *  \param[in]    pLogicalBlock Pointer to current logical block
 *  \return       Result of operation
 *                   kFblOk when operation succeeded
 *                   kFblFailed otherwise
 **********************************************************************************************************************/
tFblResult ApplFblBmIsValidBlock(tFblBmHdrTargetHandle targetHandle,
   const V_MEMRAM1 tBlockDescriptor V_MEMRAM2 V_MEMRAM3 * pLogicalBlock)
{
   tFblResult result;
# if defined( FBL_ENABLE_PRESENCE_PATTERN ) || defined( FBLBM_ENABLE_STANDALONE_MODE )
   vuint8 device;
# endif /* FBL_ENABLE_PRESENCE_PATTERN || FBLBM_ENABLE_STANDALONE_MODE */
# if !defined( FBL_ENABLE_PRESENCE_PATTERN )
   vuint8 validityFlags[kEepSizeValidityFlags];
   vuint8 validityMask;
   vuint8 byteIdx;
# endif /* !FBL_ENABLE_PRESENCE_PATTERN */

# if (!defined( FBLBM_ENABLE_STANDALONE_MODE ) || defined( FBL_ENABLE_PRESENCE_PATTERN ))
#  if defined( V_ENABLE_USE_DUMMY_STATEMENT )
   (void)targetHandle;
#  endif /* V_ENABLE_USE_DUMMY_STATEMENT */
# endif /* ( !FBLBM_ENABLE_STANDALONE_MODE || FBL_ENABLE_PRESENCE_PATTERN ) */

   result = kFblFailed;

# if defined( FBLBM_ENABLE_STANDALONE_MODE ) && !defined( FBL_ENABLE_PRESENCE_PATTERN)
#   error "If presence pattern is disabled special handling must be configured for the FBL because          \
           validity flags are not available for the FBL."
   /* Perform presence pattern check only for FBL, use NV validity flags for other blocks */
   if (targetHandle == FBLBMHDR_TARGET_FBL)
# endif /* FBLBM_ENABLE_STANDALONE_MODE && !FBL_ENABLE_PRESENCE_PATTERN */
# if defined( FBL_ENABLE_PRESENCE_PATTERN ) || defined( FBLBM_ENABLE_STANDALONE_MODE )
   {
      /* Check the presence pattern value */
      if (kFblOk == FblMemGetDeviceByRange(pLogicalBlock->blockStartAddress, pLogicalBlock->blockLength, &device))
      {
#  if defined( kMioDeviceRam )
         /* Do not check the presence pattern for RAM */
         if (device != kMioDeviceRam)
#  endif /* kMioDeviceRam */
         {
            result = FblNvPatternGetByBlockDescriptor(pLogicalBlock, kFblNvPatternId_BlockValidity );
         }
      }
   }
# endif /* FBL_ENABLE_PRESENCE_PATTERN || FBLBM_ENABLE_STANDALONE_MODE */
# if !defined( FBL_ENABLE_PRESENCE_PATTERN )
#  if defined( FBLBM_ENABLE_STANDALONE_MODE )
   /* Check NV validity flags if block other than FBL is checked */
   else
#  endif /* FBLBM_ENABLE_STANDALONE_MODE */
   {
      /* Calculate index and mask for validity bit of logical block */
      byteIdx = (pLogicalBlock->blockNr >> 0x03u);
      validityMask = (vuint8)(0x01u << (pLogicalBlock->blockNr & 0x07u));

      /* Read validity information from non-volatile memory */
      if (ApplFblNvReadValidityFlags(validityFlags) == kFblOk)
      {
         if ((validityFlags[byteIdx] & validityMask) == 0u)
         {
            /* Block is valid */
            result = kFblOk;
         }
      }
   }
# endif /* !FBL_ENABLE_PRESENCE_PATTERN */

   return result;
}
#endif /* FBLBM_AP_CALLOUT_IS_VALIDBLOCK */

#if defined( FBLNVPATTERN_ENABLE_SIGN_PRESENCE_PATTERN )
# if defined( FBLBM_AP_CALLOUT_IS_VALIDPATTERN )
/***********************************************************************************************************************
 *  ApplFblBmCheckPresencePattern
 **********************************************************************************************************************/
/*! \brief        Explicitly checks the presence pattern(excluding the CMAC) validity of the target
 *  \param[in]    targetHandle Target handle (e.g. Bootloader, Application)
 *  \param[in]    pLogicalBlock Pointer to current logical block
 *  \return       Result of operation
 *                   kFblOk when operation succeeded
 *                   kFblFailed otherwise
 **********************************************************************************************************************/
tFblResult ApplFblBmCheckPresencePattern(tFblBmHdrTargetHandle targetHandle,
   const V_MEMRAM1 tBlockDescriptor V_MEMRAM2 V_MEMRAM3 * pLogicalBlock)
{
   tFblResult result;

   vuint8 device;
   IO_PositionType      patternAddress;
   IO_SizeType          patternLength;
   tFblNvPatternState   patternState;

# if defined( V_ENABLE_USE_DUMMY_STATEMENT )
   (void)targetHandle;
# endif /* V_ENABLE_USE_DUMMY_STATEMENT */

   result = kFblFailed;

   /* Check the presence pattern value of Target */
   if (kFblOk == FblMemGetDeviceByRange(pLogicalBlock->blockStartAddress, pLogicalBlock->blockLength, &device))
   {
# if defined( kMioDeviceRam )
      /* Do not check the presence pattern for RAM */
      if (device != kMioDeviceRam)
# endif /* kMioDeviceRam */
      {
          /* Check state of Target pattern */
          patternState = FblNvPatternGetPatternState(pLogicalBlock, kFblNvPatternId_BlockValidity, &patternAddress, &patternLength);
          if ((patternState.markerState == FBL_NVPATTERN_STATE_EXPECTEDVALUE) && (patternState.maskState == FBL_NVPATTERN_STATE_ERASED))
          {
              result = kFblOk;
          }
      }
   }

   return result;
}
# endif /* FBLBM_AP_CALLOUT_IS_VALIDPATTERN */

# if defined( FBLBM_AP_CALLOUT_GET_PP_SIGN_KEYEMPTY )
/***********************************************************************************************************************
 *  ApplFblBmGetPresPattSignInitStatus
 **********************************************************************************************************************/
/*! \brief        Checks if now keys has been programmed so far Presence pattern
 *  \return       FBLBM_KEY_IS_AVAILABLE      if the keys are already programmed
                  FBLBM_KEY_IS_NOT_AVAILABLE  else
 **********************************************************************************************************************/
tFblBmKeyEmptyResult ApplFblBmGetPresPattSignInitStatus( void )
{
   /* TODO_CUSTOMER: implement check if key is available here. This can be done by querying the HSM/SHE (depending
    * on the used hardware) or e.g. by checking a pattern in the flash which indicates that the FBL has written the key
    * into the Crypto.
    */
   tFblBmKeyEmptyResult result;
   vuint8 key[FBLBM_SIGNED_PP_KEY_SIZE];
   vuint32 keyLength;

   if (Csm_KeyElementGet(FblNvPattern_GetCsmKeyIdMac, CRYPTO_KE_CIPHER_KEY, key, (uint32*)&keyLength) != CRYPTO_E_KEY_NOT_AVAILABLE)  
   {
      result = FBLBM_KEY_IS_AVAILABLE;
   }
   else
   {
      result = FBLBM_KEY_IS_NOT_AVAILABLE;
   }

   return result;
}
# endif /* FBLBM_AP_CALLOUT_GET_PP_SIGN_KEYEMPTY */
#endif /* FBLNVPATTERN_ENABLE_SIGN_PRESENCE_PATTERN */

#if defined( FBLBM_CALLOUT_IS_OPTIONALBLOCK )
/***********************************************************************************************************************
 *  ApplFblBmIsOptionalBlock
 **********************************************************************************************************************/
/*! \brief        Callout when logical block is optional and not present
 *  \param[in]    targetHandle Target handle (e.g. Bootloader, Application)
 *  \param[in]    pLogicalBlock Pointer to current logical block
 **********************************************************************************************************************/
void ApplFblBmIsOptionalBlock(tFblBmHdrTargetHandle targetHandle,
   const V_MEMRAM1 tBlockDescriptor V_MEMRAM2 V_MEMRAM3 * pLogicalBlock)
{
# if defined( V_ENABLE_USE_DUMMY_STATEMENT )
   (void)targetHandle;
   (void)pLogicalBlock;
# endif /* V_ENABLE_USE_DUMMY_STATEMENT */
}
#endif /* FBLBM_CALLOUT_IS_OPTIONALBLOCK */

#if defined( FBLBM_AP_CALLOUT_START_SOFTWARE )
/***********************************************************************************************************************
 *  ApplFblBmStartSoftware
 **********************************************************************************************************************/
/*! \brief       This function is called to start a software (e.g. Bootloader)
 *  \details     Please note: The function will never return because control is handed over to the running software.
 *  \param[in]   bmHeader Pointer to the targets BM Header structure, which shall be started
 **********************************************************************************************************************/
void ApplFblBmStartSoftware(const V_MEMRAM1 tFblBmHdrHeader V_MEMRAM2 V_MEMRAM3 * bmHeader)
{
# if defined( BRS_INSTRUCTION_SET_THUMB )
   JSR(bmHeader->bmEntryAddress | 1u);  /* PRQA S 0305 */ /* MD_FblBmAp_0305 */
# else
   JSR(bmHeader->bmEntryAddress);  /* PRQA S 0305 */ /* MD_FblBmAp_0305 */
# endif

# if defined( FBL_ENABLE_SYSTEM_CHECK )
   /* Code should never be reached */
   while (1u)
   {
      ;
   }
# endif /* FBL_ENABLE_SYSTEM_CHECK */
}
#endif /* FBLBM_AP_CALLOUT_START_SOFTWARE* */

#if defined( FBLBM_AP_CALLOUT_FAILSAFE_UPDATER_USER_CHECK ) && defined( FBLBM_ENABLE_UPDATER_FAILSAFE_USER )
/***********************************************************************************************************************
 *  ApplFblBmFailsafeUpdaterUserCheck
 **********************************************************************************************************************/
/*! \brief       This function can be used to implement a user-defined updater and provide its entry address
 *  \details     This function will be called if the user-defined updater feature is enabled and will control the rest
 *                of the bootmanager program flow
 *  \param[out]  bmHeader Pointer to the BM Header structure whose jump address must be updated in case updater is found
 *  \return      kFblOk: User-defined updater is available, jump to address given by bmHeader->bmEntryAddress
 *               kFblFailed: User-defined updater is not available, proceed to next state (failed state)
 **********************************************************************************************************************/
/* PRQA S 3673 1 */ /* MD_MSR_Rule8.13 */
tFblResult ApplFblBmFailsafeUpdaterUserCheck(V_MEMRAM1 tFblBmHdrHeader V_MEMRAM2 V_MEMRAM3 * bmHeader)
{
# if defined( V_ENABLE_USE_DUMMY_STATEMENT )
   (void)bmHeader;
# endif /* V_ENABLE_USE_DUMMY_STATEMENT */
   /* TODO_CUSTOMER: Implement user updater check here. If the user updater is valid, set bmHeader->bmEntryAddress
    * to the jump address of the updater entry function and set return value to kFblOk */

   return kFblFailed;
}
#endif

#if defined( FBLBM_ENABLE_SECURE_BOOT )
# if defined( FBLBM_ENABLE_SECBOOT_FBL_INIT_KEY )
#  if defined( FBLBM_AP_CALLOUT_GET_KEYEMPTY )
/***********************************************************************************************************************
 *  ApplFblBmGetKeyEmpty
 **********************************************************************************************************************/
/*! \brief        Checks if now keys has been programmed so far
 *  \return       FBLBM_KEY_IS_AVAILABLE      if the keys are already programmed
                  FBLBM_KEY_IS_NOT_AVAILABLE  else
 **********************************************************************************************************************/
tFblBmKeyEmptyResult ApplFblBmGetKeyEmpty( void )
{
   /* TODO_CUSTOMER: implement check if key is available here. This can be done by querying the HSM/SHE (depending
    * on the used hardware) or e.g. by checking a pattern in the flash which indicates that the FBL has written the key
    * into the Crypto.
    */
   tFblBmKeyEmptyResult result;

#    error "No default implementation for this variant available."
   /* Per default assume that the key is available */
   result = FBLBM_KEY_IS_AVAILABLE;

   return result;
}
#  endif /* FBLBM_AP_CALLOUT_GET_KEYEMPTY */
# endif /* FBLBM_ENABLE_SECBOOT_FBL_INIT_KEY */

# if defined( FBLBM_ENABLE_SECBOOT_FBL_INIT_MAC )
#  if defined( FBLBM_AP_CALLOUT_GET_FBL_CMACERASED )
/***********************************************************************************************************************
 *  ApplFblBmGetFblCmacErased
 **********************************************************************************************************************/
/*! \brief        Checks if MACs for the FBL has been programmed so far
 *  \return       FBLBM_MAC_IS_AVAILABLE     If the MACs of the FBL are already written
 *                FBLBM_MAC_IS_NOT_AVAILABLE Else. E.g. because the FBL is just flashed by a debugger
 **********************************************************************************************************************/
tFblBmMacEmptyResult ApplFblBmGetFblCmacErased( const tFblBmBlockInfo * fblBlockInfo )
{
   /* TODO_CUSTOMER: implement check if CMAC is available here. This can be done by checking the CMAC content or e.g.
    * by checking a pattern in the flash which indicates that the FBL CMAC was already written
    */

   tFblBmMacEmptyResult result;


#    if defined( V_ENABLE_USE_DUMMY_STATEMENT )
   (void)fblBlockInfo;
#    endif /* V_ENABLE_USE_DUMMY_STATEMENT */

   if (ApplFblSbIsInitialStartup() == kFblOk)
   {
      /* This is the first startup, the SecureBootSegments needs to be updated */
      result = FBLBM_MAC_IS_NOT_AVAILABLE;
   }
   else
   {
      result = FBLBM_MAC_IS_AVAILABLE;
   }

   return result;
}
#  endif /* FBLBM_AP_CALLOUT_GET_FBL_CMACERASED */
# endif /* FBLBM_ENABLE_SECBOOT_FBL_INIT_MAC */
#endif /* FBLBM_ENABLE_SECURE_BOOT */

#if defined( FBLBM_AP_CALLOUT_CHECKREPROGFLAG )
/***********************************************************************************************************************
 *  ApplFblBmCheckReprogFlag
 **********************************************************************************************************************/
/*! \brief        Checks if a reprogramming request flag is set.
 *  \return       Result of operation
 *                   kFblOk when reprogramming request flag is set
 *                   kFblFailed otherwise
 **********************************************************************************************************************/
tFblResult ApplFblBmCheckReprogFlag( void )
{
   tFblResult result = kFblFailed;
# if !defined( FBL_ENABLE_FBL_START )
   vuint8 progReqFlag = 0u;
# endif

# if defined( FBL_ENABLE_FBL_START )
   if (FblBmChkFblStartMagicFlag())
   {
      /* FblStart magic flag is set, do not clear flag as the Bootloader requires it as well */
      result = kFblOk;
   }
# else
   /* Check the reprogramming request flag */
   if (ApplFblNvReadProgReqFlag(&progReqFlag) == kFblOk)
   {
      if (progReqFlag == kEepFblReprogram)
      {
         /* UDS-Reprogramming flag is set, do not clear flag as the Bootloader requires it as well */
         result = kFblOk;
      }
#  if defined( FBL_ENABLE_XCP )
      else if (progReqFlag == kEepFblXcpProgram)
      {
         /* XCP-Reprogramming flag is set, do not clear flag as the Bootloader requires it as well */
         result = kFblOk;
      }
#  endif
#  if defined( FBL_ENABLE_OTA )
      else if (progReqFlag == kEepFblOtaReprogram)
      {
         /* OTA-Reprogramming flag is set, do not clear flag as the Bootloader requires it as well */
         result = kFblOk;
      }
#  endif
      else
      {
         /* Nothing to do */
      }
   }
# endif /* FBL_ENABLE_FBL_START */

# if defined( FBLBM_MAIN_ENABLE_MAGICFLAG ) &&  \
     defined( FBLBM_ENABLE_SECURE_BOOT ) &&     \
     defined( FBLBM_MAIN_ENABLE_HARDWARE_SWAP )
   if (FblBmChkSBUpdateMagicFlag())
   {
      /* Start FBL in case of secure boot update */
      result = kFblOk;
   }
# endif

# if defined( FBL_ENABLE_OTA )
   if (vOtaM_GetState() == vOtaM_State_OtaRequest)
   {
      /* OTA request is pending -> bootloader should be started */
      result = kFblOk;
   }
# endif /* FBL_ENABLE_OTA */

   return result;
}
#endif /* FBLBM_AP_CALLOUT_CHECKREPROGFLAG */

#if defined( FBLBM_ENABLE_UPDATER_FAILSAFE )
# if defined( FBLBM_AP_CALLOUT_SEARCH_FAILSAFE_UPDATER_INIT )
/***********************************************************************************************************************
 *  ApplFblBmSearchUpdaterHeaderInit
 **********************************************************************************************************************/
/*! \brief        Prepare search for updater BmHeader location
 *  \return       Result of operation
 *                   kFblOk when operation succeeded
 *                   kFblFailed otherwise
 **********************************************************************************************************************/
tFblResult ApplFblBmSearchUpdaterHeaderInit(void)
{
   g_ApplFblBmSearchUpdaterHeaderIndex = 0u;
   return kFblOk;
}
# endif /* FBLBM_AP_CALLOUT_SEARCH_FAILSAFE_UPDATER_INIT */

# if defined( FBLBM_AP_CALLOUT_SEARCH_FAILSAFE_UPDATER_HEADER_ADDRESS )
/***********************************************************************************************************************
 *  ApplFblBmSearchUpdaterHeaderAddress
 **********************************************************************************************************************/
/*! \brief        Get address of possible location of a BmHeader for the Failsafe Updater
 *  \param[out]   headerAddress  Address where the BmHeader could possible be located
 *  \return       Result of operation
 *                   kFblOk when operation succeeded
 *                   kFblFailed otherwise
 **********************************************************************************************************************/
tFblResult ApplFblBmSearchUpdaterHeaderAddress(vuint32 * headerAddress)
{
   vuint32 offset = 0u;
   (* headerAddress) = FlashBlock[g_ApplFblBmSearchUpdaterHeaderIndex].begin + offset;
   return kFblOk;
}
# endif /* FBLBM_AP_CALLOUT_SEARCH_FAILSAFE_UPDATER_HEADER_ADDRESS */

# if defined( FBLBM_AP_CALLOUT_SEARCH_FAILSAFE_UPDATER_NEXT )
/***********************************************************************************************************************
 *  ApplFblBmSearchUpdaterHeaderNext
 **********************************************************************************************************************/
/*! \brief        Get (next) possible location of a BmHeader for the Failsafe Updater
 *  \return       Result of operation
 *                   kFblOk when operation succeeded
 *                   kFblFailed otherwise
 **********************************************************************************************************************/
tFblResult ApplFblBmSearchUpdaterHeaderNext(void)
{
   tFblResult result;

   g_ApplFblBmSearchUpdaterHeaderIndex++;

   if (g_ApplFblBmSearchUpdaterHeaderIndex < kNrOfFlashBlock)
   {
      result = kFblOk;
   }
   else
   {
      result = kFblFailed;
   }

   return result;
}
# endif /* FBLBM_AP_CALLOUT_SEARCH_FAILSAFE_UPDATER_NEXT */
#endif /* FBLBM_ENABLE_UPDATER_FAILSAFE */

#if defined( FBLBM_AP_CALLOUT_FATAL_ERROR )
/***********************************************************************************************************************
 *  ApplFblBmFatalError
 **********************************************************************************************************************/
/*! \brief       This function is called in case no valid starting software was found
 *  \details     Provide here some final tasks which shall be executed
 **********************************************************************************************************************/
void ApplFblBmFatalError(tFblBmError error)
{
# if defined( V_ENABLE_USE_DUMMY_STATEMENT )
   (void)error;
# endif /* V_ENABLE_USE_DUMMY_STATEMENT */

# if defined( FBL_ENABLE_SYSTEM_CHECK )
   /* Code should never be reached */
   while (1u)
   {
      ;
   }
# endif /* FBL_ENABLE_SYSTEM_CHECK */
}
#endif /* FBLBM_AP_CALLOUT_FATAL_ERROR */

/*-- Other callout functions -----------------------------------------------------------------------------------------*/

#if defined( FBLBM_ENABLE_STANDALONE_MODE )
# if defined( FBL_ENABLE_ASSERTION )
/***********************************************************************************************************************
 *  ApplFblFatalError
 **********************************************************************************************************************/
/*! \brief       Will be called in case of an urecoverable error
 **********************************************************************************************************************/
void ApplFblFatalError( FBL_DECL_ASSERT_EXTENDED_INFO(vuint8 errorCode) )
{
   /* Change this variable in debugger in order to return to caller */
   volatile vuint8 stayInWhile = 1u;

#  if defined( V_ENABLE_USE_DUMMY_STATEMENT )
   (void)errorCode;
#  endif /* V_ENABLE_USE_DUMMY_STATEMENT */

   while (0u != stayInWhile)
   {
      FblLookForWatchdogVoid();
   }
}
# endif /* FBL_ENABLE_ASSERTION */

#  if (DET_ENABLED == STD_ON)
/***********************************************************************************************************************
 *  ApplFbl_DetEntryHandler
 **********************************************************************************************************************/
/*! \brief       Called by DET module to check if a DET error is intended bootloader behavior or not.
 *  \param[in]   ModuleId Code number of the encountered assertion
 *  \param[in]   InstanceId Name of the affected module (Only if extended info is enabled)
 *  \param[in]   ApiId Line number where the assertion occurred (Only if extended info is enabled)
 *  \param[in]   ErrorId Line number where the assertion occurred (Only if extended info is enabled)
 *  \return      Report if error should be handed over to DET or not
 **********************************************************************************************************************/
#   if ((DET_AR_RELEASE_MAJOR_VERSION >= 4u) && (DET_AR_RELEASE_MINOR_VERSION >= 3u))
FUNC(Std_ReturnType, DET_CODE) ApplFbl_DetEntryHandler( uint16 ModuleId, uint8 InstanceId, uint8 ApiId, uint8 ErrorId )
#   else
FUNC(boolean, DET_APPL_CODE) ApplFbl_DetEntryHandler( uint16 ModuleId, uint8 InstanceId, uint8 ApiId, uint8 ErrorId )
#   endif /* DET_AR_RELEASE_ */
{
#   if ((DET_AR_RELEASE_MAJOR_VERSION >= 4u) && (DET_AR_RELEASE_MINOR_VERSION >= 3u))
   Std_ReturnType result = E_OK;
   /* Use result value of E_NOT_OK to ignore the DET */
#   else
   boolean result = FALSE;
   /* Use result value of TRUE to ignore the DET */
#   endif /* DET_AR_RELEASE_ */

#   if defined( V_ENABLE_USE_DUMMY_STATEMENT )
   (void)ModuleId;
   (void)InstanceId;
   (void)ApiId;
   (void)ErrorId;
#   endif /* V_ENABLE_USE_DUMMY_STATEMENT */

   return result;
}
#  endif /* DET_ENABLED == STD_ON */

# if defined( FBL_MIO_ENABLE_HOOKS )
/***********************************************************************************************************************
 *  ApplFblPreMemDriver
 **********************************************************************************************************************/
/*! \brief        Function is called before the memory driver is executed.
 *  \param[in]    device   Memory device, which is going to be used.
 *  \param[in]    function Function of the memory device, which is going to be called.
 **********************************************************************************************************************/
void ApplFblPreMemDriver( vuint8 device, vuint8 function )
{
   uint8 opMode;
   Std_ReturnType retVal;

#  if defined( V_ENABLE_USE_DUMMY_STATEMENT )
   /* Parameters not used: avoid compiler warning */
   (void)device;
   (void)function;
#  endif
   /* TODO_CUSTOMER: Adapt this example implementation to project-specific needs/requirements */
   /* Suspend vHSM operations in data flash */
   opMode = CRYPTO_30_VHSM_DATAFLASH_START;
   retVal = Csm_KeyElementSet(CsmConf_CsmKey_CsmKey_vHsm_Hardware, CRYPTO_KE_CUSTOM_VHSM_FLASH_OPERATION, &opMode, 1u);
   /* Suspend vHSM operations in code flash -> send it to RAM loop */
   opMode = CRYPTO_30_VHSM_CODEFLASH_START;
   retVal |= Csm_KeyElementSet(CsmConf_CsmKey_CsmKey_vHsm_Hardware, CRYPTO_KE_CUSTOM_VHSM_FLASH_OPERATION, &opMode, 1u);

   /* Simulate DET functionality in case of any error */
   assertFblUser(retVal == E_OK, kFblSysAssertDet);
}

/***********************************************************************************************************************
 *  ApplFblPostMemDriver
 **********************************************************************************************************************/
/*! \brief        Function is called after the memory driver has finished the operation.
 *  \param[in]    device   Memory device, which is going to be used.
 *  \param[in]    function Function of the memory device, which is going to be called.
 **********************************************************************************************************************/
void ApplFblPostMemDriver( vuint8 device, vuint8 function )
{
   uint8 opMode;
   Std_ReturnType retVal;
#  if defined( V_ENABLE_USE_DUMMY_STATEMENT )
   /* Parameters not used: avoid compiler warning */
   (void)device;
   (void)function;
#  endif
   /* TODO_CUSTOMER: Adapt this example implementation to project-specific needs/requirements */
   /* Get vHSM back from RAM loop */
   opMode = CRYPTO_30_VHSM_CODEFLASH_STOP;
   retVal = Csm_KeyElementSet(CsmConf_CsmKey_CsmKey_vHsm_Hardware, CRYPTO_KE_CUSTOM_VHSM_FLASH_OPERATION, &opMode, 1u);
   /* Give vHSM access to data flash operations */
   opMode = CRYPTO_30_VHSM_DATAFLASH_STOP;
   retVal |= Csm_KeyElementSet(CsmConf_CsmKey_CsmKey_vHsm_Hardware, CRYPTO_KE_CUSTOM_VHSM_FLASH_OPERATION, &opMode, 1u);

   /* Simulate DET functionality in case of any error */
   assertFblUser(retVal == E_OK, kFblSysAssertDet);
}
# endif /* FBL_MIO_ENABLE_HOOKS */
#endif /* FBLBM_ENABLE_STANDALONE_MODE */

#define FBLBMAP_STOP_SEC_CODE
#include "MemMap.h" /* PRQA S 5087 */ /* MD_MSR_MemMap */

/***********************************************************************************************************************
 *  MISRA DEVIATIONS
 **********************************************************************************************************************/

/* Justification for module-specific MISRA deviations:

   MD_FblBmAp_0305:
      Reason:     Boot manager needs to jump to a memory location to start a target/software.
      Risk:       Unintended jump to wrong memory location.
      Prevention: No prevention possible, address is defined by the corresponding target.

   MD_FblBmAp_0306:
      Reason:     Address conversion between integer values and pointers is required to allow for hardware independent
                  configuration and address range checks.
      Risk:       The size of integer required to hold the result of a pointer cast is implementation-defined.
      Prevention: The size of the respective integer data type which holds the address value is adapted on a hardware
                  specific basis. The correctness of the respective implementation is verified by runtime tests.

   MD_FblBmAp_2741_4558:
      Reason:     Assertion macros have to be disabled in production code and are used only for development.
      Risk:       Assertion code may be enabled in production code unintentionally. If a assertion condition is unexpectedly
                  false, the code is active. A problem may occur if the Macro is additionally changed from single statement
                  to multiple statement.
      Prevention: Macro is not allowed to be changed without review. Development code is automatically disabled via
                  configuration of project state "Production".

*/

/***********************************************************************************************************************
 *  END OF FILE: BM_AP.C
 **********************************************************************************************************************/
