Imported more library files

Not compiling currently
This commit is contained in:
2025-04-12 23:37:19 +01:00
parent 264a3462e0
commit 9d06f983af
2518 changed files with 1021900 additions and 52 deletions

View File

@@ -0,0 +1,61 @@
/***************************************************************************//**
* @file
* @brief NVM3 configuration file.
*******************************************************************************
* # License
* <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* SPDX-License-Identifier: Zlib
*
* The licensor of this software is Silicon Laboratories Inc.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
******************************************************************************/
#ifndef NVM3_CONFIG_H
#define NVM3_CONFIG_H
/***************************************************************************//**
* @addtogroup nvm3
* @{
******************************************************************************/
/*** Driver instrumentation options */
#define NVM3_TRACE_PORT_NONE 0 // Nothing is printed
#define NVM3_TRACE_PORT_PRINTF 1 // Print is available
#define NVM3_TRACE_PORT_UNITYPRINTF 2 // Unity print is available
#define NVM3_TRACE_PORT NVM3_TRACE_PORT_NONE
/*** Event level
0 Critical: Trace only critical events
1 Warning : Trace warning events and above
2 Info : Trace info events and above
*/
#define NVM3_TRACE_LEVEL_ERROR 0
#define NVM3_TRACE_LEVEL_WARNING 1
#define NVM3_TRACE_LEVEL_INFO 2
#define NVM3_TRACE_LEVEL_LOW 3
#define NVM3_TRACE_LEVEL NVM3_TRACE_LEVEL_WARNING
#define NVM3_ASSERT_ON_ERROR false
/** @} (end addtogroup nvm3) */
#endif /* NVM3_CONFIG_H */

View File

@@ -0,0 +1,104 @@
/***************************************************************************//**
* @file
* @brief NVM3 API definition (Device Specific).
*******************************************************************************
* # License
* <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* SPDX-License-Identifier: Zlib
*
* The licensor of this software is Silicon Laboratories Inc.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
******************************************************************************/
#ifndef NVM3_H
#define NVM3_H
#ifndef NVM3_HOST_BUILD
#include "em_device.h"
#endif
#include "nvm3_generic.h"
#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************************//**
* @addtogroup nvm3
* @{
******************************************************************************/
#define NVM3_MIN_FRAGMENT_COUNT (2U) ///< The minimum number of fragments
#if defined(FLASH_PAGE_SIZE)
#define NVM3_MAX_OBJECT_SIZE_X (NVM3_MAX_OBJECT_SIZE + 8) // Adjust for an object header
#define FLASH_PAGE_SIZE_X (FLASH_PAGE_SIZE - 20) // Adjust for a page header
#define NVM3_FRAGMENT_COUNT (((NVM3_MAX_OBJECT_SIZE_X - 1) / FLASH_PAGE_SIZE_X) + NVM3_MIN_FRAGMENT_COUNT)
#endif
typedef struct nvm3_ObjFrag {
uint8_t idx; // Fragment index
bool isFirstFragFound; // The object first fragment found
bool isLastFragFound; // The object last fragment found
#if defined(FLASH_PAGE_SIZE)
nvm3_ObjFragDetail_t detail[NVM3_FRAGMENT_COUNT];
#else
nvm3_ObjFragDetail_t detail[NVM3_MIN_FRAGMENT_COUNT];
#endif
} nvm3_ObjFrag_t;
typedef struct nvm3_Obj {
nvm3_ObjectKey_t key; // The object key
struct nvm3_Obj *objAdr; // The object pointer
struct nvm3_Obj *nextObjAdr; // The next object pointer
const void *srcPtr; // May be used to carry the source address of the data
size_t totalLen; // The object total length
uint8_t objType; // The object type
bool isHdrValid; // The object header is valid
bool isValid; // The object is valid
bool isFragmented; // The object is fragmented
nvm3_ObjFrag_t frag; // The object fragment information
} nvm3_Obj_t;
// Definition of NVM3 variables
/// @brief A variable used by the NVM3 functions.
extern nvm3_Obj_t nvm3_internalObjectHandleA;
/// @brief A variable used by the NVM3 functions.
extern nvm3_Obj_t nvm3_internalObjectHandleB;
/// @brief A variable used by the NVM3 functions.
extern nvm3_Obj_t nvm3_internalObjectHandleC;
/// @brief A variable used by the NVM3 functions.
extern nvm3_Obj_t nvm3_internalObjectHandleD;
#if defined(NVM3_SECURITY)
/// @brief A variable used by the NVM3 functions.
extern nvm3_Obj_t nvm3_internalObjectHandleE;
#endif
/// @brief A variable that must contain the maximum number of object fragments.
extern const uint8_t nvm3_maxFragmentCount;
/// @brief A variable containing the object handle size in bytes.
extern const size_t nvm3_objHandleSize;
#ifdef __cplusplus
}
#endif
/// @} end group nvm3 ****************************************************/
#endif /* NVM3_H */

View File

@@ -0,0 +1,71 @@
/***************************************************************************//**
* @file
* @brief NVM3 object cache
*******************************************************************************
* # License
* <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* SPDX-License-Identifier: Zlib
*
* The licensor of this software is Silicon Laboratories Inc.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
******************************************************************************/
#ifndef NVM3_CACHE_H
#define NVM3_CACHE_H
#include "nvm3_config.h"
#include "nvm3.h"
#include "nvm3_object.h"
#ifdef __cplusplus
extern "C" {
#endif
/*******************************************************************************
******************************* TYPES *************************************
******************************************************************************/
typedef bool (*nvm3_CacheScanCallback_t)(nvm3_Cache_t *h, nvm3_ObjectKey_t key, nvm3_ObjGroup_t group, nvm3_ObjPtr_t obj, void *user);
/*******************************************************************************
*************************** PROTOTYPES ************************************
******************************************************************************/
void nvm3_cacheOpen(nvm3_Cache_t *h, nvm3_CacheEntry_t *ptr, size_t count);
void nvm3_cacheClear(nvm3_Cache_t *h);
void nvm3_cacheDelete(nvm3_Cache_t *h, nvm3_ObjectKey_t key);
nvm3_ObjPtr_t nvm3_cacheGet(nvm3_Cache_t *h, nvm3_ObjectKey_t key, nvm3_ObjGroup_t *group);
void nvm3_cacheSet(nvm3_Cache_t *h, nvm3_ObjectKey_t key, nvm3_ObjPtr_t obj, nvm3_ObjGroup_t group);
void nvm3_cacheScan(nvm3_Cache_t *h, nvm3_CacheScanCallback_t cacheScanCallback, void *user);
#if defined(NVM3_OPTIMIZATION) && (NVM3_OPTIMIZATION == 1)
sl_status_t nvm3_cacheSort(nvm3_Cache_t *h);
bool nvm3_cacheUpdateEntry(nvm3_Cache_t *h, nvm3_ObjectKey_t key, nvm3_ObjPtr_t obj, nvm3_ObjGroup_t group);
sl_status_t nvm3_cacheAddEntry(nvm3_Cache_t *h, nvm3_ObjectKey_t key, nvm3_ObjPtr_t obj, nvm3_ObjGroup_t group);
sl_status_t nvm3_cacheGetIdx(nvm3_Cache_t *h, nvm3_ObjectKey_t key, size_t low, size_t high, size_t *idx);
void nvm3_cacheOrganize(nvm3_Cache_t *h, size_t idx);
#endif
#ifdef __cplusplus
}
#endif
#endif /* NVM3_CACHE_H */

View File

@@ -0,0 +1,71 @@
/***************************************************************************//**
* @file
* @brief NVM3 definition of the default data structures.
*******************************************************************************
* # License
* <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* SPDX-License-Identifier: Zlib
*
* The licensor of this software is Silicon Laboratories Inc.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
******************************************************************************/
#ifndef NVM3_DEFAULT_H
#define NVM3_DEFAULT_H
#include "nvm3_generic.h"
/***************************************************************************//**
* @addtogroup nvm3
* @{
******************************************************************************/
/***************************************************************************//**
* @addtogroup nvm3default NVM3 Default Instance
* @brief NVM3 default instance functions and handles
* @{
******************************************************************************/
extern nvm3_Handle_t *nvm3_defaultHandle; ///< The default handle.
extern nvm3_Init_t *nvm3_defaultInit; ///< Default initialization data.
/***************************************************************************//**
* @brief
* Initialize the default NVM3 instance.
* Once initialized the instance can be accessed through the NVM3 API using
* nvm3_defaultHandle as the nvm3_Handle_t handle.
*
* @return
* @ref SL_STATUS_OK on success and a NVM3 @ref sl_status_t on failure.
******************************************************************************/
sl_status_t nvm3_initDefault(void);
/***************************************************************************//**
* @brief
* Deinit the default NVM3 instance.
*
* @return
* @ref SL_STATUS_OK on success and a NVM3 @ref sl_status_t on failure.
******************************************************************************/
sl_status_t nvm3_deinitDefault(void);
/** @} (end addtogroup nvm3default) */
/** @} (end addtogroup nvm3) */
#endif /* NVM3_DEFAULT_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,249 @@
/***************************************************************************//**
* @file
* @brief NVM3 driver HAL
*******************************************************************************
* # License
* <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* SPDX-License-Identifier: Zlib
*
* The licensor of this software is Silicon Laboratories Inc.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
******************************************************************************/
#ifndef NVM3_HAL_H
#define NVM3_HAL_H
#include "sl_status.h"
#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h>
#ifdef NVM3_HOST_BUILD
#include "nvm3_hal_host.h"
#else
#include "sl_assert.h"
#include "sl_common.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************************//**
* @addtogroup nvm3
* @{
******************************************************************************/
/***************************************************************************//**
* @addtogroup nvm3hal NVM3 HAL
* @brief NVM3 Hardware Abstraction Layer
* @{
* @details
* This module provides the interface to the NVM. By having all NVM access
* functions in a separate file, it is possible to support different hardware
* by substituting the functions in this module.
*
* @note These functions are used by the NVM3 and should not be used by
* any applications.
******************************************************************************/
/******************************************************************************
****************************** MACROS **********************************
*****************************************************************************/
#define NVM3_HAL_WRITE_SIZE_32 0 ///< Only single writes are allowed
#define NVM3_HAL_WRITE_SIZE_16 1 ///< Two writes are allowed
#define NVM3_HAL_NVM_ACCESS_NONE 0 ///< No access
#define NVM3_HAL_NVM_ACCESS_RD 1 ///< Read access
#define NVM3_HAL_NVM_ACCESS_RDWR 2 ///< Read and write access
#define NVM3_HAL_NVM_ACCESS_NOP 3 ///< Ignore
/// @cond DO_NOT_INCLUDE_WITH_DOXYGEN
#define nvm3_halOpen(hal, a, b) ((hal)->open((a), (b)))
#define nvm3_halClose(hal) ((hal)->close())
#define nvm3_halGetInfo(hal, a) ((hal)->getInfo(a))
#define nvm3_halNvmAccess(hal, a) ((hal)->access(a))
#define nvm3_halReadWords(hal, a, b, c) ((hal)->readWords((a), (b), (c)))
#define nvm3_halWriteWords(hal, a, b, c) ((hal)->writeWords((a), (b), (c)))
#define nvm3_halPageErase(hal, a) ((hal)->pageErase(a))
/// @endcond
/******************************************************************************
****************************** TYPEDEFS **********************************
*****************************************************************************/
/// @brief Pointer to NVM
typedef void *nvm3_HalPtr_t;
/// @brief Device NVM capabilities
typedef struct nvm3_HalInfo {
uint16_t deviceFamilyPartNumber; ///< Device family or part number.
uint8_t writeSize; ///< Write-size: 0=32-bit, 1=16-bit.
uint8_t memoryMapped; ///< Memory-mapped: 0=not memory mapped, 1=memory mapped.
size_t pageSize; ///< The data storage page size.
uint64_t systemUnique; ///< Obsolete. Was used to support external flash.
} nvm3_HalInfo_t;
typedef uint8_t nvm3_HalNvmAccessCode_t; ///< Definition of the access data type.
/*******************************************************************************
***************************** PROTOTYPES **********************************
******************************************************************************/
/***************************************************************************//**
* @brief
* Open the NVM3 HAL for usage.
*
* @details
* This function must be run at initialization, before any other functions
* are called. It is used to call necessary startup routines before the
* hardware can be accessed.
*
* @param[in] nvmAdr
* A pointer to the destination in NVM.
*
* @param[in] nvmSize
* The total size of the NVM.
*
* @return
* The result of the open call.
* @ref SL_STATUS_OK on success or a NVM3 @ref sl_status_t on failure.
******************************************************************************/
typedef sl_status_t (*nvm3_HalOpen_t)(nvm3_HalPtr_t nvmAdr, size_t nvmSize);
/***************************************************************************//**
* @brief
* Close the NVM3 HAL for usage.
*
* @details
* This function should be called at program termination.
* Should be done before any graceful halts.
******************************************************************************/
typedef void(*nvm3_HalClose_t)(void);
/***************************************************************************//**
* @brief
* Retrieve device information.
*
* @details
* This function is used to retrieve information about the device properties,
* such as the device family, write size, whether the NVM is memory mapped or
* not, and finally the NVM page size.
*
* @param[in] info
* A pointer to a structure that will receive the device information.
******************************************************************************/
typedef sl_status_t (*nvm3_HalGetInfo_t)(nvm3_HalInfo_t *info);
/***************************************************************************//**
* @brief
* Control read and write access to the NVM.
*
* @details
* This function is used to control the access to the NVM. It can be either
* read, write, or none.
*
* @param[in] access
* The requested access.
******************************************************************************/
typedef void (*nvm3_HalNvmAccess_t)(nvm3_HalNvmAccessCode_t access);
/***************************************************************************//**
* @brief
* Erase a page in the NVM.
*
* @details
* This function is used to erase an NVM page.
*
* @param[in] nvmAdr
* A memory address pointing to the start of the page to erase.
*
* @return
* The result of the erase operation.
******************************************************************************/
typedef sl_status_t (*nvm3_HalPageErase_t)(nvm3_HalPtr_t nvmAdr);
/***************************************************************************//**
* @brief
* Read data from NVM.
*
* @details
* This function is used to read data from the NVM. It will be a
* blocking call, since the thread asking for data to be read cannot continue
* without the data.
*
* @param[in] nvmAdr
* A memory address in NVM where data will be read.
*
* @param[in] *dst
* A pointer to the destination buffer.
*
* @param[in] wordCnt
* The number of words to read.
******************************************************************************/
typedef sl_status_t (*nvm3_HalReadWords_t)(nvm3_HalPtr_t nvmAdr, void *dst, size_t wordCnt);
/***************************************************************************//**
* @brief
* Write data to the NVM.
*
* @details
* This function is used to write data to the NVM. This is a blocking
* function.
*
* @param[in] nvmAdr
* A memory address in NVM where data will be written.
*
* @param[in] *pSrc
* A pointer to the source data.
*
* @param[in] cnt
* The number of words to write.
*
* @return
* The result of the write operation.
* @ref SL_STATUS_OK on success or a NVM3 @ref sl_status_t on failure.
******************************************************************************/
typedef sl_status_t (*nvm3_HalWriteWords_t)(nvm3_HalPtr_t nvmAdr, void const *pSrc, size_t cnt);
/// @brief The HAL handle definition.
typedef struct {
nvm3_HalOpen_t open; ///< Pointer to the open function
nvm3_HalClose_t close; ///< Pointer to the close function
nvm3_HalGetInfo_t getInfo; ///< Pointer to the get-info function
nvm3_HalNvmAccess_t access; ///< Pointer to the access function
nvm3_HalPageErase_t pageErase; ///< Pointer to the page-erase function
nvm3_HalReadWords_t readWords; ///< Pointer to the read-words function
nvm3_HalWriteWords_t writeWords; ///< Pointer to the write-words function
} nvm3_HalHandle_t;
/** @} (end addtogroup nvm3hal) */
/** @} (end addtogroup nvm3) */
#ifdef __cplusplus
}
#endif
#endif /* NVM3_HAL_H */

View File

@@ -0,0 +1,68 @@
/***************************************************************************//**
* @file
* @brief NVM3 driver HAL for memory mapped FLASH
*******************************************************************************
* # License
* <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* SPDX-License-Identifier: Zlib
*
* The licensor of this software is Silicon Laboratories Inc.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
******************************************************************************/
#ifndef NVM3_HAL_FLASH_H
#define NVM3_HAL_FLASH_H
#include "nvm3_hal.h"
#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************************//**
* @addtogroup nvm3
* @{
******************************************************************************/
/***************************************************************************//**
* @addtogroup nvm3hal
* @{
* @details
* This module provides the NVM3 interface to the EFM and EFR Flash NVM.
*
* @note The features available through the handle are used by the NVM3 and
* should not be used directly by any applications.
******************************************************************************/
/*******************************************************************************
*************************** GLOBAL VARIABLES ******************************
******************************************************************************/
extern const nvm3_HalHandle_t nvm3_halFlashHandle; ///< The HAL flash handle.
/** @} (end addtogroup nvm3hal) */
/** @} (end addtogroup nvm3) */
#ifdef __cplusplus
}
#endif
#endif /* NVM3_HAL_FLASH_H */

View File

@@ -0,0 +1,93 @@
/***************************************************************************//**
* @file
* @brief NVM3 data access lock API definition
*******************************************************************************
* # License
* <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* SPDX-License-Identifier: Zlib
*
* The licensor of this software is Silicon Laboratories Inc.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
******************************************************************************/
#ifndef NVM3_LOCK_H
#define NVM3_LOCK_H
#include <stdint.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************************//**
* @addtogroup nvm3
* @{
******************************************************************************/
/***************************************************************************//**
* @addtogroup nvm3lock NVM3 Lock
* @brief NVM3 lock functions
* @{
* @details
* This module provides data protection tools for NVM3.
*
* The functions in this module are the default protection tools for NVM3.
* The application can substitute the nvm3_lockBegin and nvm3_lockEnd
* functions as long as the NVM3 functions are protected from
* being called re-entrant.
*
* @note These functions are used by the NVM3 and should not be used by
* any applications.
******************************************************************************/
/***************************************************************************//**
* @brief
* Create a mutex to lock and unlock section.
******************************************************************************/
void nvm3_lockCreateMutex(void);
/***************************************************************************//**
* @brief
* Begin a lock section.
******************************************************************************/
void nvm3_lockBegin(void);
/***************************************************************************//**
* @brief
* End a lock section.
******************************************************************************/
void nvm3_lockEnd(void);
/***************************************************************************//**
* @brief
* Disable execution from data area.
******************************************************************************/
void nvm3_lockDisableExecute(void* address, size_t size);
/** @} (end addtogroup nvm3lock) */
/** @} (end addtogroup nvm3) */
#ifdef __cplusplus
}
#endif
#endif //NVM3_LOCK_H

View File

@@ -0,0 +1,111 @@
/***************************************************************************//**
* @file
* @brief NVM3 object definition
*******************************************************************************
* # License
* <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* SPDX-License-Identifier: Zlib
*
* The licensor of this software is Silicon Laboratories Inc.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
******************************************************************************/
#ifndef NVM3_OBJECT_H
#define NVM3_OBJECT_H
#include "nvm3_hal.h"
#include "nvm3_config.h"
#include "nvm3.h"
#ifdef __cplusplus
extern "C" {
#endif
/// @cond DO_NOT_INCLUDE_WITH_DOXYGEN
#define NVM3_OBJ_SMALL_MAX_SIZE 120U // Small object is limited to 120 bytes
#define NVM3_OBJ_PTR_INVALID ((nvm3_ObjPtr_t)(-1L))
#define NVM3_OBJ_HDR_PTR_INVALID ((nvm3_ObjHdrPtr_t)(-1L))
#define NVM3_OBJ_HEADER_SIZE_LARGE (sizeof(nvm3_ObjHdrLarge_t))
#define NVM3_OBJ_HEADER_SIZE_WLARGE (sizeof(nvm3_ObjHdrLarge_t) / sizeof(uint32_t))
#define NVM3_OBJ_HEADER_SIZE_SMALL (sizeof(nvm3_ObjHdrSmall_t))
#define NVM3_OBJ_HEADER_SIZE_WSMALL (sizeof(nvm3_ObjHdrSmall_t) / sizeof(uint32_t))
#define NVM3_OBJ_HEADER_SIZE_COUNTER (NVM3_OBJ_HEADER_SIZE_LARGE)
typedef struct nvm3_ObjHeaderSmall {
uint32_t oh1;
} nvm3_ObjHdrSmall_t;
typedef struct nvm3_ObjHeaderLarge {
uint32_t oh1;
uint32_t oh2;
} nvm3_ObjHdrLarge_t;
typedef nvm3_ObjHdrSmall_t *nvm3_ObjHdrSmallPtr_t;
typedef nvm3_ObjHdrLarge_t *nvm3_ObjHdrLargePtr_t;
typedef enum {
objTypeDataLarge = 0,
objTypeCounterLarge = 1,
objTypeCounterSmall = 2,
objTypeDeleted = 3,
objTypeRes_1 = 4,
objTypeRes_2 = 5,
objTypeRes_3 = 6,
objTypeDataSmall = 7,
} nvm3_ObjType_t;
typedef enum {
objGroupUnknown,
objGroupData,
objGroupCounter,
objGroupDeleted,
} nvm3_ObjGroup_t;
typedef enum {
fragTypeNone = 0,
fragTypeFirst = 1,
fragTypeNext = 2,
fragTypeLast = 3,
} nvm3_ObjFragType_t;
typedef nvm3_Obj_t *nvm3_ObjPtr_t;
void nvm3_objInit(nvm3_ObjPtr_t obj, nvm3_ObjPtr_t objAdr);
size_t nvm3_objHdrInit(nvm3_ObjHdrLargePtr_t oh, nvm3_ObjectKey_t key, nvm3_ObjType_t objType, size_t len, bool isLarge, nvm3_ObjFragType_t fragTyp);
size_t nvm3_objHdrLen(bool isLarge);
bool nvm3_objHdrValidateSmall(nvm3_ObjHdrSmallPtr_t objHdrSmall);
bool nvm3_objHdrValidateLarge(nvm3_ObjHdrLargePtr_t objHdrLarge);
bool nvm3_objHdrGetErased(nvm3_ObjHdrSmallPtr_t objHdrSmall);
nvm3_ObjFragType_t nvm3_objHdrGetFragTyp(nvm3_ObjHdrSmallPtr_t objHdrSmall);
nvm3_ObjectKey_t nvm3_objHdrGetKey(nvm3_ObjHdrSmallPtr_t objHdrSmall);
bool nvm3_objHdrGetHdrIsLarge(nvm3_ObjHdrSmallPtr_t objHdrSmall);
size_t nvm3_objHdrGetHdrLen(nvm3_ObjHdrSmallPtr_t objHdrSmall);
size_t nvm3_objHdrGetDatLen(nvm3_ObjHdrLargePtr_t objHdrLarge);
nvm3_ObjType_t nvm3_objHdrGetType(nvm3_ObjHdrSmallPtr_t objHdrSmall);
nvm3_ObjType_t nvm3_objGroupToType(nvm3_ObjGroup_t objGroup, bool hdrIsLarge);
nvm3_ObjGroup_t nvm3_objTypeToGroup(nvm3_ObjType_t objType);
/// @endcond
#ifdef __cplusplus
}
#endif
#endif /* NVM3_OBJECT_H */

View File

@@ -0,0 +1,97 @@
/***************************************************************************//**
* @file
* @brief NVM3 page handling functions
*******************************************************************************
* # License
* <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* SPDX-License-Identifier: Zlib
*
* The licensor of this software is Silicon Laboratories Inc.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
******************************************************************************/
#ifndef NVM3_PAGE_H
#define NVM3_PAGE_H
#include "nvm3_hal.h"
#include "nvm3_object.h"
#ifdef __cplusplus
extern "C" {
#endif
/// @cond DO_NOT_INCLUDE_WITH_DOXYGEN
#define NVM3_PAGE_COUNTER_SIZE 27U // 27 bits
#define NVM3_PAGE_COUNTER_MASK ((1U << NVM3_PAGE_COUNTER_SIZE) - 1U)
#define NVM3_PAGE_BCCB_SIZE 5U // 5 bits
#define NVM3_PAGE_BCCB_MASK ((1U << NVM3_PAGE_BCCB_SIZE) - 1U)
#define NVM3_PAGE_HEADER_WORDS 5 // The number of words in the page header
#define NVM3_PAGE_HEADER_SIZE (sizeof(nvm3_PageHdr_t))
#define NVM3_PAGE_HEADER_WSIZE (sizeof(nvm3_PageHdr_t) / sizeof(uint32_t))
#define NVM3_PAGE_H1_OFFSET (0 * sizeof(uint32_t))
#define NVM3_PAGE_H2_OFFSET (1 * sizeof(uint32_t))
#define NVM3_PAGE_H3_OFFSET (2 * sizeof(uint32_t))
#define NVM3_PAGE_H4_OFFSET (3 * sizeof(uint32_t))
#define NVM3_PAGE_H5_OFFSET (4 * sizeof(uint32_t))
#define NVM3_ERASE_COUNT_INVALID 0xFFFFFFFFU
#define NVM3_PAGE_INDEX_INVALID 0xFFFFU
typedef struct nvm3_PageHdr {
uint32_t data[NVM3_PAGE_HEADER_WORDS];
} nvm3_PageHdr_t;
/// @endcond
typedef enum {
nvm3_PageStateGood,
nvm3_PageStateGoodEip,
nvm3_PageStateBad,
nvm3_PageStateInvalidErased,
nvm3_PageStateInvalidUnknown,
} nvm3_PageState_t;
#if defined(NVM3_SECURITY)
sl_status_t nvm3_pageHeaderWrite(const nvm3_HalHandle_t *hal, nvm3_HalPtr_t pageAdr, uint32_t eraseCnt, nvm3_HalInfo_t *halInfo, nvm3_SecurityType_t secType);
#else
sl_status_t nvm3_pageHeaderWrite(const nvm3_HalHandle_t *hal, nvm3_HalPtr_t pageAdr, uint32_t eraseCnt, nvm3_HalInfo_t *halInfo);
#endif
void nvm3_pageSetBad(const nvm3_HalHandle_t *hal, nvm3_HalPtr_t pageAdr);
sl_status_t nvm3_pageSetEip(const nvm3_HalHandle_t *hal, nvm3_HalPtr_t pageAdr);
uint32_t nvm3_pageGetEraseCnt(nvm3_PageHdr_t *pageHdr);
nvm3_PageState_t nvm3_pageGetState(nvm3_PageHdr_t *pageHdr);
bool nvm3_pageStateIsGood(nvm3_PageState_t pageState);
bool nvm3_pageStateIsInvalid(nvm3_PageState_t pageState);
nvm3_ObjPtr_t nvm3_pageGetFirstObj(nvm3_HalPtr_t pageAdr);
#if defined(NVM3_SECURITY)
nvm3_SecurityType_t nvm3_pageGetSecType(nvm3_PageHdr_t *pageHdr);
sl_status_t nvm3_pageErase(const nvm3_HalHandle_t *hal, nvm3_HalPtr_t pageAdr, uint32_t eraseCnt, nvm3_HalInfo_t *halInfo, nvm3_SecurityType_t secType);
#else
sl_status_t nvm3_pageErase(const nvm3_HalHandle_t *hal, nvm3_HalPtr_t pageAdr, uint32_t eraseCnt, nvm3_HalInfo_t *halInfo);
#endif
#ifdef __cplusplus
}
#endif
#endif /* NVM3_PAGE_H */

View File

@@ -0,0 +1,74 @@
/***************************************************************************//**
* @file
* @brief NVM3 trace macros
*******************************************************************************
* # License
* <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* SPDX-License-Identifier: Zlib
*
* The licensor of this software is Silicon Laboratories Inc.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
******************************************************************************/
#ifndef NVM3_TRACE_H
#define NVM3_TRACE_H
#include "nvm3_config.h"
#include <stdint.h>
#if (NVM3_TRACE_PORT == NVM3_TRACE_PORT_PRINTF)
#include <stdio.h>
#endif
#if NVM3_TRACE_PORT == NVM3_TRACE_PORT_UNITYPRINTF
#include "unity.h"
#endif
/***************************************************************************//**
* @addtogroup nvm3trace NVM3 Trace
* @brief NVM3 Trace functions
* @{
******************************************************************************/
/*** */
/// @cond DO_NOT_INCLUDE_WITH_DOXYGEN
// Temporary solution, shoud use NVM3_TRACE_LEVEL as well
#define NVM3_TRACE_ENABLED (NVM3_TRACE_PORT != NVM3_TRACE_PORT_NONE)
#ifdef NVM3_HOST_BUILD
#define UnityPrintf(...) nvm3_tracePrint(NVM3_TRACE_LEVEL, __VA_ARGS__)
#define UNITY_PRINT_EOL() nvm3_tracePrint(NVM3_TRACE_LEVEL, "\n")
#define TEST_PRINTF UnityPrintf
#define TEST_MESSAGE UnityPrintf
#define UNITY_OUTPUT_CHAR UnityPrintf
#endif
#if (NVM3_TRACE_PORT == NVM3_TRACE_PORT_PRINTF)
#define nvm3_tracePrint(lev, ...) do { if (lev <= NVM3_TRACE_LEVEL) { printf(__VA_ARGS__); } } while (0)
#elif (NVM3_TRACE_PORT == NVM3_TRACE_PORT_UNITYPRINTF)
#define nvm3_tracePrint(lev, ...) do { if (lev <= NVM3_TRACE_LEVEL) { UnityPrintf(__VA_ARGS__); } } while (0)
#else
#define nvm3_tracePrint(lev, ...)
#endif
/// @endcond
/** @} (end addtogroup nvm3trace) */
#endif /* NVM3_TRACE_H */

View File

@@ -0,0 +1,68 @@
/***************************************************************************//**
* @file
* @brief NVM3 utility functions
*******************************************************************************
* # License
* <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* SPDX-License-Identifier: Zlib
*
* The licensor of this software is Silicon Laboratories Inc.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
******************************************************************************/
#ifndef NVM3_UTILS_H
#define NVM3_UTILS_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/// @cond DO_NOT_INCLUDE_WITH_DOXYGEN
/***************************************************************************//**
* @brief
* This function calculates the Berger Code of the supplied input variable.
* The Berger Code is calculated by looking at the binary value of the variable
* and counting the number of binary zeros.
*
* @param[in, out] pResult
* A pointer to a variable that will accumulate the berger code for
* the input variable specified in the next two variables.
*
* @param[in] pInput
* A pointer to the variable that contains data that is used.
*
* @param[in] numberOfBits
* The number of bits in the input variable used in the calculation.
* The calculation is starting from the least significant bit in the input
* variable.
******************************************************************************/
void nvm3_utilsComputeBergerCode(uint8_t *pResult, void *pInput, uint8_t numberOfBits);
/// @endcond
#ifdef __cplusplus
}
#endif
#endif /* NVM3_UTILS_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,672 @@
/***************************************************************************//**
* @file
* @brief NVM3 object cache
*******************************************************************************
* # License
* <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* SPDX-License-Identifier: Zlib
*
* The licensor of this software is Silicon Laboratories Inc.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
******************************************************************************/
#include "nvm3_cache.h"
#include "nvm3_trace.h"
#if defined(__ICCARM__)
#define SPEED_OPT _Pragma("optimize=speed")
#elif defined(__GNUC__) && defined(__CORTEX_M)
#define SPEED_OPT _Pragma("GCC optimize(\"O3\")")
#else
#define SPEED_OPT
#endif
#define TRACE_LEVEL NVM3_TRACE_LEVEL_LOW
#if defined(NVM3_OPTIMIZATION) && (NVM3_OPTIMIZATION == 1)
#include "sl_memory_manager.h"
#endif
//****************************************************************************
// isValid is implemented as a macro as this significantly improves
// speed when using compiler settings that do not inline these functions.
#define isValid(h, idx) (h->entryPtr[idx].key != NVM3_KEY_INVALID)
#if defined(NVM3_OPTIMIZATION) && (NVM3_OPTIMIZATION == 1)
uint32_t *L;
uint32_t *H;
uint32_t *P1;
uint32_t *P2;
uint32_t *K1;
uint32_t *K2;
#endif
static inline nvm3_ObjectKey_t entryGetKey(nvm3_Cache_t *h, size_t idx)
{
uint32_t tmp = (uint32_t)h->entryPtr[idx].key;
return (nvm3_ObjectKey_t)(tmp & NVM3_KEY_MASK);
}
static inline nvm3_ObjGroup_t entryGetGroup(nvm3_Cache_t *h, size_t idx)
{
uint32_t tmp = (uint32_t)h->entryPtr[idx].key;
return (nvm3_ObjGroup_t)(tmp >> NVM3_KEY_SIZE);
}
static inline nvm3_ObjPtr_t entryGetPtr(nvm3_Cache_t *h, size_t idx)
{
return h->entryPtr[idx].ptr;
}
static inline void entrySetKey(nvm3_Cache_t *h, size_t idx, nvm3_ObjectKey_t key)
{
uint32_t tmp = (uint32_t)h->entryPtr[idx].key;
tmp &= ~NVM3_KEY_MASK;
tmp |= key;
h->entryPtr[idx].key = (nvm3_ObjectKey_t)tmp;
}
static inline void entrySetGroup(nvm3_Cache_t *h, size_t idx, nvm3_ObjGroup_t group)
{
uint32_t tmp = (uint32_t)h->entryPtr[idx].key;
tmp &= NVM3_KEY_MASK;
tmp |= (group << NVM3_KEY_SIZE);
h->entryPtr[idx].key = (nvm3_ObjectKey_t)tmp;
}
static inline void entrySetPtr(nvm3_Cache_t *h, size_t idx, nvm3_ObjPtr_t obj)
{
h->entryPtr[idx].ptr = obj;
}
static inline void setInvalid(nvm3_Cache_t *h, size_t idx)
{
h->entryPtr[idx].key = NVM3_KEY_INVALID;
h->entryPtr[idx].ptr = NVM3_OBJ_PTR_INVALID;
}
//****************************************************************************
void nvm3_cacheOpen(nvm3_Cache_t *h, nvm3_CacheEntry_t *ptr, size_t count)
{
h->entryPtr = ptr;
h->entryCount = count;
nvm3_cacheClear(h);
}
void nvm3_cacheClear(nvm3_Cache_t *h)
{
nvm3_tracePrint(TRACE_LEVEL, " nvm3_cacheClear.\n");
for (size_t idx = 0; idx < h->entryCount; idx++) {
setInvalid(h, idx);
}
h->overflow = false;
#if defined(NVM3_OPTIMIZATION) && (NVM3_OPTIMIZATION == 1)
h->usedCount = 0U;
#endif
}
#if defined(NVM3_OPTIMIZATION) && (NVM3_OPTIMIZATION == 1)
/******************************************************************************************************//**
* Find index of the key in cache using binary search.
*
* @param[in] h A pointer to NVM3 cache data.
*
* @param[in] key A 20-bit object identifier.
*
* @param[out] idx A pointer to the location where key idx will be placed.
*
* @return Returns SL_STATUS_OK on success or SL_STATUS_NOT_FOUND on failure.
*********************************************************************************************************/
static sl_status_t cacheSearch(nvm3_Cache_t *h, nvm3_ObjectKey_t key, size_t *idx)
{
if (h->usedCount <= 0U) {
return SL_STATUS_NOT_FOUND;
}
size_t low = 0U;
size_t high = h->usedCount - 1;
size_t mid = 0U;
while (low <= high) {
mid = (low + high) / 2;
if (entryGetKey(h, mid) == key) {
*idx = mid;
return SL_STATUS_OK;
}
if (entryGetKey(h, mid) < key) {
low = mid + 1;
} else {
if (mid != 0U) {
high = mid - 1;
} else {
return SL_STATUS_NOT_FOUND;
}
}
}
return SL_STATUS_NOT_FOUND;
}
/******************************************************************************************************//**
* Merge two cache subarrays. Merges the two haves arr[low..mid] and arr[mid+1..high] of cache subarrays.
*
* @param[in] h A pointer to NVM3 cache data.
*
* @param[in] low Left index of cache subarray.
*
* @param[in] mid Mid index of cache subarray.
*
* @param[in] high Right index of cache subarray.
*
* @return Returns SL_STATUS_OK on success or SL_STATUS_ALLOCATION_FAILED on failure.
*********************************************************************************************************/
static sl_status_t cacheMerge(nvm3_Cache_t *h, uint32_t low, uint32_t mid, uint32_t high)
{
sl_status_t status = SL_STATUS_OK;
if ((low > mid) || (mid >= high)) {
return SL_STATUS_INVALID_PARAMETER;
}
uint32_t i, j, k;
uint32_t a1 = mid - low + 1;
uint32_t a2 = high - mid;
if ((L != NULL) && (H != NULL) && (P1 != NULL) && (P2 != NULL) && (K1 != NULL) && (K2 != NULL)) {
// Copy cache key and pointer data into subarrays
for (i = 0; i < a1; i++) {
L[i] = entryGetKey(h, low + i);
P1[i] = (uint32_t)h->entryPtr[low + i].ptr;
K1[i] = h->entryPtr[low + i].key;
}
for (j = 0; j < a2; j++) {
H[j] = entryGetKey(h, mid + 1 + j);
P2[j] = (uint32_t)h->entryPtr[mid + 1 + j].ptr;
K2[j] = h->entryPtr[mid + 1 + j].key;
}
// Index of first, second and merged subarrays
i = 0;
j = 0;
k = low;
// Merge cache subarrays
while (i < a1 && j < a2) {
if (L[i] <= H[j]) {
h->entryPtr[k].key = K1[i];
h->entryPtr[k].ptr = (uint32_t*)P1[i];
i++;
} else {
h->entryPtr[k].key = K2[j];
h->entryPtr[k].ptr = (uint32_t*)P2[j];
j++;
}
k++;
}
// Copy remaining cache elements of L subarray
while (i < a1) {
h->entryPtr[k].key = K1[i];
h->entryPtr[k].ptr = (uint32_t*)P1[i];
i++;
k++;
}
// Copy remaining cache elements of H subarray
while (j < a2) {
h->entryPtr[k].key = K2[j];
h->entryPtr[k].ptr = (uint32_t*)P2[j];
j++;
k++;
}
} else {
status = SL_STATUS_ALLOCATION_FAILED;
}
return status;
}
/******************************************************************************************************//**
* Sort cache entries using merge sort.
*
* @param[in] h A pointer to NVM3 cache data.
*
* @return Returns SL_STATUS_OK on success or SL_STATUS_ALLOCATION_FAILED on failure.
*********************************************************************************************************/
sl_status_t nvm3_cacheSort(nvm3_Cache_t *h)
{
sl_status_t status = SL_STATUS_OK;
uint32_t cacheSize = h->usedCount; // size of cache array
uint32_t currSize; // current size of subarray
uint32_t leftStart; // starting index of left subarray
// Allocate memory for cache subarrays
L = sl_malloc(cacheSize * sizeof(uint32_t));
H = sl_malloc(cacheSize * sizeof(uint32_t));
P1 = sl_malloc(cacheSize * sizeof(uint32_t));
P2 = sl_malloc(cacheSize * sizeof(uint32_t));
K1 = sl_malloc(cacheSize * sizeof(uint32_t));
K2 = sl_malloc(cacheSize * sizeof(uint32_t));
// Merge cache subarrays using bottom up approach.
for (currSize = 1; currSize <= cacheSize - 1; currSize = (currSize * 2U)) {
// Pick starting point of different subarrays of current size
for (leftStart = 0; leftStart < cacheSize - 1; leftStart += (currSize * 2U)) {
// Find ending point of left subarray. mid+1 is starting point of right
uint32_t mid = SL_MIN(leftStart + currSize - 1, cacheSize - 1);
uint32_t rightEnd = SL_MIN(leftStart + (2U * currSize - 1), cacheSize - 1);
// Merge cache subarrays arr[leftStart...mid] & arr[mid+1...rightEnd]
status = cacheMerge(h, leftStart, mid, rightEnd);
}
}
sl_free(L);
sl_free(H);
sl_free(K1);
sl_free(P1);
sl_free(K2);
sl_free(P2);
return status;
}
/******************************************************************************************************//**
* Update existing cache entry.
*
* @param[in] h A pointer to NVM3 cache data.
*
* @param[in] key A 20-bit object identifier.
*
* @param[in] obj A pointer to object struct.
*
* @param[in] group Object group.
*
* @return Returns true on success or false on failure.
*********************************************************************************************************/
bool nvm3_cacheUpdateEntry(nvm3_Cache_t *h, nvm3_ObjectKey_t key, nvm3_ObjPtr_t obj, nvm3_ObjGroup_t group)
{
size_t idx = 0;
bool res = false;
if ((h->usedCount > 0U) && (h->usedCount <= h->entryCount)) {
if (cacheSearch(h, key, &idx) == SL_STATUS_OK) {
if (isValid(h, idx)) {
entrySetGroup(h, idx, group);
entrySetPtr(h, idx, obj);
res = true;
}
}
}
nvm3_tracePrint(TRACE_LEVEL, " nvm3_cacheUpdateEntry, key=%5u, grp=%u, obj=%p, idx=%u.\n", key, group, obj, idx);
return res;
}
/******************************************************************************************************//**
* Add new cache entry
*
* @param[in] h A pointer to NVM3 cache data.
*
* @param[in] key A 20-bit object identifier.
*
* @param[in] obj A pointer to object struct.
*
* @param[in] group Object type.
*
* @return Returns SL_STATUS_OK on success or SL_STATUS_ALLOCATION_FAILED on failure.
*********************************************************************************************************/
sl_status_t nvm3_cacheAddEntry(nvm3_Cache_t *h, nvm3_ObjectKey_t key, nvm3_ObjPtr_t obj, nvm3_ObjGroup_t group)
{
sl_status_t status = SL_STATUS_OK;
bool cacheSet = false;
if (h->usedCount < h->entryCount) {
size_t idx = 0;
if (h->usedCount > 0U) {
if (nvm3_cacheGetIdx(h, key, 0U, h->usedCount - 1, &idx) == SL_STATUS_OK) {
nvm3_cacheOrganize(h, idx);
}
}
setInvalid(h, idx);
entrySetKey(h, idx, key);
entrySetGroup(h, idx, group);
entrySetPtr(h, idx, obj);
cacheSet = true;
h->usedCount++;
nvm3_tracePrint(TRACE_LEVEL, " nvm3_cacheAddEntry(1), key=%5u, grp=%u, obj=%p, idx=%u.\n", key, group, obj, idx);
}
// Prioritize data over deleted objects, force an overwrite if possible
if ((!cacheSet) && (group != objGroupDeleted)) {
for (size_t idx1 = 0; idx1 < h->entryCount; idx1++) {
nvm3_ObjGroup_t cacheGroup = entryGetGroup(h, idx1);
if (cacheGroup == objGroupDeleted) {
entrySetKey(h, idx1, key);
entrySetGroup(h, idx1, group);
entrySetPtr(h, idx1, obj);
cacheSet = true;
if (h->usedCount > 1U) {
status = nvm3_cacheSort(h);
}
nvm3_tracePrint(TRACE_LEVEL, " nvm3_cacheAddEntry(2), cache overflow for key=%u, grp=%u, obj=%p, inserted at idx=%u.\n", key, group, obj, idx1);
break;
}
}
}
if (!cacheSet) {
h->overflow = true;
nvm3_tracePrint(TRACE_LEVEL, " nvm3_cacheAddEntry(3), cache overflow for key=%u, grp=%u, obj=%p.\n", key, group, obj);
}
return status;
}
/******************************************************************************************************//**
* Get cache idx to add new entry
*
* @param[in] h A pointer to NVM3 cache data.
*
* @param[in] key A 20-bit object identifier.
*
* @param[in] low Left index of cache subarray.
*
* @param[in] high Right index of cache subarray.
*
* @param[out] idx A pointer to the location where key idx will be placed.
*
* @return Returns SL_STATUS_OK on success or SL_STATUS_NOT_FOUND on failure.
*********************************************************************************************************/
sl_status_t nvm3_cacheGetIdx(nvm3_Cache_t *h, nvm3_ObjectKey_t key, size_t low, size_t high, size_t *idx)
{
if (high <= low) {
*idx = (key > entryGetKey(h, low)) ? (low + 1) : low;
return SL_STATUS_OK;
}
if (key > entryGetKey(h, high)) {
*idx = high + 1;
return SL_STATUS_OK;
}
if (key < entryGetKey(h, low)) {
*idx = low;
return SL_STATUS_OK;
}
size_t mid = (low + high) / 2;
if (key == entryGetKey(h, mid)) {
*idx = mid + 1;
return SL_STATUS_OK;
}
if (key > entryGetKey(h, mid)) {
return nvm3_cacheGetIdx(h, key, mid + 1, high, idx);
}
if (mid != 0U) {
return nvm3_cacheGetIdx(h, key, low, mid - 1, idx);
} else {
return SL_STATUS_NOT_FOUND;
}
}
/******************************************************************************************************//**
* Arrange cache entries
*
* @param[in] h A pointer to NVM3 cache data.
*
* @param[in] idx Index of the key to arrange the cache entries.
*
*********************************************************************************************************/
void nvm3_cacheOrganize(nvm3_Cache_t *h, size_t idx)
{
size_t lastIdx = h->usedCount - 1;
// Move all cache entries from idx to end
for (; (lastIdx >= idx) && (lastIdx != 0); lastIdx--) {
h->entryPtr[lastIdx + 1].key = h->entryPtr[lastIdx].key;
h->entryPtr[lastIdx + 1].ptr = h->entryPtr[lastIdx].ptr;
}
if ((lastIdx == 0) && (idx == 0)) {
h->entryPtr[lastIdx + 1].key = h->entryPtr[lastIdx].key;
h->entryPtr[lastIdx + 1].ptr = h->entryPtr[lastIdx].ptr;
}
}
#endif
#if defined(NVM3_OPTIMIZATION) && (NVM3_OPTIMIZATION == 1)
void nvm3_cacheDelete(nvm3_Cache_t *h, nvm3_ObjectKey_t key)
{
bool found = false;
size_t idx = 0;
if ((h->usedCount > 0U) && (h->usedCount <= h->entryCount)) {
if (cacheSearch(h, key, &idx) == SL_STATUS_OK) {
if (isValid(h, idx)) {
if (entryGetKey(h, idx) == key) {
setInvalid(h, idx);
found = true;
size_t lastIdx = h->usedCount - 1;
// Arrange cache entries after cache obj deletion
for (; idx < lastIdx; idx++) {
h->entryPtr[idx].key = h->entryPtr[idx + 1].key;
h->entryPtr[idx].ptr = h->entryPtr[idx + 1].ptr;
}
if (h->usedCount > 0) {
h->usedCount--;
}
}
}
}
}
nvm3_tracePrint(TRACE_LEVEL, " nvm3_cacheDelete, key=%u, found=%d.\n", key, found ? 1 : 0);
(void)found;
}
#else
void nvm3_cacheDelete(nvm3_Cache_t *h, nvm3_ObjectKey_t key)
{
bool found = false;
for (size_t idx = 0; idx < h->entryCount; idx++) {
if (isValid(h, idx)) {
if (entryGetKey(h, idx) == key) {
setInvalid(h, idx);
found = true;
break;
}
}
}
nvm3_tracePrint(TRACE_LEVEL, " nvm3_cacheDelete, key=%u, found=%d.\n", key, found ? 1 : 0);
(void)found;
}
#endif
#if defined(NVM3_OPTIMIZATION) && (NVM3_OPTIMIZATION == 1)
nvm3_ObjPtr_t nvm3_cacheGet(nvm3_Cache_t *h, nvm3_ObjectKey_t key, nvm3_ObjGroup_t *group)
{
nvm3_ObjPtr_t obj = NVM3_OBJ_PTR_INVALID;
#if NVM3_TRACE_PORT
int tmp = -1;
#endif
size_t idx = 0;
if ((h->usedCount > 0U) && (h->usedCount <= h->entryCount)) {
if (cacheSearch(h, key, &idx) == SL_STATUS_OK) {
if (isValid(h, idx)) {
*group = entryGetGroup(h, idx);
obj = entryGetPtr(h, idx);
#if NVM3_TRACE_PORT
tmp = (int)idx;
#endif
}
}
}
nvm3_tracePrint(TRACE_LEVEL, " nvm3_cacheGet, key=%5u, grp=%d, obj=%p, idx=%d.\n", key, (obj != NVM3_OBJ_PTR_INVALID) ? *group : -1, obj, tmp);
return obj;
}
#else
nvm3_ObjPtr_t nvm3_cacheGet(nvm3_Cache_t *h, nvm3_ObjectKey_t key, nvm3_ObjGroup_t *group)
{
nvm3_ObjPtr_t obj = NVM3_OBJ_PTR_INVALID;
#if NVM3_TRACE_PORT
int tmp = -1;
#endif
for (size_t idx = 0; idx < h->entryCount; idx++) {
if (isValid(h, idx)) {
if (entryGetKey(h, idx) == key) {
*group = entryGetGroup(h, idx);
obj = entryGetPtr(h, idx);
#if NVM3_TRACE_PORT
tmp = (int)idx;
#endif
break;
}
}
}
nvm3_tracePrint(TRACE_LEVEL, " nvm3_cacheGet, key=%5u, grp=%d, obj=%p, idx=%d.\n", key, (obj != NVM3_OBJ_PTR_INVALID) ? *group : -1, obj, tmp);
return obj;
}
#endif
#if defined(NVM3_OPTIMIZATION) && (NVM3_OPTIMIZATION == 1)
SPEED_OPT
void nvm3_cacheSet(nvm3_Cache_t *h, nvm3_ObjectKey_t key, nvm3_ObjPtr_t obj, nvm3_ObjGroup_t group)
{
bool bSet = false;
// Update existing entry
size_t idx = 0;
if ((h->usedCount > 0U) && (h->usedCount <= h->entryCount)) {
for (idx = 0; idx < h->usedCount; idx++) {
if (isValid(h, idx)) {
if (entryGetKey(h, idx) == key) {
entrySetGroup(h, idx, group);
entrySetPtr(h, idx, obj);
nvm3_tracePrint(TRACE_LEVEL, " nvm3_cacheSet(1), key=%5u, grp=%u, obj=%p, idx=%u.\n", key, group, obj, idx);
return;
}
}
}
}
// Add new Entry
if (h->usedCount < h->entryCount) {
idx = h->usedCount;
if (!isValid(h, idx)) {
entrySetKey(h, idx, key);
entrySetGroup(h, idx, group);
entrySetPtr(h, idx, obj);
bSet = true;
h->usedCount++;
nvm3_tracePrint(TRACE_LEVEL, " nvm3_cacheSet(2), key=%5u, grp=%u, obj=%p, idx=%u.\n", key, group, obj, idx);
}
}
// Full, prioritize data over deleted objects, force an overwrite if possible
if ((!bSet) && (group != objGroupDeleted)) {
for (size_t idx1 = 0; idx1 < h->entryCount; idx1++) {
nvm3_ObjGroup_t cacheGroup = entryGetGroup(h, idx1);
if (cacheGroup == objGroupDeleted) {
entrySetKey(h, idx1, key);
entrySetGroup(h, idx1, group);
entrySetPtr(h, idx1, obj);
bSet = true;
nvm3_tracePrint(TRACE_LEVEL, " nvm3_cacheSet(3), cache overflow for key=%u, grp=%u, obj=%p, inserted at idx=%u.\n", key, group, obj, idx1);
break;
}
}
}
if (!bSet) {
h->overflow = true;
nvm3_tracePrint(TRACE_LEVEL, " nvm3_cacheSet(4), cache overflow for key=%u, grp=%u, obj=%p.\n", key, group, obj);
}
}
#else
SPEED_OPT
void nvm3_cacheSet(nvm3_Cache_t *h, nvm3_ObjectKey_t key, nvm3_ObjPtr_t obj, nvm3_ObjGroup_t group)
{
bool bSet = false;
// Update existing entry
for (size_t idx = 0; idx < h->entryCount; idx++) {
if (isValid(h, idx)) {
if (entryGetKey(h, idx) == key) {
entrySetGroup(h, idx, group);
entrySetPtr(h, idx, obj);
nvm3_tracePrint(TRACE_LEVEL, " nvm3_cacheSet(1), key=%5u, grp=%u, obj=%p, idx=%u.\n", key, group, obj, idx);
return;
}
}
}
// Add new Entry
for (size_t idx = 0; idx < h->entryCount; idx++) {
if (!isValid(h, idx)) {
entrySetKey(h, idx, key);
entrySetGroup(h, idx, group);
entrySetPtr(h, idx, obj);
bSet = true;
nvm3_tracePrint(TRACE_LEVEL, " nvm3_cacheSet(2), key=%5u, grp=%u, obj=%p, idx=%u.\n", key, group, obj, idx);
break;
}
}
// Full, prioritize data over deleted objects, force an overwrite if possible
if ((!bSet) && (group != objGroupDeleted)) {
for (size_t idx = 0; idx < h->entryCount; idx++) {
nvm3_ObjGroup_t cacheGroup = entryGetGroup(h, idx);
if (cacheGroup == objGroupDeleted) {
entrySetKey(h, idx, key);
entrySetGroup(h, idx, group);
entrySetPtr(h, idx, obj);
bSet = true;
nvm3_tracePrint(TRACE_LEVEL, " nvm3_cacheSet(3), cache overflow for key=%u, grp=%u, obj=%p, inserted at idx=%u.\n", key, group, obj, idx);
break;
}
}
}
if (!bSet) {
h->overflow = true;
nvm3_tracePrint(TRACE_LEVEL, " nvm3_cacheSet(4), cache overflow for key=%u, grp=%u, obj=%p.\n", key, group, obj);
}
}
#endif
void nvm3_cacheScan(nvm3_Cache_t *h, nvm3_CacheScanCallback_t cacheScanCallback, void *user)
{
bool keepGoing;
for (size_t idx = 0; idx < h->entryCount; idx++) {
if (isValid(h, idx)) {
// Found an object.
nvm3_ObjectKey_t key = entryGetKey(h, idx);
nvm3_ObjGroup_t group = entryGetGroup(h, idx);
nvm3_ObjPtr_t obj = entryGetPtr(h, idx);
keepGoing = cacheScanCallback(h, key, group, obj, user);
if (!keepGoing) {
return;
}
}
}
}

View File

@@ -0,0 +1,100 @@
/***************************************************************************//**
* @file
* @brief NVM3 definition of the default data structures.
*******************************************************************************
* # License
* <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* SPDX-License-Identifier: Zlib
*
* The licensor of this software is Silicon Laboratories Inc.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
******************************************************************************/
#include "nvm3.h"
#include "nvm3_hal_flash.h"
#include "nvm3_default_config.h"
#if defined(NVM3_SECURITY)
#include "nvm3_hal_crypto_handle.h"
#endif
#if defined(NVM3_BASE)
/* Manually control the NVM3 address and size */
#elif defined (__ICCARM__)
__root __no_init uint8_t nvm3_default_storage[NVM3_DEFAULT_NVM_SIZE] @ "SIMEE";
#define NVM3_BASE (nvm3_default_storage)
#elif defined (__GNUC__)
extern char linker_nvm_begin;
__attribute__((used)) uint8_t nvm3_default_storage[NVM3_DEFAULT_NVM_SIZE] __attribute__ ((section(".simee")));
#define NVM3_BASE (&linker_nvm_begin)
#else
#error "Unsupported toolchain"
#endif
nvm3_Handle_t nvm3_defaultHandleData;
nvm3_Handle_t *nvm3_defaultHandle = &nvm3_defaultHandleData;
#if (NVM3_DEFAULT_CACHE_SIZE != 0)
static nvm3_CacheEntry_t defaultCache[NVM3_DEFAULT_CACHE_SIZE];
#endif
// Compile time checks for NVM3 max object size macros
#if NVM3_DEFAULT_MAX_OBJECT_SIZE > NVM3_MAX_OBJECT_SIZE_HIGH_LIMIT
#error "NVM3_DEFAULT_MAX_OBJECT_SIZE is greater than max value supported"
#elif NVM3_DEFAULT_MAX_OBJECT_SIZE < NVM3_MAX_OBJECT_SIZE_LOW_LIMIT
#error "NVM3_DEFAULT_MAX_OBJECT_SIZE is less than min value supported"
#endif
nvm3_Init_t nvm3_defaultInitData =
{
(nvm3_HalPtr_t)NVM3_BASE,
NVM3_DEFAULT_NVM_SIZE,
#if (NVM3_DEFAULT_CACHE_SIZE != 0)
defaultCache,
#else
NULL,
#endif
NVM3_DEFAULT_CACHE_SIZE,
NVM3_DEFAULT_MAX_OBJECT_SIZE,
NVM3_DEFAULT_REPACK_HEADROOM,
&nvm3_halFlashHandle,
#if defined(NVM3_SECURITY)
&nvm3_halCryptoHandle,
NVM3_DEFAULT_SECURITY_TYPE,
#endif
};
nvm3_Init_t *nvm3_defaultInit = &nvm3_defaultInitData;
sl_status_t nvm3_initDefault(void)
{
return nvm3_open(nvm3_defaultHandle, nvm3_defaultInit);
}
sl_status_t nvm3_deinitDefault(void)
{
return nvm3_close(nvm3_defaultHandle);
}

View File

@@ -0,0 +1,231 @@
/***************************************************************************//**
* @file
* @brief Non-Volatile Memory Wear-Leveling driver HAL implementation
*******************************************************************************
* # License
* <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* SPDX-License-Identifier: Zlib
*
* The licensor of this software is Silicon Laboratories Inc.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
******************************************************************************/
#include <stdbool.h>
#include <string.h>
#include "nvm3.h"
#include "nvm3_hal_flash.h"
#include "em_system.h"
#include "em_msc.h"
/***************************************************************************//**
* @addtogroup nvm3
* @{
******************************************************************************/
/***************************************************************************//**
* @addtogroup nvm3hal
* @{
******************************************************************************/
/******************************************************************************
****************************** MACROS **********************************
*****************************************************************************/
#define CHECK_DATA 1 ///< Macro defining if data should be checked
/******************************************************************************
*************************** LOCAL VARIABLES ******************************
*****************************************************************************/
/******************************************************************************
*************************** LOCAL FUNCTIONS ******************************
*****************************************************************************/
/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
/***************************************************************************//**
* @brief
* Convert return type.
*
* @details
* This function converts between the return type of the emlib and the
* NVM3 API.
*
* @param[in] result
* Operation result.
*
* @return
* Returns remapped status code.
******************************************************************************/
static sl_status_t convertMscStatusToNvm3Status(MSC_Status_TypeDef result)
{
sl_status_t ret;
switch (result) {
case mscReturnOk:
ret = SL_STATUS_OK;
break;
case mscReturnInvalidAddr:
ret = SL_STATUS_NVM3_INVALID_ADDR;
break;
default:
ret = SL_STATUS_NVM3_EMULATOR;
break;
}
return ret;
}
// Check if the page is erased.
static bool isErased(void *adr, size_t len)
{
size_t i;
size_t cnt;
uint32_t *dat = adr;
cnt = len / sizeof(uint32_t);
for (i = 0U; i < cnt; i++) {
if (*dat != 0xFFFFFFFFUL) {
return false;
}
dat++;
}
return true;
}
/** @endcond */
static sl_status_t nvm3_halFlashOpen(nvm3_HalPtr_t nvmAdr, size_t flashSize)
{
(void)nvmAdr;
(void)flashSize;
MSC_Init();
return SL_STATUS_OK;
}
static void nvm3_halFlashClose(void)
{
MSC_Deinit();
}
static sl_status_t nvm3_halFlashGetInfo(nvm3_HalInfo_t *halInfo)
{
SYSTEM_ChipRevision_TypeDef chipRev;
SYSTEM_ChipRevisionGet(&chipRev);
#if defined(_SYSCFG_CHIPREV_PARTNUMBER_MASK)
halInfo->deviceFamilyPartNumber = chipRev.partNumber;
#else
halInfo->deviceFamilyPartNumber = chipRev.family;
#endif
halInfo->memoryMapped = 1;
#if defined(_SILICON_LABS_32B_SERIES_2)
halInfo->writeSize = NVM3_HAL_WRITE_SIZE_32;
#else
halInfo->writeSize = NVM3_HAL_WRITE_SIZE_16;
#endif
halInfo->pageSize = SYSTEM_GetFlashPageSize();
return SL_STATUS_OK;
}
static void nvm3_halFlashAccess(nvm3_HalNvmAccessCode_t access)
{
(void)access;
}
static sl_status_t nvm3_halFlashReadWords(nvm3_HalPtr_t nvmAdr, void *dst, size_t wordCnt)
{
uint32_t *pSrc = (uint32_t *)nvmAdr;
uint32_t *pDst = dst;
if ((((size_t)pSrc % 4) == 0) && (((size_t)pDst % 4) == 0)) {
while (wordCnt > 0U) {
*pDst++ = *pSrc++;
wordCnt--;
}
} else {
(void)memcpy(dst, nvmAdr, wordCnt * sizeof(uint32_t));
}
return SL_STATUS_OK;
}
static sl_status_t nvm3_halFlashWriteWords(nvm3_HalPtr_t nvmAdr, void const *src, size_t wordCnt)
{
const uint32_t *pSrc = src;
uint32_t *pDst = (uint32_t *)nvmAdr;
MSC_Status_TypeDef mscSta;
sl_status_t halSta;
size_t byteCnt;
byteCnt = wordCnt * sizeof(uint32_t);
mscSta = MSC_WriteWord(pDst, pSrc, byteCnt);
halSta = convertMscStatusToNvm3Status(mscSta);
#if CHECK_DATA
if (halSta == SL_STATUS_OK) {
if (memcmp(pDst, pSrc, byteCnt) != 0) {
halSta = SL_STATUS_FLASH_PROGRAM_FAILED;
}
}
#endif
return halSta;
}
static sl_status_t nvm3_halFlashPageErase(nvm3_HalPtr_t nvmAdr)
{
MSC_Status_TypeDef mscSta;
sl_status_t halSta;
mscSta = MSC_ErasePage((uint32_t *)nvmAdr);
halSta = convertMscStatusToNvm3Status(mscSta);
#if CHECK_DATA
if (halSta == SL_STATUS_OK) {
if (!isErased(nvmAdr, SYSTEM_GetFlashPageSize())) {
halSta = SL_STATUS_FLASH_ERASE_FAILED;
}
}
#endif
return halSta;
}
/*******************************************************************************
*************************** GLOBAL VARIABLES ******************************
******************************************************************************/
const nvm3_HalHandle_t nvm3_halFlashHandle = {
.open = nvm3_halFlashOpen, ///< Set the open function
.close = nvm3_halFlashClose, ///< Set the close function
.getInfo = nvm3_halFlashGetInfo, ///< Set the get-info function
.access = nvm3_halFlashAccess, ///< Set the access function
.pageErase = nvm3_halFlashPageErase, ///< Set the page-erase function
.readWords = nvm3_halFlashReadWords, ///< Set the read-words function
.writeWords = nvm3_halFlashWriteWords, ///< Set the write-words function
};
/** @} (end addtogroup nvm3hal) */
/** @} (end addtogroup nvm3) */

View File

@@ -0,0 +1,207 @@
/***************************************************************************//**
* @file
* @brief NVM3 data access lock API implementation
*******************************************************************************
* # License
* <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* SPDX-License-Identifier: Zlib
*
* The licensor of this software is Silicon Laboratories Inc.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
******************************************************************************/
#include "nvm3_lock.h"
#include "nvm3.h"
#ifdef NVM3_HOST_BUILD
#include "nvm3_config.h"
#include "nvm3_trace.h"
#include "nvm3_hal.h"
#else
#include "sl_core.h"
#endif
#if defined(SL_COMPONENT_CATALOG_PRESENT)
#include "sl_component_catalog.h"
#endif
#if defined(SL_CATALOG_MPU_PRESENT)
#include "sl_mpu.h"
#endif
#if defined(SL_CATALOG_KERNEL_PRESENT)
#include "cmsis_os2.h"
#endif
//****************************************************************************
#ifdef NVM3_HOST_BUILD
#define SL_WEAK
#endif
#ifdef NVM3_HOST_BUILD
static int lockCount = 0;
/// @cond DO_NOT_INCLUDE_WITH_DOXYGEN
#elif defined(SL_CATALOG_KERNEL_PRESENT) && !defined(_SILICON_LABS_32B_SERIES_2)
static osMutexId_t nvm3_mutex; ///< NVM3 Lock Mutex
#define NVM3_ERROR_ASSERT() do { EFM_ASSERT(false); } while (0)
#else
CORE_DECLARE_IRQ_STATE;
/// @endcond
#endif
/***************************************************************************//**
* @addtogroup nvm3
* @{
******************************************************************************/
/// @cond DO_NOT_INCLUDE_WITH_DOXYGEN
nvm3_Obj_t nvm3_internalObjectHandleA;
nvm3_Obj_t nvm3_internalObjectHandleB;
nvm3_Obj_t nvm3_internalObjectHandleC;
nvm3_Obj_t nvm3_internalObjectHandleD;
#if defined(NVM3_SECURITY)
nvm3_Obj_t nvm3_internalObjectHandleE;
#endif
const uint8_t nvm3_maxFragmentCount = NVM3_FRAGMENT_COUNT;
const size_t nvm3_objHandleSize = sizeof(nvm3_Obj_t);
/// @endcond
/***************************************************************************//**
* @addtogroup nvm3lock
* @{
******************************************************************************/
/***************************************************************************//**
* @details
* The Mutex creation for lock enable and disable.
*
* It provides options for using "mutexes" for RTOS users
* and "core_critical" APIs for bare-metal users.
*
* @note RTOS users should avoid invoking the nvm3_lock APIs from within
* critical sections, as this may result in unexpected behavior.
* Please, ensure that kernel has been initialized before this API call.
******************************************************************************/
SL_WEAK void nvm3_lockCreateMutex(void)
{
#if defined(SL_CATALOG_KERNEL_PRESENT) && !defined(_SILICON_LABS_32B_SERIES_2)
if (nvm3_mutex == NULL) {
const osMutexAttr_t mutex_attr = {
" NVM3 Mutex",
osMutexRecursive | osMutexPrioInherit,
NULL,
0
};
nvm3_mutex = osMutexNew(&mutex_attr);
if (nvm3_mutex == NULL) {
NVM3_ERROR_ASSERT();
}
}
#endif
}
/***************************************************************************//**
* @details
* The default lock-begin implementation.
* @note RTOS users should avoid invoking the nvm3_lock APIs from within
* critical sections, as this may result in unexpected behavior.
* Please, ensure that kernel has been initialized before this API call.
******************************************************************************/
SL_WEAK void nvm3_lockBegin(void)
{
#ifdef NVM3_HOST_BUILD
lockCount++;
// In apps running on micrium OS on Ser2, the app is acquiring the mutex within
// a critical section while invoking bootloader APIs
#elif defined(SL_CATALOG_KERNEL_PRESENT) && !defined(_SILICON_LABS_32B_SERIES_2)
/// @cond DO_NOT_INCLUDE_WITH_DOXYGEN
osStatus_t os_status = osError;
// Bypass the lock if kernel is not running
if (osKernelGetState() == osKernelRunning) {
if (nvm3_mutex == NULL) {
nvm3_lockCreateMutex();
}
os_status = osMutexAcquire(nvm3_mutex, osWaitForever);
if (os_status != osErrorISR && os_status != osOK) {
NVM3_ERROR_ASSERT();
}
}
#else
/// @cond DO_NOT_INCLUDE_WITH_DOXYGEN
CORE_ENTER_CRITICAL();
/// @endcond
#endif
}
/***************************************************************************//**
* @details
* The default lock-end implementation.
* @note RTOS users should avoid invoking the nvm3_lock APIs from within
* critical sections, as this may result in unexpected behavior.
* Please, ensure that kernel has been initialized before this API call.
******************************************************************************/
SL_WEAK void nvm3_lockEnd(void)
{
#ifdef NVM3_HOST_BUILD
if (lockCount == 0) {
nvm3_tracePrint(NVM3_TRACE_LEVEL_ERROR, "NVM3 ERROR - lockEnd: invalid lock count.\n");
}
lockCount--;
#elif defined(SL_CATALOG_KERNEL_PRESENT) && !defined(_SILICON_LABS_32B_SERIES_2)
osStatus_t os_status = osError;
// Bypass the lock if kernel is not running
if (osKernelGetState() == osKernelRunning) {
os_status = osMutexRelease(nvm3_mutex);
if (os_status != osErrorISR && os_status != osOK) {
NVM3_ERROR_ASSERT();
}
}
#else
CORE_EXIT_CRITICAL();
#endif
}
/***************************************************************************//**
* @details
* Disable execution from data area.
*
* @param[in] address Start of memory range
*
* @param[in] size Size of memory range.
******************************************************************************/
void nvm3_lockDisableExecute(void *address, size_t size)
{
#if defined(__MPU_PRESENT) && (__MPU_PRESENT == 1U) \
&& defined(SL_CATALOG_MPU_PRESENT) \
&& !defined(SL_TRUSTZONE_SECURE)
// The memory range used by nvm3 may not be compatible with the mpu.
// Just ignore errors.
sl_mpu_disable_execute((uint32_t)address, (uint32_t)address + size - 1, size);
#else
(void)address;
(void)size;
#endif
}
/** @} (end addtogroup nvm3lock) */
/** @} (end addtogroup nvm3) */

View File

@@ -0,0 +1,267 @@
/***************************************************************************//**
* @file
* @brief NVM3 object handling functions
*******************************************************************************
* # License
* <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* SPDX-License-Identifier: Zlib
*
* The licensor of this software is Silicon Laboratories Inc.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
******************************************************************************/
#include "nvm3_object.h"
#include "nvm3_utils.h"
#include <string.h>
#define NVM3_OBJ_LEN_SIZE 7U // 7 bits
#define NVM3_OBJ_LEN_MASK ((1U << NVM3_OBJ_LEN_SIZE) - 1U)
#define NVM3_OBJ_LLEN_SIZE 26U // 26 bits: large obj length
#define NVM3_OBJ_LLEN_MASK ((1U << NVM3_OBJ_LLEN_SIZE) - 1U)
#define NVM3_OBJ_BCCB_SIZE 5U // 5 bits: small obj berger code
#define NVM3_OBJ_BCCB_MASK ((1U << NVM3_OBJ_BCCB_SIZE) - 1U)
#define NVM3_OBJ_LBCCB_SIZE 6U // 6 bits: large obj berger code
#define NVM3_OBJ_LBCCB_MASK ((1U << NVM3_OBJ_LBCCB_SIZE) - 1U)
#define NVM3_OBJ_F_SIZE 2U // 2 bits: fragment field
#define NVM3_OBJ_F_MASK ((1U << NVM3_OBJ_F_SIZE) - 1U)
#define NVM3_OBJ_U_SIZE 3U // 3 bits: unused field
#define NVM3_OBJ_U_MASK ((1U << NVM3_OBJ_U_SIZE) - 1U)
#define NVM3_OBJ_KEY_OFFSET (NVM3_OBJ_LEN_SIZE)
#define NVM3_OBJ_F_OFFSET (NVM3_OBJ_LEN_SIZE + NVM3_KEY_SIZE)
#define NVM3_OBJ_U_OFFSET (NVM3_OBJ_LEN_SIZE + NVM3_KEY_SIZE + NVM3_OBJ_F_SIZE)
#define NVM3_OBJ_BCCB_OFFSET (NVM3_OBJ_LEN_SIZE + NVM3_KEY_SIZE)
#define NVM3_OBJ_LBCCB_OFFSET (NVM3_OBJ_LLEN_SIZE)
//****************************************************************************
__STATIC_INLINE uint32_t hdrSmallGetBergerCode(nvm3_ObjHdrSmall_t *oh)
{
return (((oh)->oh1 >> NVM3_OBJ_BCCB_OFFSET) & NVM3_OBJ_BCCB_MASK);
}
__STATIC_INLINE uint32_t hdrLargeGetBergerCode(nvm3_ObjHdrLarge_t *oh)
{
return (((oh)->oh2 >> NVM3_OBJ_LBCCB_OFFSET) & NVM3_OBJ_LBCCB_MASK);
}
__STATIC_INLINE nvm3_ObjType_t toObjType(uint32_t value)
{
int type = (int)value;
return (nvm3_ObjType_t)type;
}
__STATIC_INLINE nvm3_ObjFragType_t toObjFragType(uint32_t value)
{
int type = (int)value;
return (nvm3_ObjFragType_t)type;
}
__STATIC_INLINE nvm3_ObjType_t hdrGetType(nvm3_ObjHdrSmall_t *oh)
{
return toObjType(oh->oh1 & NVM3_OBJ_LEN_MASK);
}
__STATIC_INLINE bool hdrIsLarge(nvm3_ObjHdrSmall_t *oh)
{
nvm3_ObjType_t objTyp = hdrGetType(oh);
return ((objTyp == objTypeCounterLarge) || (objTyp == objTypeDataLarge));
}
//****************************************************************************
/*** Initialize object header */
size_t nvm3_objHdrInit(nvm3_ObjHdrLargePtr_t oh, nvm3_ObjectKey_t key, nvm3_ObjType_t objType,
size_t len, bool isLarge, nvm3_ObjFragType_t fragTyp)
{
uint8_t BCCB = 0;
oh->oh1 = (key & NVM3_KEY_MASK) << NVM3_OBJ_KEY_OFFSET;
oh->oh2 = (len & NVM3_OBJ_LLEN_MASK);
switch (objType) {
case objTypeCounterLarge:
/* Intented fall-through */
case objTypeDataLarge:
oh->oh1 |= (uint32_t)objType;
oh->oh1 |= ((uint32_t)NVM3_OBJ_U_MASK << NVM3_OBJ_U_OFFSET);
oh->oh1 |= ((uint32_t)fragTyp & NVM3_OBJ_F_MASK) << NVM3_OBJ_F_OFFSET;
break;
case objTypeCounterSmall:
/* Intented fall-through*/
case objTypeDeleted:
oh->oh1 |= (uint32_t)objType;
break;
default:
oh->oh1 |= ((len + (uint32_t)objTypeDataSmall) & NVM3_OBJ_LEN_MASK);
break;
}
if (isLarge) {
nvm3_utilsComputeBergerCode(&BCCB, &oh->oh1, 32);
nvm3_utilsComputeBergerCode(&BCCB, &oh->oh2, NVM3_OBJ_LLEN_SIZE);
oh->oh2 |= ((uint32_t)BCCB & NVM3_OBJ_LBCCB_MASK) << NVM3_OBJ_LBCCB_OFFSET;
} else {
nvm3_utilsComputeBergerCode(&BCCB, &oh->oh1, (uint8_t)(NVM3_OBJ_LEN_SIZE + NVM3_KEY_SIZE));
oh->oh1 |= ((uint32_t)BCCB & NVM3_OBJ_BCCB_MASK) << NVM3_OBJ_BCCB_OFFSET;
}
return nvm3_objHdrLen(isLarge);
}
size_t nvm3_objHdrLen(bool isLarge)
{
return isLarge ? NVM3_OBJ_HEADER_SIZE_LARGE : NVM3_OBJ_HEADER_SIZE_SMALL;
}
bool nvm3_objHdrValidateSmall(nvm3_ObjHdrSmallPtr_t objHdrSmall)
{
uint8_t codReq = 0;
uint8_t codAct;
bool res = false;
nvm3_utilsComputeBergerCode(&codReq, &objHdrSmall->oh1, (uint8_t)(NVM3_OBJ_LEN_SIZE + NVM3_KEY_SIZE));
codAct = (uint8_t)hdrSmallGetBergerCode(objHdrSmall);
if (codReq == codAct) {
res = true;
}
return res;
}
bool nvm3_objHdrValidateLarge(nvm3_ObjHdrLargePtr_t objHdrLarge)
{
uint8_t codReq = 0;
uint8_t codAct;
bool res = false;
nvm3_utilsComputeBergerCode(&codReq, &objHdrLarge->oh1, 32);
nvm3_utilsComputeBergerCode(&codReq, &objHdrLarge->oh2, NVM3_OBJ_LLEN_SIZE);
codAct = (uint8_t)hdrLargeGetBergerCode(objHdrLarge);
if (codReq == codAct) {
res = true;
}
return res;
}
bool nvm3_objHdrGetErased(nvm3_ObjHdrSmallPtr_t objHdrSmall)
{
return objHdrSmall->oh1 == 0xFFFFFFFFU;
}
nvm3_ObjFragType_t nvm3_objHdrGetFragTyp(nvm3_ObjHdrSmallPtr_t objHdrSmall)
{
nvm3_ObjFragType_t fragTyp = toObjFragType((objHdrSmall->oh1 >> NVM3_OBJ_F_OFFSET) & NVM3_OBJ_F_MASK);
return hdrIsLarge(objHdrSmall) ? fragTyp : fragTypeNone;
}
nvm3_ObjectKey_t nvm3_objHdrGetKey(nvm3_ObjHdrSmallPtr_t objHdrSmall)
{
return (nvm3_ObjectKey_t)((objHdrSmall->oh1 >> NVM3_OBJ_KEY_OFFSET) & NVM3_KEY_MASK);
}
bool nvm3_objHdrGetHdrIsLarge(nvm3_ObjHdrSmallPtr_t objHdrSmall)
{
return hdrIsLarge(objHdrSmall);
}
size_t nvm3_objHdrGetHdrLen(nvm3_ObjHdrSmallPtr_t objHdrSmall)
{
return nvm3_objHdrLen(hdrIsLarge(objHdrSmall));
}
size_t nvm3_objHdrGetDatLen(nvm3_ObjHdrLargePtr_t objHdrLarge)
{
size_t len;
if (hdrIsLarge((nvm3_ObjHdrSmallPtr_t)objHdrLarge)) {
len = objHdrLarge->oh2 & NVM3_OBJ_LLEN_MASK;
} else {
len = objHdrLarge->oh1 & NVM3_OBJ_LEN_MASK;
len = (len > (size_t)objTypeDataSmall) ? (len - (size_t)objTypeDataSmall) : 0U;
}
return len;
}
nvm3_ObjType_t nvm3_objHdrGetType(nvm3_ObjHdrSmallPtr_t objHdrSmall)
{
return hdrGetType(objHdrSmall);
}
void nvm3_objInit(nvm3_ObjPtr_t obj, nvm3_ObjPtr_t objAdr)
{
// The sizeof(nvm3_Obj_t) is dependent on the page size.
(void)memset(obj, 0, nvm3_objHandleSize);
obj->key = NVM3_KEY_INVALID;
obj->objAdr = objAdr;
obj->isValid = false;
obj->totalLen = 0;
obj->nextObjAdr = NVM3_OBJ_PTR_INVALID;
obj->isFragmented = false;
obj->frag.isFirstFragFound = false;
obj->frag.isLastFragFound = false;
obj->frag.idx = 0;
}
nvm3_ObjType_t nvm3_objGroupToType(nvm3_ObjGroup_t objGroup, bool hdrIsLarge)
{
nvm3_ObjType_t objType;
if (objGroup == objGroupDeleted) {
objType = objTypeDeleted;
} else if (objGroup == objGroupCounter) {
objType = hdrIsLarge ? objTypeCounterLarge : objTypeCounterSmall;
} else {
objType = hdrIsLarge ? objTypeDataLarge : objTypeDataSmall;
}
return objType;
}
nvm3_ObjGroup_t nvm3_objTypeToGroup(nvm3_ObjType_t objType)
{
nvm3_ObjGroup_t objGroup;
switch (objType) {
case objTypeCounterSmall:
objGroup = objGroupCounter;
break;
case objTypeCounterLarge:
objGroup = objGroupCounter;
break;
case objTypeDataLarge:
objGroup = objGroupData;
break;
case objTypeRes_1:
case objTypeRes_2:
case objTypeRes_3:
objGroup = objGroupUnknown;
break;
case objTypeDeleted:
objGroup = objGroupDeleted;
break;
default:
objGroup = objGroupData;
break;
}
return objGroup;
}

View File

@@ -0,0 +1,375 @@
/***************************************************************************//**
* @file
* @brief NVM3 page handling functions
*******************************************************************************
* # License
* <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* SPDX-License-Identifier: Zlib
*
* The licensor of this software is Silicon Laboratories Inc.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
******************************************************************************/
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#include "nvm3_page.h"
#include "nvm3_object.h"
#include "nvm3_utils.h"
#include "nvm3_trace.h"
/** @cond DO_NOT_INCLUDE_WITH_DOXYGEN */
//============================================================================
#define H1_MAGIC_SHIFT 16 // The magic shift
#define H1_MAGIC_V1 0xB29AU // The magic marker
#define H1_VERSION_V1 0x01U // The first version of NVM3
#define H4_BAD_MASK 0xffff0000U // The BAD mask
#define H4_BAD_SHIFT 16 // The BAD shift
#define H4_BAD_GOOD 0xFFFFU // The page is good
#define H4_BAD_NOTGOOD 0x0000U // The page is not good
#define H4_EIP_MASK 0xffffU // The EIP mask
#define H4_EIP_SET 0xA5A5U // The page is scheduled for erase
#define H4_EIP_CLEAR 0xFFFFU // The page is not sceduled for erase
#define H5_DEVICE_FAMILY_MASK 0x07FFU
#define H5_WRITESIZE_SHIFT 11
#define H5_WRITESIZE_MASK 0x0800U
#define H5_MEMORYMAPPED_SHIFT 12
#define H5_MEMORYMAPPED_MASK 0x1000U
#define H5_PAGESIZE_SHIFT 13
#define H5_PAGESIZE_MASK 0xE000U
#define H5_DEVINFO_MASK (H5_DEVICE_FAMILY_MASK | H5_WRITESIZE_MASK | H5_MEMORYMAPPED_MASK | H5_PAGESIZE_MASK)
#if defined(NVM3_SECURITY)
#define H5_SECTYPE_AEAD_SHIFT 16 // The AEAD shift
#define H5_SECTYPE_AEAD_MASK 0x10000U // The AEAD mask
#define H5_SECTYPE_ENC_SHIFT 17 // The encryption shift
#define H5_SECTYPE_ENC_MASK 0x20000U // The encryption mask
#endif
//============================================================================
typedef enum {
eraseCntNormal,
eraseCntInverted
} EraseCnt_t;
//============================================================================
__STATIC_INLINE bool pageHdrErased(nvm3_PageHdr_t *pageHdr)
{
return (pageHdr->data[0] == 0xFFFFFFFFU);
}
__STATIC_INLINE bool pageHdrMagicAndVersion(nvm3_PageHdr_t *pageHdr)
{
uint16_t magic, version;
magic = (uint16_t)(pageHdr->data[0] >> H1_MAGIC_SHIFT);
version = (uint16_t)pageHdr->data[0];
return (magic == H1_MAGIC_V1) && (version == H1_VERSION_V1);
}
__STATIC_INLINE bool pageHdrIsPageBad(nvm3_PageHdr_t *pageHdr)
{
uint32_t badPage = (pageHdr->data[3] & H4_BAD_MASK) >> H4_BAD_SHIFT;
return badPage != H4_BAD_GOOD;
}
__STATIC_INLINE bool pageHdrIsEraseInProgress(nvm3_PageHdr_t *pageHdr)
{
uint16_t EIP = (pageHdr->data[3]);
return EIP != H4_EIP_CLEAR;
}
__STATIC_INLINE uint32_t pageHdrGetCounterBcod(uint32_t h)
{
return (h >> NVM3_PAGE_COUNTER_SIZE) & NVM3_PAGE_BCCB_MASK;
}
__STATIC_INLINE uint32_t pageHdrGetCounterVal(uint32_t h, EraseCnt_t level)
{
uint32_t cnt = (level == eraseCntInverted) ? ~h : h;
return cnt & NVM3_PAGE_COUNTER_MASK;
}
__STATIC_INLINE uint32_t pageHdrCounterMake(uint32_t cnt, EraseCnt_t level)
{
uint8_t BCCB;
if (level == eraseCntInverted) {
cnt = ~cnt;
}
cnt &= NVM3_PAGE_COUNTER_MASK;
BCCB = 0;
nvm3_utilsComputeBergerCode(&BCCB, &cnt, NVM3_PAGE_COUNTER_SIZE);
return ((uint32_t)BCCB << NVM3_PAGE_COUNTER_SIZE) | cnt;
}
// The page size field has a value from 0 to 7 describing page sizes from 512
// to 65536 bytes. Note: The page size must be a power of 2.
static uint16_t pageSizeToField(size_t pageSize)
{
uint16_t field = 0U;
pageSize /= 512U;
for (;; ) {
pageSize /= 2U;
if (pageSize == 0U) {
break;
}
field++;
}
return field;
}
//============================================================================
#if defined(NVM3_SECURITY)
sl_status_t nvm3_pageHeaderWrite(const nvm3_HalHandle_t *hal, nvm3_HalPtr_t pageAdr, uint32_t eraseCnt, nvm3_HalInfo_t *halInfo, nvm3_SecurityType_t secType)
#else
sl_status_t nvm3_pageHeaderWrite(const nvm3_HalHandle_t *hal, nvm3_HalPtr_t pageAdr, uint32_t eraseCnt, nvm3_HalInfo_t *halInfo)
#endif
{
nvm3_PageHdr_t pageHdr;
uint32_t devInfo;
uint32_t formatInfo;
size_t ofs;
nvm3_HalPtr_t adr;
sl_status_t staWrite;
sl_status_t sta = SL_STATUS_OK;
// Create header
devInfo = ((pageSizeToField(halInfo->pageSize) << H5_PAGESIZE_SHIFT) & H5_PAGESIZE_MASK)
+ (((halInfo->memoryMapped) << H5_MEMORYMAPPED_SHIFT) & H5_MEMORYMAPPED_MASK)
+ (((halInfo->writeSize) << H5_WRITESIZE_SHIFT) & H5_WRITESIZE_MASK)
+ ((halInfo->deviceFamilyPartNumber) & H5_DEVICE_FAMILY_MASK);
#if defined(NVM3_SECURITY)
formatInfo = ((secType == NVM3_SECURITY_AEAD) ? 0 : 1) + 0xFFFEU;
#else
formatInfo = 0xFFFFU;
#endif
pageHdr.data[0] = (H1_MAGIC_V1 << H1_MAGIC_SHIFT) | H1_VERSION_V1;
pageHdr.data[1] = pageHdrCounterMake(eraseCnt, eraseCntNormal);
pageHdr.data[2] = pageHdrCounterMake(eraseCnt, eraseCntInverted);
pageHdr.data[3] = 0xffffffffU;
pageHdr.data[4] = (formatInfo << 16) | (devInfo);
//printf("-> hdrWr: adr=%p, cnt=%u, 1=0x%08x, 2=0x%08x\n", pageAdr, eraseCnt, pageHdr.data[1], pageHdr.data[2]);
// Write header in the following order: H5 -> H3 -> H2 -> H1
// Write H5
ofs = 4 * sizeof(uint32_t);
adr = (nvm3_HalPtr_t)((size_t)pageAdr + ofs);
staWrite = nvm3_halWriteWords(hal, adr, &(pageHdr.data[4]), 1);
if (staWrite != SL_STATUS_OK) {
sta = staWrite;
}
// Write H4
// Do not write 0xffffffff
// Write H3
ofs = 2 * sizeof(uint32_t);
adr = (nvm3_HalPtr_t)((size_t)pageAdr + ofs);
staWrite = nvm3_halWriteWords(hal, adr, &(pageHdr.data[2]), 1);
if (staWrite != SL_STATUS_OK) {
sta = staWrite;
}
// Write H2
ofs = 1 * sizeof(uint32_t);
adr = (nvm3_HalPtr_t)((size_t)pageAdr + ofs);
staWrite = nvm3_halWriteWords(hal, adr, &(pageHdr.data[1]), 1);
if (staWrite != SL_STATUS_OK) {
sta = staWrite;
}
// Write H1
ofs = 0;
adr = (nvm3_HalPtr_t)((size_t)pageAdr + ofs);
staWrite = nvm3_halWriteWords(hal, adr, &(pageHdr.data[0]), 1);
if (staWrite != SL_STATUS_OK) {
sta = staWrite;
}
return sta;
}
/*** Mark page as bad page */
void nvm3_pageSetBad(const nvm3_HalHandle_t *hal, nvm3_HalPtr_t pageAdr)
{
uint32_t h4Rd;
uint32_t h4Wr;
nvm3_HalPtr_t adr;
nvm3_tracePrint(NVM3_TRACE_LEVEL_WARNING, "nvm3_pageSetBad, pageAdr=0x%p.\n", pageAdr);
adr = (nvm3_HalPtr_t)((size_t)pageAdr + NVM3_PAGE_H4_OFFSET);
nvm3_halReadWords(hal, adr, &h4Rd, 1);
h4Wr = h4Rd & ~H4_BAD_MASK;
h4Wr |= (H4_BAD_NOTGOOD << H4_BAD_SHIFT);
(void)nvm3_halWriteWords(hal, adr, &h4Wr, 1);
// There is no recovery from a write error at this point.
}
sl_status_t nvm3_pageSetEip(const nvm3_HalHandle_t *hal, nvm3_HalPtr_t pageAdr)
{
uint32_t h4Rd;
uint32_t h4Wr;
nvm3_HalPtr_t adr;
sl_status_t sta = SL_STATUS_OK;
nvm3_tracePrint(NVM3_TRACE_LEVEL_LOW, " nvm3_pageSetEip, pageAdr=0x%p.\n", pageAdr);
adr = (nvm3_HalPtr_t)((size_t)pageAdr + NVM3_PAGE_H4_OFFSET);
nvm3_halReadWords(hal, adr, &h4Rd, 1);
if ((h4Rd & H4_EIP_MASK) == H4_EIP_CLEAR) {
h4Wr = (h4Rd & ~H4_EIP_MASK);
h4Wr |= H4_EIP_SET;
sta = nvm3_halWriteWords(hal, adr, &h4Wr, 1);
}
return sta;
}
uint32_t nvm3_pageGetEraseCnt(nvm3_PageHdr_t *pageHdr)
{
uint8_t BCCB;
BCCB = 0;
nvm3_utilsComputeBergerCode(&BCCB, &(pageHdr->data[1]), NVM3_PAGE_COUNTER_SIZE);
if (BCCB == pageHdrGetCounterBcod(pageHdr->data[1])) {
return pageHdrGetCounterVal(pageHdr->data[1], eraseCntNormal);
}
BCCB = 0;
nvm3_utilsComputeBergerCode(&BCCB, &(pageHdr->data[2]), NVM3_PAGE_COUNTER_SIZE);
if (BCCB == pageHdrGetCounterBcod(pageHdr->data[2])) {
return pageHdrGetCounterVal(pageHdr->data[2], eraseCntInverted);
}
//printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> ERROR: getEraseCount failed!\n");
return NVM3_ERASE_COUNT_INVALID;
}
nvm3_PageState_t nvm3_pageGetState(nvm3_PageHdr_t *pageHdr)
{
nvm3_PageState_t pageState;
uint32_t eraseCnt = NVM3_ERASE_COUNT_INVALID;
bool pageHdrValid;
pageHdrValid = pageHdrMagicAndVersion(pageHdr);
if (pageHdrValid) {
eraseCnt = nvm3_pageGetEraseCnt(pageHdr);
}
if (eraseCnt != NVM3_ERASE_COUNT_INVALID) {
if (pageHdrIsPageBad(pageHdr)) {
pageState = nvm3_PageStateBad;
} else if (pageHdrIsEraseInProgress(pageHdr)) {
pageState = nvm3_PageStateGoodEip;
} else {
pageState = nvm3_PageStateGood;
}
} else {
if (pageHdrErased(pageHdr)) {
pageState = nvm3_PageStateInvalidErased;
} else {
pageState = nvm3_PageStateInvalidUnknown;
}
}
return pageState;
}
bool nvm3_pageStateIsGood(nvm3_PageState_t pageState)
{
return ((pageState == nvm3_PageStateGood) || (pageState == nvm3_PageStateGoodEip));
}
bool nvm3_pageStateIsInvalid(nvm3_PageState_t pageState)
{
return ((pageState == nvm3_PageStateInvalidErased) || (pageState == nvm3_PageStateInvalidUnknown));
}
nvm3_ObjPtr_t nvm3_pageGetFirstObj(nvm3_HalPtr_t pageAdr)
{
return (nvm3_ObjPtr_t)((size_t)pageAdr + NVM3_PAGE_HEADER_SIZE);
}
#if defined(NVM3_SECURITY)
sl_status_t nvm3_pageErase(const nvm3_HalHandle_t *hal, nvm3_HalPtr_t pageAdr, uint32_t eraseCnt, nvm3_HalInfo_t *halInfo, nvm3_SecurityType_t secType)
#else
sl_status_t nvm3_pageErase(const nvm3_HalHandle_t *hal, nvm3_HalPtr_t pageAdr, uint32_t eraseCnt, nvm3_HalInfo_t *halInfo)
#endif
{
sl_status_t sta;
nvm3_tracePrint(NVM3_TRACE_LEVEL_LOW, " nvm3_pageErase: adr=0x%p, eraseCnt=%u.\n", pageAdr, eraseCnt);
// Erase
sta = nvm3_halPageErase(hal, pageAdr);
if (sta == SL_STATUS_OK) {
// Create new page header
#if defined(NVM3_SECURITY)
sta = nvm3_pageHeaderWrite(hal, pageAdr, eraseCnt, halInfo, secType);
#else
sta = nvm3_pageHeaderWrite(hal, pageAdr, eraseCnt, halInfo);
#endif
if (sta != SL_STATUS_OK) {
nvm3_tracePrint(NVM3_TRACE_LEVEL_WARNING, " erasePage: adr=0x%p, Write hdr ERROR, mark page as BAD.\n", pageAdr);
nvm3_pageSetBad(hal, pageAdr);
}
} else {
// Erasure failed, mark page as BAD
nvm3_tracePrint(NVM3_TRACE_LEVEL_WARNING, " erasePage: adr=0x%p, Erase ERROR, page is marked as BAD.\n", pageAdr);
nvm3_pageSetBad(hal, pageAdr);
}
//nvm3_tracePrint(" erasePage: sta=%u.\n", sta);
return sta;
}
#if defined(NVM3_SECURITY)
/***************************************************************************//**
* Get NVM3 security type.
*
* @param[in] pageHdr Page header of a valid page.
*
* @return Returns NVM3 security type.
******************************************************************************/
nvm3_SecurityType_t nvm3_pageGetSecType(nvm3_PageHdr_t *pageHdr)
{
nvm3_SecurityType_t secType = NVM3_SECURITY_INVALID;
if (((pageHdr->data[4] & H5_SECTYPE_AEAD_MASK) >> H5_SECTYPE_AEAD_SHIFT) == 0) {
secType = NVM3_SECURITY_AEAD;
}
return secType;
}
#endif
/** @endcond */

View File

@@ -0,0 +1,57 @@
/***************************************************************************//**
* @file
* @brief NVM3 utility functions
*******************************************************************************
* # License
* <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
*******************************************************************************
*
* SPDX-License-Identifier: Zlib
*
* The licensor of this software is Silicon Laboratories Inc.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
******************************************************************************/
#include "nvm3_utils.h"
/// @cond DO_NOT_INCLUDE_WITH_DOXYGEN
void nvm3_utilsComputeBergerCode(uint8_t *pResult, void *pInput, uint8_t numberOfBits)
{
uint8_t sum;
uint32_t word = *((uint32_t *)pInput);
uint32_t mask;
// Clear bits that are outside the wanted bits
if (numberOfBits < 32U) {
mask = (1UL << numberOfBits) - 1U;
word = word & mask;
}
// Count bits set:
// From http://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetNaive
word = word - ((word >> 1) & 0x55555555U);
word = (word & 0x33333333U) + ((word >> 2) & 0x33333333U);
sum = (uint8_t)((((word + (word >> 4)) & 0xF0F0F0FU) * 0x1010101U) >> 24U);
// Count bit cleared and accumulate
*pResult = *pResult + (numberOfBits - sum);
}
/// @endcond