/*********************************************************************************************************************** * FILE DESCRIPTION * ------------------------------------------------------------------------------------------------------------------*/ /** \file * \brief Implementation of pattern/mask based non-volatile information storage * * -------------------------------------------------------------------------------------------------------------------- * 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 * -------------------------------------------------------------------------------------------------------------------- * 02.00.00 2025-03-11 virjjn FBL-9704 Initial version * 02.01.00 2025-06-19 dganesh FBL-11034 Improvements in extended presence pattern **********************************************************************************************************************/ #define FBL_NVPATTERN_SOURCE /*********************************************************************************************************************** * INCLUDES **********************************************************************************************************************/ #include "fbl_inc.h" #include "fbl_nvpattern.h" /*********************************************************************************************************************** * VERSION **********************************************************************************************************************/ #if ( FBLLIB_NVPATTERN_VERSION != 0x0201u ) || \ ( FBLLIB_NVPATTERN_RELEASE_VERSION != 0x00u ) # error "Error in fbl_nvpattern.c: Source and header file are inconsistent!" #endif #if ( FBLLIB_NVPATTERN_VERSION != _FBLLIB_NVPATTERN_VERSION ) || \ ( FBLLIB_NVPATTERN_RELEASE_VERSION != _FBLLIB_NVPATTERN_RELEASE_VERSION ) # error "Error in fbl_nvpattern.c: Source and v_ver.h are inconsistent!" #endif /*********************************************************************************************************************** * DEFINES **********************************************************************************************************************/ /* Definition of marker/mask values and their size */ #if !defined( kFblNvMarkerValue ) # define kFblNvMarkerValue {0x73u, 0x6Au, 0x29u, 0x3Eu} #endif /* kFblNvMarkerValue */ #if !defined( kFblNvMaskValue ) # define kFblNvMaskValue {0x8Cu, 0x95u, 0xD6u, 0xC1u} #endif /* kFblNvMaskValue */ #if !defined( kFblNvPatternSize ) # define kFblNvPatternSize 4u #endif /* kFblNvPatternSize */ /* Macro to calculate the page aligned size to hold a value of size len */ #define PAGE_ALIGN(len, align) (((len) + ((align) - 1u)) & ~((align) - 1u)) /* Macro to check if val is a power of two */ #define IS_POWOFTWO(val) (((val) & ~((val) - 1u)) == (val)) /* Size of write buffer with enough space to hold one marker/mask value */ #if ( FBL_MAX_SEGMENT_SIZE < kFblNvPatternSize ) # define kFblNvPatternSegmentSize PAGE_ALIGN(kFblNvPatternSize, FBL_MAX_SEGMENT_SIZE) #else # define kFblNvPatternSegmentSize FBL_MAX_SEGMENT_SIZE #endif /* Checks if tFblNvPatternId belongs to a block property or a pattern */ #define IS_VALID_PATTERN_ID(id) (((id) > kFblNvPatternId_Invalid) && ((id) < kFblNvPatternId_Separator)) #define IS_VALID_PROPERTY_ID(id) (((id) > kFblNvPatternId_Separator) && ((id) < kFblNvPatternId_Last)) /* Parameter value to skip comparison for function FblNvPatternGetPatternItemState */ #define DONT_COMPARE (vuint8*)0u /* Enable the unexpected value check by default */ #if !defined( FBL_NVPATTERN_DISABLE_CHECK_UNEXPECTEDVALUE ) # define FBL_NVPATTERN_ENABLE_CHECK_UNEXPECTEDVALUE #endif /* !FBL_NVPATTERN_DISABLE_CHECK_UNEXPECTEDVALUE && !FBL_NVPATTERN_ENABLE_CHECK_UNEXPECTEDVALUE */ /*********************************************************************************************************************** * TYPEDEFS **********************************************************************************************************************/ /** Buffer with alignment to platform requirements */ typedef struct { vuint32 alignDummy; /**< Used to force 4Byte alignment */ vuint8 data[kFblNvPatternSegmentSize]; } tFblNvPatternAlignedBuffer; /*********************************************************************************************************************** * LOCAL DATA **********************************************************************************************************************/ #define FBLNVPATTERN_START_SEC_VAR #include "MemMap.h" /* PRQA S 5087 */ /* MD_MSR_MemMap */ V_MEMRAM0 static V_MEMRAM1 tFblNvPatternAlignedBuffer V_MEMRAM2 pageBuffer; #define FBLNVPATTERN_STOP_SEC_VAR #include "MemMap.h" /* PRQA S 5087 */ /* MD_MSR_MemMap */ /*********************************************************************************************************************** * LOCAL FUNCTION PROTOTYPES **********************************************************************************************************************/ #define FBLNVPATTERN_START_SEC_CODE #include "MemMap.h" /* PRQA S 5087 */ /* MD_MSR_MemMap */ static tFblResult FblNvPatternWritePageAligned( const vuint8* pSrcBuffer, IO_PositionType address, IO_SizeType length ); static tFblNvPatternItemState FblNvPatternGetPatternItemState( IO_PositionType patternAddress, IO_SizeType length, const vuint8* compareValue ); static tFblResult FblNvPatternGetPatternBlockDescriptorByStartAddress( IO_PositionType patternStartAddress, V_MEMRAM1 tBlockDescriptor V_MEMRAM2 V_MEMRAM3 * blockDescriptor ); static IO_SizeType FblNvPatternGetPatternOffset( tFblNvPatternId patternId, V_MEMRAM1 IO_SizeType V_MEMRAM2 V_MEMRAM3 * patternLength ); /*********************************************************************************************************************** * LOCAL FUNCTIONS **********************************************************************************************************************/ /*********************************************************************************************************************** * FblNvPatternWritePageAligned **********************************************************************************************************************/ /*! \brief Writes data respecting the page size of the memory device * \pre GetBaseAddr function has been called first * \param[in] pSrcBuffer pointer to source data * \param[in] address target address * \param[in] length length of data **********************************************************************************************************************/ static tFblResult FblNvPatternWritePageAligned( const vuint8* pSrcBuffer, IO_PositionType address, IO_SizeType length ) { tFblResult result; IO_SizeType i; IO_SizeType writeGranularity; IO_SizeType actualWriteLength; IO_SizeType localLength; IO_PositionType offset; /* Initialize variables */ result = kFblOk; localLength = length; offset = 0u; while (localLength > 0u) { (void)FblRealTimeSupport(); /* Determine page aligned write length, limit to buffer length */ if (localLength > kFblNvPatternSegmentSize) { writeGranularity = kFblNvPatternSegmentSize; actualWriteLength = kFblNvPatternSegmentSize; } else { writeGranularity = PAGE_ALIGN(localLength, (IO_SizeType)MemDriver_SegmentSize); actualWriteLength = localLength; } /* Fill buffer with payload data */ for (i = 0u; i < actualWriteLength; i++) { pageBuffer.data[i] = pSrcBuffer[i + offset]; } /* Pad remaining buffer if necessary */ if (actualWriteLength < kFblNvPatternSegmentSize) { for (i = actualWriteLength; i < writeGranularity; i++) { pageBuffer.data[i] = 0u; } } /* Call MIO to write data */ if (MemDriver_RWriteSync(pageBuffer.data, writeGranularity, address + offset) != IO_E_OK) { result = kFblFailed; break; } /* Update variables */ localLength -= actualWriteLength; offset += actualWriteLength; } return result; } /*********************************************************************************************************************** * FblNvPatternGetPatternItemState **********************************************************************************************************************/ /*! \brief Reads one marker/mask and returns the state of it * \pre Global variable memSegment is set to the block where the pattern is stored * \param[in] patternAddress address of pattern item * \param[in] length the length of the pattern item to read * \param[in] compareValue pointer to expected pattern value (return ExpectedValue), 0 if no comparison is needed * \return The state of the pattern item **********************************************************************************************************************/ /* PRQA S 6010, 6030, 6080 1 */ /* MD_MSR_STPTH, MD_MSR_STCYC, MD_MSR_STMIF */ static tFblNvPatternItemState FblNvPatternGetPatternItemState( IO_PositionType patternAddress, IO_SizeType length, const vuint8* compareValue) { tFblNvPatternItemState itemState = FBL_NVPATTERN_STATE_READERROR; vuint8 memErasedValue; IO_SizeType currentReadLength; IO_SizeType localLength = length; IO_PositionType readOffset = 0u; vuint32 i; vuint32 countExpectedValue = 0u; vuint32 countErasedValue = 0u; /* Determine memory erased value of used device */ #if defined( FBL_ENABLE_MULTIPLE_MEM_DEVICES ) memErasedValue = memDrvLst[FlashBlock[memSegment].device].erasedValue; #else memErasedValue = FBL_FLASH_DELETED; #endif while (localLength > 0u) { /* Limit read length to buffer size */ if (localLength > kFblNvPatternSegmentSize) { currentReadLength = kFblNvPatternSegmentSize; } else { currentReadLength = localLength; } /* Read marker/mask */ switch (MemDriver_RReadSync(pageBuffer.data, currentReadLength, patternAddress + readOffset)) { case IO_E_OK: case IO_E_ERASED: { /* Read successful. Because some drivers don't return IO_E_ERASED, * we have to assume that memory is erased if all bytes show the erased value * and compare against the erased value later. */ itemState = FBL_NVPATTERN_STATE_ERASED; break; } default: { /* Read error */ itemState = FBL_NVPATTERN_STATE_READERROR; assertFbl(0u, kFblSysAssertParameterOutOfRange); /* PRQA S 2741, 4558 */ /* MD_FblNvPattern_Assertion */ break; } } if (itemState == FBL_NVPATTERN_STATE_ERASED) { /* Check all bytes of marker/mask */ for (i = 0u; i < currentReadLength; i++) { /* Compare one byte of pattern against the expected value/erased value */ if ((compareValue != DONT_COMPARE) && (pageBuffer.data[i] == compareValue[readOffset + i])) { countExpectedValue++; } else if (pageBuffer.data[i] == memErasedValue) { countErasedValue++; } else /* (pageBuffer.data[i] != memErasedValue) */ { /* This might happen in case of unintended writes to pattern area */ itemState = FBL_NVPATTERN_STATE_UNEXPECTEDVALUE; } /* In case of an unexpected value break out of the for loop */ if (itemState == FBL_NVPATTERN_STATE_UNEXPECTEDVALUE) { break; } } /* Check if there were expected and erased bytes included */ if ( (countErasedValue != 0u) && (countExpectedValue != 0u)) { itemState = FBL_NVPATTERN_STATE_UNEXPECTEDVALUE; } } /* Abort in case of error */ if ((itemState == FBL_NVPATTERN_STATE_UNEXPECTEDVALUE) || (itemState == FBL_NVPATTERN_STATE_READERROR)) { break; } /* Update variables */ localLength -= currentReadLength; readOffset += currentReadLength; } /* Set itemState according to the counts */ if (length == 0u) { itemState = FBL_NVPATTERN_STATE_NOMEMSEGMENT; } else if (countErasedValue == length) { itemState = FBL_NVPATTERN_STATE_ERASED; } else if (countExpectedValue == length) { itemState = FBL_NVPATTERN_STATE_EXPECTEDVALUE; } else { /* itemState already set correctly */ } return itemState; } /*********************************************************************************************************************** * FblNvPatternGetPatternBlockDescriptorByStartAddress **********************************************************************************************************************/ /*! \brief Prepares a dummy block descriptor spaning only the pattern region * \param[in] patternStartAddress Start address of pattern region * \param[out] blockDescriptor Pointer to RAM buffer in which the dummy block descriptor can be stored * \return kFblOk: block descriptor created successfully , kFblFailed: Else **********************************************************************************************************************/ static tFblResult FblNvPatternGetPatternBlockDescriptorByStartAddress( IO_PositionType patternStartAddress, V_MEMRAM1 tBlockDescriptor V_MEMRAM2 V_MEMRAM3 * blockDescriptor ) { tFblResult result = kFblFailed; IO_SizeType patternLength; IO_SizeType patternRegionLength = 0u; /* Get memory segment index */ memSegment = FblMemSegmentNrGet(patternStartAddress); /* Check if a valid memory segment in flash block table was found */ if (memSegment >= 0) { /* Get offset for last pattern/property as this offset equals size of the complete pattern region */ /* PRQA S 4342 1 */ /* MD_FblNvPattern_4342 */ patternRegionLength = FblNvPatternGetPatternOffset((tFblNvPatternId)((vuintx)kFblNvPatternId_Last - 1u), &patternLength); blockDescriptor->blockStartAddress = patternStartAddress; blockDescriptor->blockLength = patternRegionLength; result = kFblOk; } return result; } /*********************************************************************************************************************** * FblNvPatternGetPatternOffset **********************************************************************************************************************/ /*! \brief Returns the offset for a certain pattern/property * \details The returned offset is calculated from the end of the pattern region. Therefore a lower offset has * the meaning that the respective pattern is located closer to the end of the pattern region. * \pre Global variable memSegment is set to the block where the pattern region is stored * \param[in] patternId ID of pattern/property for which the offset shall be calculated * \param[out] patternOffset Pointer to RAM buffer to store the offset to the requested pattern * \param[out] pPatternLength Pointer to RAM buffer to store the actual write address of the NvPattern or property * \return Offset to the requested pattern **********************************************************************************************************************/ static IO_SizeType FblNvPatternGetPatternOffset( tFblNvPatternId patternId, V_MEMRAM1 IO_SizeType V_MEMRAM2 V_MEMRAM3 * patternLength ) { IO_SizeType patternOffset = 0u; IO_SizeType localPatternLength = 0u; vuintx i; vuintx upperBound; /* Segment size must be a power of two */ assertFbl(IS_POWOFTWO(MemDriver_SegmentSize), kFblSysAssertParameterOutOfRange); /* Adjust patternLength to write segment size of device */ localPatternLength = PAGE_ALIGN(kFblNvPatternSize, (IO_SizeType)MemDriver_SegmentSize); /* Add size of NvPatterns to offset... * Upper bound for loop is either the last NvPattern element if base address of block property has been requested * or patternId in case the requested element is a NvPattern */ upperBound = (patternId > kFblNvPatternId_Separator) ? ((vuintx)kFblNvPatternId_Separator - 1u) : (vuintx)patternId; for (i = 0u; i < upperBound; i++) { #if defined( FBL_NVPATTERN_ENABLE_MULTIPLE_VALIDATION ) patternOffset += (localPatternLength * ((IO_SizeType)fblNvPatternMultiplicity[i] * 2u)); #else patternOffset += (localPatternLength * 2u); #endif /* FBL_NVPATTERN_ENABLE_MULTIPLE_VALIDATION */ } /* ... then add sizes of block property elements */ #if defined( FBL_NVPATTERN_ENABLE_BLOCK_PROPERTIES ) /* Skip this loop (set upperBound to 0) if the requested Id is not a block property, * otherwise subtract kFblNvPatternId_Separator from pattern id to get the index into fblNvPatternElementLength */ upperBound = (patternId > kFblNvPatternId_Separator) ? ((vuintx)patternId - (vuintx)kFblNvPatternId_Separator) : 0u; for (i = 0u; i < upperBound; i++) { patternOffset += PAGE_ALIGN(fblNvBlockProperties[i].length, (IO_SizeType)MemDriver_SegmentSize); localPatternLength = PAGE_ALIGN(fblNvBlockProperties[i].length, (IO_SizeType)MemDriver_SegmentSize); } #endif /* FBL_NVPATTERN_ENABLE_BLOCK_PROPERTIES */ /* Put results into arguments */ *patternLength = localPatternLength; return patternOffset; } /*********************************************************************************************************************** * GLOBAL FUNCTIONS **********************************************************************************************************************/ /*********************************************************************************************************************** * FblNvPatternGetPatternState **********************************************************************************************************************/ /*! \brief Determines the state of one or a set of marker/mask pairs. * \details Iterates through all sub-patterns in case of multiple validation. * Returns address and length of pattern which stores the currently relevant state. * \param[in] pBlockDescriptor descriptor of the logical block which contains the NvPattern * \param[in] patternId Id of pattern to read * \param[out] pPatternAddress Pointer to RAM buffer which keeps the pattern base address * \param[out] pPatternLength Pointer to RAM buffer which keeps the actual write length of the pattern * \return The state of the (sub) pattern which holds the current state of the pattern **********************************************************************************************************************/ tFblNvPatternState FblNvPatternGetPatternState( const V_MEMRAM1 tBlockDescriptor V_MEMRAM2 V_MEMRAM3 * pBlockDescriptor, tFblNvPatternId patternId, V_MEMRAM1 IO_PositionType V_MEMRAM2 V_MEMRAM3 * pPatternAddress, V_MEMRAM1 IO_SizeType V_MEMRAM2 V_MEMRAM3 * pPatternLength ) { vuint32 multiplicity; tFblNvPatternState patternState; IO_PositionType patternAddress; vuint8 fblMarkerValue[] = kFblNvMarkerValue; /* PRQA S 3678 */ /* MD_FblNvPattern_3678_LocalVariable */ vuint8 fblMaskValue[] = kFblNvMaskValue; /* PRQA S 3678 */ /* MD_FblNvPattern_3678_LocalVariable */ /* PRQA S 2742, 2880 2 */ /* MD_FblNvPattern_Assertion */ assertFblUser(sizeof(fblMarkerValue) == kFblNvPatternSize, kFblSysAssertParameterOutOfRange); assertFblUser(sizeof(fblMaskValue) == kFblNvPatternSize, kFblSysAssertParameterOutOfRange); /* Initialize variables */ patternAddress = *pPatternAddress; patternState.markerState = FBL_NVPATTERN_STATE_NOMEMSEGMENT; patternState.maskState = FBL_NVPATTERN_STATE_NOMEMSEGMENT; memSegment = -1; /* Get Base Address of pattern if id is valid */ if (IS_VALID_PATTERN_ID(patternId)) { memSegment = FblNvPatternGetBaseAddrByBlockDescriptor(pBlockDescriptor, patternId, &patternAddress, pPatternLength); } if (memSegment >= 0) { /* Determine number of sub-patterns */ #if defined( FBL_NVPATTERN_ENABLE_MULTIPLE_VALIDATION ) multiplicity = (vuint32)fblNvPatternMultiplicity[((vuintx)patternId - 1u)]; #else multiplicity = 1u; #endif } else { /* No memory segment found, abort */ multiplicity = 0u; } /* Go through all configured sub-patterns until we have found the sub-pattern which holds the most recent state */ while (multiplicity >= 1u) { /* Poll watchdog function */ (void)FblRealTimeSupport(); /* Read marker and mask area */ patternState.markerState = FblNvPatternGetPatternItemState(patternAddress, kFblNvPatternSize, fblMarkerValue); patternState.maskState = FblNvPatternGetPatternItemState((patternAddress + *pPatternLength), kFblNvPatternSize, fblMaskValue); if ( ((patternState.markerState == FBL_NVPATTERN_STATE_EXPECTEDVALUE) && (patternState.maskState == FBL_NVPATTERN_STATE_ERASED)) || ((patternState.markerState == FBL_NVPATTERN_STATE_ERASED) && (patternState.maskState == FBL_NVPATTERN_STATE_ERASED))) { /* One pattern item is in erased state, this is the most recent state of the pattern */ break; } /* Get base address of next sub-pattern */ patternAddress += (*pPatternLength * 2u); /* Decrement number of sub-patterns to process */ multiplicity--; } /* Write current address to passed argument pointer */ *pPatternAddress = patternAddress; return patternState; } /*********************************************************************************************************************** * FblNvPatternGetPatternStateByStartAddress **********************************************************************************************************************/ /*! \brief Determines the state of one or a set of marker/mask pairs. * \details Iterates through all sub-patterns in case of multiple validation. * Returns address and length of pattern which stores the currently relevant state. * \param[in] patternStartAddress Start address of pattern region * \param[in] patternId Id of pattern to read * \param[out] pPatternAddress Pointer to RAM buffer which keeps the address of the pattern * \param[out] pPatternLength Pointer to RAM buffer which keeps the actual write length of the pattern * \return The state of the (sub) pattern which holds the current state of the pattern **********************************************************************************************************************/ tFblNvPatternState FblNvPatternGetPatternStateByStartAddress( IO_PositionType patternStartAddress, tFblNvPatternId patternId, V_MEMRAM1 IO_PositionType V_MEMRAM2 V_MEMRAM3 * patternAddress, V_MEMRAM1 IO_SizeType V_MEMRAM2 V_MEMRAM3 * patternLength ) { tBlockDescriptor dummyBlockDescriptor = { 0u }; tFblNvPatternState patternState = { 0u }; if(FblNvPatternGetPatternBlockDescriptorByStartAddress(patternStartAddress, &dummyBlockDescriptor) == kFblOk) { patternState = FblNvPatternGetPatternState(&dummyBlockDescriptor, patternId, patternAddress, patternLength); } return patternState; } /*********************************************************************************************************************** * FblNvPatternGetBaseAddr **********************************************************************************************************************/ /*! \brief Calculates base address and actual (write) length of pattern and mask * \pre LBT is present * \param[in] blockNr Logical block number * \param[in] patternId ID of the pattern which shall be checked * \param[out] pPatternAddress Pointer to RAM buffer which keeps the pattern base address * \param[out] pPatternLength Pointer to RAM buffer which keeps the actual write length of the pattern * \return memSegment of the pattern location or -1 in case of an error **********************************************************************************************************************/ vsint16 FblNvPatternGetBaseAddr( vuint8 blockNr, tFblNvPatternId patternId, V_MEMRAM1 IO_PositionType V_MEMRAM2 V_MEMRAM3 * pPatternAddress, V_MEMRAM1 IO_SizeType V_MEMRAM2 V_MEMRAM3 * pPatternLength ) { tBlockDescriptor blockDescriptor; tFblResult result; result = FblLbtGetBlockDescriptorByNr(blockNr, &blockDescriptor); if (result == kFblOk) { memSegment = FblNvPatternGetBaseAddrByBlockDescriptor(&blockDescriptor, patternId, pPatternAddress, pPatternLength); } else { /* Invalid block number passed, signal failure via return value */ memSegment = -1; } return memSegment; } /*********************************************************************************************************************** * FblNvPatternGetBaseAddrByBlockDescriptor **********************************************************************************************************************/ /*! \brief Calculates base address and actual (write) length of an NvPattern or block property element * \param[in] blockDescriptor Logical block descriptor * \param[in] patternId ID of the NvPattern or block property for which the base address is requested * \param[out] pPatternAddress Pointer to RAM buffer to store the base address * \param[out] pPatternLength Pointer to RAM buffer to store the actual write address of the NvPattern or property * \return memSegment of the pattern location or -1 in case of an error **********************************************************************************************************************/ vsint16 FblNvPatternGetBaseAddrByBlockDescriptor( const V_MEMRAM1 tBlockDescriptor V_MEMRAM2 V_MEMRAM3 * blockDescriptor, tFblNvPatternId patternId, V_MEMRAM1 IO_PositionType V_MEMRAM2 V_MEMRAM3 * patternAddress, V_MEMRAM1 IO_SizeType V_MEMRAM2 V_MEMRAM3 * patternLength ) { IO_PositionType lastBlockAddress; /* Get address of last byte in block */ lastBlockAddress = blockDescriptor->blockStartAddress + (blockDescriptor->blockLength - 1u); /* Get corresponding memory segment index */ memSegment = FblMemSegmentNrGet(lastBlockAddress); /* Check if a valid memory segment in flash block table was found */ if (memSegment >= 0) { IO_SizeType offsetLength = FblNvPatternGetPatternOffset(patternId, patternLength); /* Calculate pattern address */ *patternAddress = (lastBlockAddress - offsetLength) + 1u; /* Check for range overflow */ assertFbl(*patternAddress >= blockDescriptor->blockStartAddress, kFblSysAssertParameterOutOfRange); /* All NvPattern data must be stored in the same memSegment */ assertFbl(FblMemSegmentNrGet(*patternAddress) == memSegment, kFblSysAssertParameterOutOfRange); } else { /* No memory segment found, this is a configuration error. */ assertFbl(0u, kFblSysAssertParameterOutOfRange); /* PRQA S 2741, 4558 */ /* MD_FblNvPattern_Assertion */ } return memSegment; } /*********************************************************************************************************************** * FblNvPatternGetPatternRegionSizeByStartAddress **********************************************************************************************************************/ /*! \brief Calculates length of complete region containing NvPattern or block property elements * \param[in] patternStartAddress Start address of pattern region * \param[out] patternLength Pointer to RAM buffer to store the region size * \return kFblOk: Pattern region size calculated successfully , kFblFailed: Else **********************************************************************************************************************/ tFblResult FblNvPatternGetPatternRegionSizeByStartAddress( IO_PositionType patternStartAddress, V_MEMRAM1 IO_SizeType V_MEMRAM2 V_MEMRAM3 * patternRegionLength) { tBlockDescriptor blockDescriptor; tFblResult result = FblNvPatternGetPatternBlockDescriptorByStartAddress(patternStartAddress, &blockDescriptor); if (result == kFblOk) { *patternRegionLength = (IO_SizeType)blockDescriptor.blockLength; } return result; } /*********************************************************************************************************************** * FblNvPatternSet **********************************************************************************************************************/ /*! \brief Writes the pattern into the flash memory. * \details The location of the pattern will be taken from the logical block table * \param[in] blockDescriptor Pointer to the logical block descriptor * \param[in] patternId ID of the pattern which shall be set * \return kFblOk: pattern successfully written, kFblFailed: Error writing pattern **********************************************************************************************************************/ tFblResult FblNvPatternSet( const V_MEMRAM1 tBlockDescriptor V_MEMRAM2 V_MEMRAM3 * blockDescriptor, tFblNvPatternId patternId ) { tBlockDescriptor localBlockDescriptor; tFblResult result; result = FblLbtGetBlockDescriptorByNr(blockDescriptor->blockNr, &localBlockDescriptor); if (result == kFblOk) { result = FblNvPatternSetByBlockDescriptor(&localBlockDescriptor, patternId); } return result; } /*********************************************************************************************************************** * FblNvPatternSetByBlockDescriptor **********************************************************************************************************************/ /*! \brief Writes the pattern into the flash memory. * \details The location of the pattern will be taken from the logical block descriptor. * \param[in] blockDescriptor Pointer to the logical block descriptor * \param[in] patternId ID of the pattern which shall be set * \return kFblOk: pattern successfully written or already set, kFblFailed: Error writing pattern **********************************************************************************************************************/ tFblResult FblNvPatternSetByBlockDescriptor( const V_MEMRAM1 tBlockDescriptor V_MEMRAM2 V_MEMRAM3 * blockDescriptor, tFblNvPatternId patternId ) { IO_PositionType patternAddress; IO_SizeType patternLength; tFblResult result; tFblNvPatternState patternState; vuint8 fblMarkerValue[] = kFblNvMarkerValue; /* PRQA S 3678 */ /* MD_FblNvPattern_3678_LocalVariable */ /* PRQA S 2742, 2880 1 */ /* MD_FblNvPattern_Assertion */ assertFblUser(sizeof(fblMarkerValue) == kFblNvPatternSize, kFblSysAssertParameterOutOfRange); /* Initialize variables */ result = kFblFailed; /* Check state of pattern */ patternState = FblNvPatternGetPatternState(blockDescriptor, patternId, &patternAddress, &patternLength); /* Proceed if marker is blank */ if (patternState.markerState == FBL_NVPATTERN_STATE_ERASED) { /* Write pattern */ if (kFblOk == FblNvPatternWritePageAligned(fblMarkerValue, patternAddress, kFblNvPatternSize)) { /* Verify that pattern is valid now */ patternState = FblNvPatternGetPatternState(blockDescriptor, patternId, &patternAddress, &patternLength); if (patternState.markerState == FBL_NVPATTERN_STATE_EXPECTEDVALUE) { #if defined( FBLNVPATTERN_ENABLE_SIGN_PRESENCE_PATTERN ) result = FblNvPatternUpdateCmacByBlockDescriptor(blockDescriptor, patternId); #else result = kFblOk; #endif /* FBLNVPATTERN_ENABLE_SIGN_PRESENCE_PATTERN */ } } } else if ((patternState.markerState == FBL_NVPATTERN_STATE_EXPECTEDVALUE) && (patternState.maskState == FBL_NVPATTERN_STATE_ERASED)) { /* Pattern already has expected state */ result = kFblOk; } else { /* For the sake of completeness */ } return result; } /*********************************************************************************************************************** * FblNvPatternSetByStartAddress **********************************************************************************************************************/ /*! \brief Writes the pattern into the flash memory. * \param[in] patternStartAddress Start address of pattern region * \param[in] patternId ID of the pattern which shall be set * \return kFblOk: pattern successfully written or already set, kFblFailed: Error writing pattern **********************************************************************************************************************/ tFblResult FblNvPatternSetByStartAddress( IO_PositionType patternStartAddress, tFblNvPatternId patternId) { tBlockDescriptor dummyBlockDescriptor = { 0u }; tFblResult result = FblNvPatternGetPatternBlockDescriptorByStartAddress(patternStartAddress, &dummyBlockDescriptor); if (result == kFblOk) { result = FblNvPatternSetByBlockDescriptor(&dummyBlockDescriptor, patternId); } return result; } /*********************************************************************************************************************** * FblNvPatternClr **********************************************************************************************************************/ /*! \brief Writes the mask to invalidate the pattern * \details The location of the pattern will be taken from the logical block table * \param[in] blockDescriptor Pointer to the logical block descriptor * \param[in] patternId ID of the pattern which shall be set * \return kFblOk: Mask for invalidation successfully written, kFblFailed: Error writing invalidation mask **********************************************************************************************************************/ tFblResult FblNvPatternClr( const V_MEMRAM1 tBlockDescriptor V_MEMRAM2 V_MEMRAM3 * blockDescriptor, tFblNvPatternId patternId ) { tBlockDescriptor localBlockDescriptor; tFblResult result; result = FblLbtGetBlockDescriptorByNr(blockDescriptor->blockNr, &localBlockDescriptor); if (result == kFblOk) { result = FblNvPatternClrByBlockDescriptor(&localBlockDescriptor, patternId); } return result; } /*********************************************************************************************************************** * FblNvPatternClrByBlockDescriptor **********************************************************************************************************************/ /*! \brief Writes the mask to invalidate the pattern * \details The location of the pattern will be taken from the passed logical block descriptor * \param[in] blockDescriptor Pointer to the logical block descriptor * \param[in] patternId ID of the pattern which shall be set * \return kFblOk: Mask for invalidation successfully written, kFblFailed: Error writing invalidation mask **********************************************************************************************************************/ tFblResult FblNvPatternClrByBlockDescriptor( const V_MEMRAM1 tBlockDescriptor V_MEMRAM2 V_MEMRAM3 * blockDescriptor, tFblNvPatternId patternId ) { tFblResult result; IO_PositionType patternAddress; IO_SizeType patternLength; tFblNvPatternState patternState; vuint8 fblMaskValue[] = kFblNvMaskValue; /* PRQA S 3678 */ /* MD_FblNvPattern_3678_LocalVariable */ /* PRQA S 2742, 2880 1 */ /* MD_FblNvPattern_Assertion */ assertFblUser(sizeof(fblMaskValue) == kFblNvPatternSize, kFblSysAssertParameterOutOfRange); /* Check state of pattern */ patternState = FblNvPatternGetPatternState(blockDescriptor, patternId, &patternAddress, &patternLength); /* Only set mask if pattern is set to valid */ if ((patternState.markerState == FBL_NVPATTERN_STATE_EXPECTEDVALUE) && (patternState.maskState == FBL_NVPATTERN_STATE_ERASED)) { /* Write mask value to flash */ result = FblNvPatternWritePageAligned(fblMaskValue, (patternAddress + patternLength), kFblNvPatternSize); } else { /* Pattern is already in invalid state, do nothing. Illegal states are detected with assertions only. */ result = kFblOk; } return result; } /*********************************************************************************************************************** * FblNvPatternClrByStartAddress **********************************************************************************************************************/ /*! \brief Writes the mask to invalidate the pattern * \param[in] patternStartAddress Start address of pattern region * \param[in] patternId ID of the pattern which shall be cleared * \return kFblOk: Mask for invalidation successfully written, kFblFailed: Error writing invalidation mask **********************************************************************************************************************/ tFblResult FblNvPatternClrByStartAddress( IO_PositionType patternStartAddress, tFblNvPatternId patternId ) { tBlockDescriptor dummyBlockDescriptor = { 0u }; tFblResult result = FblNvPatternGetPatternBlockDescriptorByStartAddress(patternStartAddress, &dummyBlockDescriptor); if (result == kFblOk) { result = FblNvPatternClrByBlockDescriptor(&dummyBlockDescriptor, patternId); } return result; } /*********************************************************************************************************************** * FblNvPatternGet **********************************************************************************************************************/ /*! \brief Checks if the pattern state is 'valid' (correct pattern value is set/mask is erased) * \details The location of the pattern and mask is taken from the logical block table * \param[in] blockDescriptor Pointer to the logical block descriptor * \param[in] patternId ID of the pattern which shall be checked * \return kFblOk: Pattern is set and mask is erased, * kFblFailed: Pattern is not set or mask not erased **********************************************************************************************************************/ tFblResult FblNvPatternGet( const V_MEMRAM1 tBlockDescriptor V_MEMRAM2 V_MEMRAM3 * blockDescriptor, tFblNvPatternId patternId ) { tBlockDescriptor localBlockDescriptor; tFblResult result; result = FblLbtGetBlockDescriptorByNr(blockDescriptor->blockNr, &localBlockDescriptor); if (result == kFblOk) { result = FblNvPatternGetByBlockDescriptor(&localBlockDescriptor, patternId); } return result; } /*********************************************************************************************************************** * FblNvPatternGetByBlockDescriptor **********************************************************************************************************************/ /*! \brief Checks if the pattern state is 'valid' (correct pattern value is set/mask is erased) * \details The location of the pattern and mask is taken from the passed logical block descriptor * \param[in] blockDescriptor Pointer to the logical block descriptor * \param[in] patternId ID of the pattern which shall be checked * \return kFblOk: Pattern is set and mask is erased, * kFblFailed: Pattern is not set or mask not erased **********************************************************************************************************************/ tFblResult FblNvPatternGetByBlockDescriptor( const V_MEMRAM1 tBlockDescriptor V_MEMRAM2 V_MEMRAM3 * blockDescriptor, tFblNvPatternId patternId ) { IO_PositionType patternAddress; IO_SizeType patternLength; tFblNvPatternState patternState; tFblResult result; /* Initialize result */ result = kFblFailed; /* Check state of pattern */ patternState = FblNvPatternGetPatternState(blockDescriptor, patternId, &patternAddress, &patternLength); if ((patternState.markerState == FBL_NVPATTERN_STATE_EXPECTEDVALUE) && (patternState.maskState == FBL_NVPATTERN_STATE_ERASED)) { #if defined( FBLNVPATTERN_ENABLE_SIGN_PRESENCE_PATTERN ) result = FblNvPatternVerifyCmacByBlockDescriptor(blockDescriptor, patternId); #else result = kFblOk; #endif /* FBLNVPATTERN_ENABLE_SIGN_PRESENCE_PATTERN */ } return result; } /*********************************************************************************************************************** * FblNvPatternGetByStartAddress **********************************************************************************************************************/ /*! \brief Checks if the pattern state is 'valid' (correct pattern value is set/mask is erased) * \param[in] patternStartAddress Start address of pattern region * \param[in] patternId ID of the pattern which shall be checked * \return kFblOk: Pattern is set and mask is erased, * kFblFailed: Pattern is not set or mask not erased **********************************************************************************************************************/ tFblResult FblNvPatternGetByStartAddress( IO_PositionType patternStartAddress, tFblNvPatternId patternId ) { tBlockDescriptor dummyBlockDescriptor = { 0u }; tFblResult result = FblNvPatternGetPatternBlockDescriptorByStartAddress(patternStartAddress, &dummyBlockDescriptor); if (result == kFblOk) { result = FblNvPatternGetByBlockDescriptor(&dummyBlockDescriptor, patternId); } return result; } #if defined( FBL_NVPATTERN_ENABLE_BLOCK_PROPERTIES ) # if defined( FBLNVPATTERN_ENABLE_SIGN_PRESENCE_PATTERN ) /*********************************************************************************************************************** * FblNvPatternGetPropertyStateAndAddrByBlockDescriptor **********************************************************************************************************************/ /*! \brief Retrieve the property state and address * \details The location of the property is taken from the passed logical block descriptor * \param[in] blockDescriptor Pointer to the logical block descriptor * \param[in] propertyId Id of the property to check the erase state * \param[out] address Pointer to the property address * \param[out] state Pointer to the property state * \return kFblOk: Property state and address are read, * kFblFailed: Property state and address are not read **********************************************************************************************************************/ tFblResult FblNvPatternGetPropertyStateAndAddrByBlockDescriptor(const V_MEMRAM1 tBlockDescriptor V_MEMRAM2 V_MEMRAM3 * blockDescriptor, tFblNvPatternId propertyId, V_MEMRAM1 IO_PositionType V_MEMRAM2 V_MEMRAM3 * address, V_MEMRAM1 tFblNvPatternItemState V_MEMRAM2 V_MEMRAM3 * state) { IO_PositionType propertyAddress = 0u; IO_SizeType propertyLength; IO_SizeType actualPropertyLength; tFblResult result = kFblFailed; /* Init variables */ *state = FBL_NVPATTERN_STATE_UNEXPECTEDVALUE; *address = 0u; /* Check if requested Id is valid */ if (IS_VALID_PROPERTY_ID(propertyId)) { /* Get address of element. Length is not used. */ if (FblNvPatternGetBaseAddrByBlockDescriptor(blockDescriptor, propertyId, &propertyAddress, &propertyLength) >= 0) { /* Get the property length */ actualPropertyLength = fblNvBlockProperties[(vuintx)propertyId - (vuintx)kFblNvPatternId_Separator - 1u].length; *state = FblNvPatternGetPatternItemState(propertyAddress, actualPropertyLength, DONT_COMPARE); *address = propertyAddress; result = kFblOk; } } return result; } # endif /* FBLNVPATTERN_ENABLE_SIGN_PRESENCE_PATTERN */ /*********************************************************************************************************************** * FblNvPatternGetProperty **********************************************************************************************************************/ /*! \brief Reads value of a block property element * \details Location of the property is taken from the logical block table * \param[in] blockDescriptor Pointer to the logical block descriptor * \param[in] propertyId Id of property to read * \param[in] bufferLength Length of destination buffer * \param[out] pDestBuffer Pointer to RAM where read property value will be stored * \return kFblOk: Property successfully read, kFblFailed: Error reading property **********************************************************************************************************************/ tFblResult FblNvPatternGetProperty( const V_MEMRAM1 tBlockDescriptor V_MEMRAM2 V_MEMRAM3 * blockDescriptor, tFblNvPatternId propertyId, IO_SizeType bufferLength, vuint8* pDestBuffer ) { tBlockDescriptor localBlockDescriptor; tFblResult result; result = FblLbtGetBlockDescriptorByNr(blockDescriptor->blockNr, &localBlockDescriptor); if (result == kFblOk) { result = FblNvPatternGetPropertyByBlockDescriptor(&localBlockDescriptor, propertyId, bufferLength, pDestBuffer); } return result; } /*********************************************************************************************************************** * FblNvPatternGetPropertyByBlockDescriptor **********************************************************************************************************************/ /*! \brief Reads value of an block property element * \details The location of the block property is taken from the passed logical block descriptor * \param[in] blockDescriptor Pointer to the logical block descriptor * \param[in] propertyId Id of the property to read * \param[in] bufferLength Length of destination buffer * \param[out] pDestBuffer Pointer to RAM where the read property value will be stored * \return kFblOk: Property successfully read, kFblFailed: Error reading property **********************************************************************************************************************/ tFblResult FblNvPatternGetPropertyByBlockDescriptor( const V_MEMRAM1 tBlockDescriptor V_MEMRAM2 V_MEMRAM3 * blockDescriptor, tFblNvPatternId propertyId, IO_SizeType bufferLength, vuint8* pDestBuffer ) { IO_PositionType propertyAddress; IO_SizeType propertyLength; IO_SizeType sizeToRead = 0u; tFblNvPatternId depPattern; tFblResult result; result = kFblFailed; propertyAddress = 0u; /* Check if requested Id is valid */ if (IS_VALID_PROPERTY_ID(propertyId)) { sizeToRead = fblNvBlockProperties[(vuintx)propertyId - (vuintx)kFblNvPatternId_Separator - 1u].length; depPattern = fblNvBlockProperties[(vuintx)propertyId - (vuintx)kFblNvPatternId_Separator - 1u].dependentPattern; /* Check if buffer length is sufficient for storing requested data */ if (sizeToRead <= bufferLength) { /* If dependent pattern configured, check its validity */ if (depPattern != kFblNvPatternId_Invalid) { result = FblNvPatternGetByBlockDescriptor(blockDescriptor, depPattern); } else { result = kFblOk; } } } if (result == kFblOk) { /* Get address of property (length is not needed) */ if (FblNvPatternGetBaseAddrByBlockDescriptor(blockDescriptor, propertyId, &propertyAddress, &propertyLength) >= 0) { if (MemDriver_RReadSync(pDestBuffer, sizeToRead, propertyAddress) == IO_E_OK) { result = kFblOk; } } } return result; } /*********************************************************************************************************************** * FblNvPatternGetPropertyByStartAddress **********************************************************************************************************************/ /*! \brief Reads value of an block property element * \param[in] patternStartAddress Start address of pattern region * \param[in] propertyId Id of the property to read * \param[in] bufferLength Length of destination buffer * \param[out] pDestBuffer Pointer to RAM where the read property value will be stored * \return kFblOk: Property successfully read, kFblFailed: Error reading property **********************************************************************************************************************/ tFblResult FblNvPatternGetPropertyByStartAddress( IO_PositionType patternStartAddress, tFblNvPatternId propertyId, IO_SizeType bufferLength, vuint8 * destBuffer ) { tBlockDescriptor dummyBlockDescriptor = { 0u }; tFblResult result = FblNvPatternGetPatternBlockDescriptorByStartAddress(patternStartAddress, &dummyBlockDescriptor); if (result == kFblOk) { result = FblNvPatternGetPropertyByBlockDescriptor(&dummyBlockDescriptor, propertyId, bufferLength, destBuffer); } return result; } /*********************************************************************************************************************** * FblNvPatternSetProperty **********************************************************************************************************************/ /*! \brief Writes value of a block property * \details The location of the property is taken from the logical block table * \param[in] blockDescriptor Pointer to the logical block descriptor * \param[in] pSrcBuffer Pointer to RAM with the data to write * \param[in] propertyId Id of the block property to write * \return kFblOk: Property successfully written, kFblFailed: Error writing property **********************************************************************************************************************/ tFblResult FblNvPatternSetProperty( const V_MEMRAM1 tBlockDescriptor V_MEMRAM2 V_MEMRAM3 * blockDescriptor, const vuint8* pSrcBuffer, tFblNvPatternId propertyId ) { tBlockDescriptor localBlockDescriptor; tFblResult result; result = FblLbtGetBlockDescriptorByNr(blockDescriptor->blockNr, &localBlockDescriptor); if (result == kFblOk) { result = FblNvPatternSetPropertyByBlockDescriptor(&localBlockDescriptor, pSrcBuffer, propertyId); } return result; } /*********************************************************************************************************************** * FblNvPatternSetPropertyByBlockDescriptor **********************************************************************************************************************/ /*! \brief Writes value of a block property * \details The location of the property is taken from the passed logical block descriptor * \param[in] blockDescriptor Pointer to the logical block descriptor * \param[in] pSrcBuffer Pointer to RAM with the data to write * \param[in] propertyId Id of the property to write * \return kFblOk: Property successfully written, kFblFailed: Error writing property **********************************************************************************************************************/ tFblResult FblNvPatternSetPropertyByBlockDescriptor( const V_MEMRAM1 tBlockDescriptor V_MEMRAM2 V_MEMRAM3 * blockDescriptor, const vuint8* pSrcBuffer, tFblNvPatternId propertyId ) { IO_PositionType propertyAddress; IO_SizeType propertyLength; IO_SizeType actualPropertyLength; tFblResult result; /* Initialize variables */ result = kFblFailed; propertyAddress = 0u; /* Check if requested Id is valid */ if (IS_VALID_PROPERTY_ID(propertyId)) { /* Get address and length of element */ if (FblNvPatternGetBaseAddrByBlockDescriptor(blockDescriptor, propertyId, &propertyAddress, &propertyLength) >= 0) { /* Only write block property to memory if it has not been set before */ actualPropertyLength = fblNvBlockProperties[(vuintx)propertyId - (vuintx)kFblNvPatternId_Separator - 1u].length; if (FblNvPatternGetPatternItemState(propertyAddress, actualPropertyLength, DONT_COMPARE) == FBL_NVPATTERN_STATE_ERASED) { result = FblNvPatternWritePageAligned(pSrcBuffer, propertyAddress, actualPropertyLength); } } } return result; } /*********************************************************************************************************************** * FblNvPatternSetPropertyByStartAddress **********************************************************************************************************************/ /*! \brief Writes value of a block property * \param[in] patternStartAddress Start address of pattern region * \param[in] pSrcBuffer Pointer to RAM with the data to write * \param[in] propertyId Id of the property to write * \return kFblOk: Property successfully written, kFblFailed: Error writing property **********************************************************************************************************************/ tFblResult FblNvPatternSetPropertyByStartAddress( IO_PositionType patternStartAddress, const vuint8* srcBuffer, tFblNvPatternId propertyId ) { tBlockDescriptor dummyBlockDescriptor = { 0u }; tFblResult result = FblNvPatternGetPatternBlockDescriptorByStartAddress(patternStartAddress, &dummyBlockDescriptor); if (result == kFblOk) { result = FblNvPatternSetPropertyByBlockDescriptor(&dummyBlockDescriptor, srcBuffer, propertyId); } return result; } # if defined( FBLNVPATTERN_ENABLE_SIGN_PRESENCE_PATTERN ) /*********************************************************************************************************************** * FblNvPatternSignedPresencePatternInit **********************************************************************************************************************/ /*! \brief Init the AES key and update the CMAC for all valid logical block during the first startup of ECU **********************************************************************************************************************/ void FblNvPatternSignedPresencePatternInit(void) { ApplFblNvPatternSignedPresencePatternInit(); } /*********************************************************************************************************************** * FblNvPatternUpdateCmacByBlockDescriptor **********************************************************************************************************************/ /*! \brief Calculate the CMAC for the received patternId and update it in the respective property * \details The address of the property will be fetched from the logical block descriptor * \param[in] blockDescriptor Pointer to the logical block descriptor * \param[in] patternId Id of the pattern for which the CMAC needs to be calculated and written * \return kFblOk: CMAC updated * kFblFailed: CMAC not updated **********************************************************************************************************************/ tFblResult FblNvPatternUpdateCmacByBlockDescriptor(const V_MEMRAM1 tBlockDescriptor V_MEMRAM2 V_MEMRAM3 * blockDescriptor, tFblNvPatternId patternId) { tFblResult result = kFblFailed; IO_PositionType propertyAddress = 0u; tFblNvPatternItemState propertyState; vuint8 signatureBuffer[FBL_NVPATTERN_PP_CMAC_SIZE]; if (fblNvPatternProperties[patternId] != kFblNvPatternId_Invalid) { assertFblUser(fblNvBlockProperties[(vuintx)fblNvPatternProperties[patternId] - (vuintx)kFblNvPatternId_Separator - 1u].dependentPattern == kFblNvPatternId_Invalid, kFblSysAssertParameterOutOfRange); if (FblNvPatternGetPropertyStateAndAddrByBlockDescriptor(blockDescriptor, fblNvPatternProperties[patternId], &propertyAddress, &propertyState) == kFblOk) { if (propertyState == FBL_NVPATTERN_STATE_ERASED) { if (ApplFblNvPatternGenerateCMAC(fblNvPatternProperties[patternId], blockDescriptor, signatureBuffer) == kFblOk) { result = FblNvPatternSetPropertyByBlockDescriptor(blockDescriptor, signatureBuffer, fblNvPatternProperties[patternId]); } } } } else { result = kFblOk; } return result; } /*********************************************************************************************************************** * FblNvPatternVerifyCmacByBlockDescriptor **********************************************************************************************************************/ /*! \brief Verify the CMAC for the received patternId * \details The address of the property will be fetched from the logical block descriptor * \param[in] blockDescriptor Pointer to the logical block descriptor * \param[in] patternId Id of the pattern for which the CMAC needs to be verified * \return kFblOk: CMAC verified successfully * kFblFailed: CMAC not verified or verification failed **********************************************************************************************************************/ tFblResult FblNvPatternVerifyCmacByBlockDescriptor(const V_MEMRAM1 tBlockDescriptor V_MEMRAM2 V_MEMRAM3 * blockDescriptor, tFblNvPatternId patternId) { vuint8 signatureBuffer[FBL_NVPATTERN_PP_CMAC_SIZE]; IO_PositionType propertyAddress = 0u; IO_SizeType actualPropertyLength; tFblNvPatternItemState propertyState; tFblResult result = kFblFailed; if (fblNvPatternProperties[patternId] != kFblNvPatternId_Invalid) { assertFblUser(fblNvBlockProperties[(vuintx)fblNvPatternProperties[patternId] - (vuintx)kFblNvPatternId_Separator - 1u].dependentPattern == kFblNvPatternId_Invalid, kFblSysAssertParameterOutOfRange); if (FblNvPatternGetPropertyStateAndAddrByBlockDescriptor(blockDescriptor, fblNvPatternProperties[patternId], &propertyAddress, &propertyState) == kFblOk) { if (propertyState != FBL_NVPATTERN_STATE_ERASED) { actualPropertyLength = fblNvBlockProperties[(vuintx)fblNvPatternProperties[patternId] - (vuintx)kFblNvPatternId_Separator - 1u].length; if (MemDriver_RReadSync(signatureBuffer, actualPropertyLength, propertyAddress) == IO_E_OK) { result = ApplFblNvPatternVerifyCMAC(fblNvPatternProperties[patternId], blockDescriptor, signatureBuffer); } } } } else { result = kFblOk; } return result; } # endif /* FBLNVPATTERN_ENABLE_SIGN_PRESENCE_PATTERN */ #endif /* FBL_NVPATTERN_ENABLE_BLOCK_PROPERTIES */ #define FBLNVPATTERN_STOP_SEC_CODE #include "MemMap.h" /* PRQA S 5087 */ /* MD_MSR_MemMap */ /*********************************************************************************************************************** * ERROR CHECKS **********************************************************************************************************************/ #if (!IS_POWOFTWO(FBL_MAX_SEGMENT_SIZE)) # error "FBL_MAX_SEGMENT_SIZE must be a power of two." #endif /*********************************************************************************************************************** * MISRA DEVIATIONS **********************************************************************************************************************/ /* Justification for module-specific MISRA deviations: MD_FblNvPattern_Assertion: 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". MD_FblNvPattern_3678_LocalVariable: Reason: Local variable/array is not declared as const as some compiler/platforms have issues with that. Risk: Content of the variable/array could be modified within the function. Prevention: Code is checked for unintended write accesses by code inspection. MD_FblNvPattern_4342: Reason: An expression of essential type has been cast to an enum type. Risk: The essential type is not in range of enum type. Prevention: Code must be reviewed to ensure cast is only applied on values in valid range */ /*********************************************************************************************************************** * END OF FILE: FBL_NVPATTERN.C **********************************************************************************************************************/