转换nv库源码为unix格式方便对比更新内容,修复uapi_nv_write 失效问题。解决write sn函数失效bug
authorSnickerSun <snickersun@163.com>
Thu, 29 Feb 2024 07:04:36 +0000 (15:04 +0800)
committerSnickerSun <snickersun@163.com>
Thu, 29 Feb 2024 07:04:36 +0000 (15:04 +0800)
24 files changed:
code/sdk/drivers/peripheral/utils/custom_utils.c
code/sdk/drivers/peripheral/utils/custom_utils_at_cmd.c
code/sdk/middleware/utils/nv/CMakeLists.txt
code/sdk/middleware/utils/nv/nv_storage_app/nv_storage.h
code/sdk/middleware/utils/nv/nv_storage_app/soc_nv_storage.c
code/sdk/middleware/utils/nv/nv_storage_app/soc_nv_storage_handle.c
code/sdk/middleware/utils/nv/nv_storage_lib/nv_debug.c
code/sdk/middleware/utils/nv/nv_storage_lib/nv_debug.h
code/sdk/middleware/utils/nv/nv_storage_lib/nv_key.c
code/sdk/middleware/utils/nv/nv_storage_lib/nv_key.h
code/sdk/middleware/utils/nv/nv_storage_lib/nv_nvregion.c
code/sdk/middleware/utils/nv/nv_storage_lib/nv_nvregion.h
code/sdk/middleware/utils/nv/nv_storage_lib/nv_page.c
code/sdk/middleware/utils/nv/nv_storage_lib/nv_page.h
code/sdk/middleware/utils/nv/nv_storage_lib/nv_reset.c
code/sdk/middleware/utils/nv/nv_storage_lib/nv_reset.h
code/sdk/middleware/utils/nv/nv_storage_lib/nv_rpc.c
code/sdk/middleware/utils/nv/nv_storage_lib/nv_rpc.h
code/sdk/middleware/utils/nv/nv_storage_lib/nv_store.h
code/sdk/middleware/utils/nv/nv_storage_lib/nv_task_adapt.h
code/sdk/middleware/utils/nv/nv_storage_lib/nv_update.c
code/sdk/middleware/utils/nv/nv_storage_lib/nv_update.h
code/sdk/middleware/utils/nv/nv_storage_lib/nv_upg.c
code/sdk/middleware/utils/nv/nv_storage_lib/nv_upg.h

index 24c6d51..cdc14f3 100644 (file)
@@ -55,25 +55,37 @@ uint32_t zh_get_sn(uint8_t *buf_sn, uint32_t *len_sn)
 
 uint32_t zh_set_sn(uint8_t *buf_sn, uint32_t len_sn)
 {
-
+    errcode_t nv_ret_value=0;
 #ifdef SUPPORT_NV
     if( buf_sn == NULL || len_sn == 0)
         return ERRCODE_FAIL;
 
+    uint8_t *test_nv_value; /* 要写入的NV value保存在test_nv_value中 */ 
+
+    uint16_t key_len=  sizeof(custom_key_sn_t); 
+    uint8_t *write_value = malloc(key_len); 
+    custom_key_sn_t *p_sn = (custom_key_sn_t*)write_value;
     uint16_t len = 0;
-    custom_key_sn_t sn = {0};
-    if (len_sn > sizeof(sn.sn))
+    if (len_sn > sizeof(p_sn->sn))
     {
-        len = sizeof(sn.sn);
+        len = sizeof(p_sn->sn);
     }else{
         len = len_sn;
     }
-    sn.size = len;
-    memcpy_s(sn.sn,sizeof(sn.sn),buf_sn,len);
-    errcode_t nvRet = uapi_nv_write(NV_ID_CUSTOM_KEY_SERIAL_NUM, &sn, sizeof(custom_key_sn_t));
-    //PRINT("write sn len %d, ret %d , %s\r\n",len,nvRet,sn.sn);
+    p_sn->size = len;
+    memcpy_s(p_sn->sn,sizeof(p_sn->sn),buf_sn,len); 
+    nv_ret_value = uapi_nv_write(NV_ID_CUSTOM_KEY_SERIAL_NUM, write_value, key_len); 
+    if (nv_ret_value != ERRCODE_SUCC) { 
+        /* ERROR PROCESS */ 
+        free(write_value); 
+        return ERRCODE_FAIL; 
+    } 
+    /* APP PROCESS */ 
+    free(write_value); 
+
 #endif
-    return nvRet;
+    return nv_ret_value;
+
 }
 // extern "C" {
     uint32_t mcu_os_sys_reset(uint8_t *para, uint32_t para_len);
index cf7a552..ea9416c 100644 (file)
@@ -65,8 +65,9 @@ static uint32_t custom_utils_setsn(uint8_t *para, uint32_t paraLen, char *strCom
     }
     uint8_t *sn_buf = (uint8_t*)argv[0];
     uint16_t len = strlen((const char*)sn_buf);
-    PRINT("set sn = %s \r\n",sn_buf);
     uint32_t rret = zh_set_sn(sn_buf,len);
+    PRINT("set sn = %s , len =  %d, ret 0x%X\r\n",sn_buf,len, rret);
+
     return 0;
 }
 
@@ -74,6 +75,7 @@ static uint32_t custom_start_ota(uint8_t *para, uint32_t paraLen, char *strCommo
 {
     UNUSED(strCommonCmd);
     PRINT("custom_start_ota  \r\n");
+
     return uaip_cmd_update_request();
 }
 static uint32_t custom_utils_getsn(uint8_t *para, uint32_t paraLen, char *strCommonCmd)
@@ -82,7 +84,7 @@ static uint32_t custom_utils_getsn(uint8_t *para, uint32_t paraLen, char *strCom
     uint8_t sn_buf[32] = {0};
     uint32_t len = 0;
     uint32_t ret = zh_get_sn(sn_buf,&len);
-    PRINT("get sn len %d , %s \r\n",len,sn_buf);
+    PRINT("get sn len %d , %s , ret = 0x%X\r\n",len,sn_buf,ret);
     return 0;
 }
 static const at_cmd_table_t g_custom_utils_cmd[] = {
index 1549be8..0cce4a7 100755 (executable)
@@ -1,54 +1,54 @@
-#===============================================================================\r
-# @brief    cmake file\r
-# Copyright (c) @CompanyNameMagicTag 2022-2022. All rights reserved.\r
-#===============================================================================\r
-set(COMPONENT_NAME "nv")\r
-\r
-set(SOURCES\r
-    ${CMAKE_CURRENT_SOURCE_DIR}/nv_storage_app/soc_nv_storage_handle.c\r
-    ${CMAKE_CURRENT_SOURCE_DIR}/nv_storage_app/soc_nv_storage.c\r
-    ${CMAKE_CURRENT_SOURCE_DIR}/nv_storage_lib/nv_key.c\r
-    ${CMAKE_CURRENT_SOURCE_DIR}/nv_storage_lib/nv_notify.c\r
-    ${CMAKE_CURRENT_SOURCE_DIR}/nv_storage_lib/nv_nvregion.c\r
-    ${CMAKE_CURRENT_SOURCE_DIR}/nv_storage_lib/nv_page.c\r
-    ${CMAKE_CURRENT_SOURCE_DIR}/nv_storage_lib/nv_reset.c\r
-    ${CMAKE_CURRENT_SOURCE_DIR}/nv_storage_lib/nv_rpc.c\r
-    ${CMAKE_CURRENT_SOURCE_DIR}/nv_storage_lib/nv_store.c\r
-    ${CMAKE_CURRENT_SOURCE_DIR}/nv_storage_lib/nv_update.c\r
-    ${CMAKE_CURRENT_SOURCE_DIR}/nv_storage_lib/nv_upg.c\r
-    ${CMAKE_CURRENT_SOURCE_DIR}/nv_storage_lib/nv_debug.c\r
-    ${CMAKE_CURRENT_SOURCE_DIR}/nv_storage_lib/nv_async_store.c\r
-)\r
-\r
-set(PUBLIC_HEADER\r
-    ${CMAKE_SOURCE_DIR}/include/middleware/utils\r
-    ${CMAKE_CURRENT_SOURCE_DIR}/nv_storage_lib\r
-    ${CMAKE_CURRENT_SOURCE_DIR}/nv_storage_app\r
-)\r
-\r
-set(PRIVATE_HEADER\r
-    ${CMAKE_SOURCE_DIR}/middleware/chips/${chip}/nv/include\r
-    ${CMAKE_SOURCE_DIR}/middleware/utils/update/inner_include\r
-)\r
-\r
-set(PRIVATE_DEFINES\r
-)\r
-\r
-set(PUBLIC_DEFINES\r
-)\r
-\r
-# use this when you want to add ccflags like -include xxx\r
-set(COMPONENT_PUBLIC_CCFLAGS\r
-)\r
-\r
-set(COMPONENT_CCFLAGS\r
-)\r
-\r
-set(WHOLE_LINK\r
-    true\r
-)\r
-\r
-set(MAIN_COMPONENT\r
-    false\r
-)\r
+#===============================================================================
+# @brief    cmake file
+# Copyright (c) @CompanyNameMagicTag 2022-2022. All rights reserved.
+#===============================================================================
+set(COMPONENT_NAME "nv")
+
+set(SOURCES
+    ${CMAKE_CURRENT_SOURCE_DIR}/nv_storage_app/soc_nv_storage_handle.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/nv_storage_app/soc_nv_storage.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/nv_storage_lib/nv_key.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/nv_storage_lib/nv_notify.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/nv_storage_lib/nv_nvregion.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/nv_storage_lib/nv_page.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/nv_storage_lib/nv_reset.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/nv_storage_lib/nv_rpc.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/nv_storage_lib/nv_store.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/nv_storage_lib/nv_update.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/nv_storage_lib/nv_upg.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/nv_storage_lib/nv_debug.c
+    ${CMAKE_CURRENT_SOURCE_DIR}/nv_storage_lib/nv_async_store.c
+)
+
+set(PUBLIC_HEADER
+    ${CMAKE_SOURCE_DIR}/include/middleware/utils
+    ${CMAKE_CURRENT_SOURCE_DIR}/nv_storage_lib
+    ${CMAKE_CURRENT_SOURCE_DIR}/nv_storage_app
+)
+
+set(PRIVATE_HEADER
+    ${CMAKE_SOURCE_DIR}/middleware/chips/${chip}/nv/include
+    ${CMAKE_SOURCE_DIR}/middleware/utils/update/inner_include
+)
+
+set(PRIVATE_DEFINES
+)
+
+set(PUBLIC_DEFINES
+)
+
+# use this when you want to add ccflags like -include xxx
+set(COMPONENT_PUBLIC_CCFLAGS
+)
+
+set(COMPONENT_CCFLAGS
+)
+
+set(WHOLE_LINK
+    true
+)
+
+set(MAIN_COMPONENT
+    false
+)
 build_component()
\ No newline at end of file
index 8fe59cd..75f1a8d 100755 (executable)
-/*\r
- * Copyright (c) @CompanyNameMagicTag 2021-2022. All rights reserved.\r
- * Description: KEY VALUE STORAGE INTERNAL INTERFACE\r
- */\r
-\r
-#ifndef NV_STORAGE_H\r
-#define NV_STORAGE_H\r
-\r
-#include "nv_notify.h"\r
-#include "nv.h"\r
-\r
-#include "errcode.h"\r
-\r
-#ifdef __cplusplus\r
-#if __cplusplus\r
-extern "C" {\r
-#endif /* __cplusplus */\r
-#endif /* __cplusplus */\r
-\r
-/**\r
- * KV key attribute flags\r
- * A key with a normal or encrypted attribute can be set to a permanent attribute again.\r
- * A key with a permanent attribute cannot be set to another attribute.\r
- * Attribute 3 is considered to be both encrypted and permanent.\r
- */\r
-typedef enum {\r
-    NV_ATTRIBUTE_NORMAL       = 0x0,    /* Default type, no special attribute */\r
-    NV_ATTRIBUTE_PERMANENT    = 0x1,    /* Key is permanent and can't be deleted or modified */\r
-    NV_ATTRIBUTE_ENCRYPTED    = 0x2,    /* Key is encrypted in flash, The key can be encrypted permanently */\r
-    NV_ATTRIBUTE_NON_UPGRADE  = 0x4\r
-} nv_attributes_t;\r
-\r
-nv_direct_ctrl_t *nv_direct_get_nv_ctrl(void);\r
-\r
-/**\r
- * Force store a key value pair, even if the key has been set to permanent.\r
- * @param key key to associate kvalue to\r
- * @param kvalue value to store\r
- * @param kvalue_length length in bytes of kvalue\r
- * @return SOC_ERR_SUCCESS or an error code\r
- */\r
-errcode_t uapi_nv_write_force(uint16_t key, const uint8_t *kvalue, uint16_t kvalue_length);\r
-\r
-/**\r
- * Erase an stored value given its key\r
- * @param key key of the key to erase\r
- * @return SOC_ERR_SUCCESS or an error code\r
- */\r
-errcode_t uapi_nv_delete_key(uint16_t key);\r
-\r
-/**\r
- * Update the attributes of an existing key.\r
- * @param key key to associate make permanent\r
- * @param attr Sets the storage attributes of a key.\r
- * @return SOC_ERR_SUCCESS or an error code\r
- * @note This key can not then be deleted or overwitten, and there is no mechanism to undo this\r
- */\r
-errcode_t uapi_nv_update_key_attr(uint16_t key, nv_key_attr_t *attr, nv_storage_completed_callback func);\r
-\r
-/**\r
- * Get key information associated with a specific key\r
- * @param key key of the value to get\r
- * @param length length of the current key\r
- * @param attr The storage attributes of a key.\r
- * @return SOC_ERR_SUCCESS or an error code\r
- */\r
-errcode_t uapi_nv_get_key_attr(uint16_t key, uint16_t *length, nv_key_attr_t *attr);\r
-\r
- /**\r
- * @ingroup iot_nv\r
- * @brief compare a value associated with a specific key.\r
- *        CNcomment:检验特定NV的值 CNend\r
- *\r
- * @par 描述:\r
- * Check whether NV data has been stored. If the stored data is the same\r
- * as the input parameter data,a success message is returned.\r
- * CNcomment:检查NV数据是否已存储。如果存储的数据与入参数据相同,则返回成功 CNend\r
- * @attention None.\r
- *\r
- * @param key               [IN] The key to which the kvalue is associated.\r
- *                               CNcomment:要检验的NV ID CNend\r
- * @param kvalue_length     [IN] Length of kvalue in bytes.\r
- *                               CNcomment:要检验的NV长度 CNend\r
- * @param kvalue            [IN] The value to store.CNcomment:待进行对比的NV值 CNend\r
- *\r
- * @retval #true                Success\r
- * @retval #false               Failure\r
- *\r
- * @par 依赖:\r
- * @li nv\r
- * @li nv.h\r
- * @see None\r
- */\r
-bool uapi_nv_is_stored(uint16_t key, uint16_t kvalue_length, const uint8_t *kvalue);\r
-\r
-#ifdef __cplusplus\r
-#if __cplusplus\r
-}\r
-#endif /* __cplusplus */\r
-#endif /* __cplusplus */\r
-\r
-#endif /* NV_STORAGE_H */\r
+/*
+ * Copyright (c) @CompanyNameMagicTag 2021-2022. All rights reserved.
+ * Description: KEY VALUE STORAGE INTERNAL INTERFACE
+ */
+
+#ifndef NV_STORAGE_H
+#define NV_STORAGE_H
+
+#include "nv_notify.h"
+#include "nv.h"
+
+#include "errcode.h"
+
+#ifdef __cplusplus
+#if __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+/**
+ * KV key attribute flags
+ * A key with a normal or encrypted attribute can be set to a permanent attribute again.
+ * A key with a permanent attribute cannot be set to another attribute.
+ * Attribute 3 is considered to be both encrypted and permanent.
+ */
+typedef enum {
+    NV_ATTRIBUTE_NORMAL       = 0x0,    /* Default type, no special attribute */
+    NV_ATTRIBUTE_PERMANENT    = 0x1,    /* Key is permanent and can't be deleted or modified */
+    NV_ATTRIBUTE_ENCRYPTED    = 0x2,    /* Key is encrypted in flash, The key can be encrypted permanently */
+    NV_ATTRIBUTE_NON_UPGRADE  = 0x4
+} nv_attributes_t;
+
+nv_direct_ctrl_t *nv_direct_get_nv_ctrl(void);
+
+/**
+ * Force store a key value pair, even if the key has been set to permanent.
+ * @param key key to associate kvalue to
+ * @param kvalue value to store
+ * @param kvalue_length length in bytes of kvalue
+ * @return SOC_ERR_SUCCESS or an error code
+ */
+errcode_t uapi_nv_write_force(uint16_t key, const uint8_t *kvalue, uint16_t kvalue_length);
+
+/**
+ * Erase an stored value given its key
+ * @param key key of the key to erase
+ * @return SOC_ERR_SUCCESS or an error code
+ */
+errcode_t uapi_nv_delete_key(uint16_t key);
+
+/**
+ * Update the attributes of an existing key.
+ * @param key key to associate make permanent
+ * @param attr Sets the storage attributes of a key.
+ * @return SOC_ERR_SUCCESS or an error code
+ * @note This key can not then be deleted or overwitten, and there is no mechanism to undo this
+ */
+errcode_t uapi_nv_update_key_attr(uint16_t key, nv_key_attr_t *attr, nv_storage_completed_callback func);
+
+/**
+ * Get key information associated with a specific key
+ * @param key key of the value to get
+ * @param length length of the current key
+ * @param attr The storage attributes of a key.
+ * @return SOC_ERR_SUCCESS or an error code
+ */
+errcode_t uapi_nv_get_key_attr(uint16_t key, uint16_t *length, nv_key_attr_t *attr);
+
+ /**
+ * @ingroup iot_nv
+ * @brief compare a value associated with a specific key.
+ *        CNcomment:检验特定NV的值 CNend
+ *
+ * @par 描述:
+ * Check whether NV data has been stored. If the stored data is the same
+ * as the input parameter data,a success message is returned.
+ * CNcomment:检查NV数据是否已存储。如果存储的数据与入参数据相同,则返回成功 CNend
+ * @attention None.
+ *
+ * @param key               [IN] The key to which the kvalue is associated.
+ *                               CNcomment:要检验的NV ID CNend
+ * @param kvalue_length     [IN] Length of kvalue in bytes.
+ *                               CNcomment:要检验的NV长度 CNend
+ * @param kvalue            [IN] The value to store.CNcomment:待进行对比的NV值 CNend
+ *
+ * @retval #true                Success
+ * @retval #false               Failure
+ *
+ * @par 依赖:
+ * @li nv
+ * @li nv.h
+ * @see None
+ */
+bool uapi_nv_is_stored(uint16_t key, uint16_t kvalue_length, const uint8_t *kvalue);
+
+#ifdef __cplusplus
+#if __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+#endif /* NV_STORAGE_H */
index 255ee94..99a09bb 100755 (executable)
-/*\r
- * Copyright (c) @CompanyNameMagicTag 2016-2022. All rights reserved.\r
- * Description: SOC KEY VALUE STORAGE IMPLEMENTATION\r
- */\r
-\r
-#include "nv.h"\r
-#include "nv_storage.h"\r
-#include "nv_store.h"\r
-#include "nv_reset.h"\r
-#include "securec.h"\r
-#include "nv_porting.h"\r
-#include "common_def.h"\r
-#include "nv_config.h"\r
-#include "systick.h"\r
-#include "nv_async_store.h"\r
-#include "nv_update.h"\r
-#include "nv_notify.h"\r
-#include "nv_task_adapt.h"\r
-#include "nv_storage_handle.h"\r
-\r
-void uapi_nv_init(void)\r
-{\r
-    (void)nv_direct_ctrl_init();\r
-}\r
-\r
-errcode_t uapi_nv_write_with_attr(uint16_t key, const uint8_t *kvalue, uint16_t kvalue_length, nv_key_attr_t *attr,\r
-                                  nv_storage_completed_callback func)\r
-{\r
-    errcode_t ret;\r
-\r
-    if (kvalue == NULL || kvalue_length == 0) {\r
-        return ERRCODE_NV_INVALID_PARAMS;\r
-    }\r
-\r
-#if (CONFIG_NV_SUPPORT_ENCRYPT != NV_YES)\r
-    if ((attr != NULL && attr->encrypted == true)) {\r
-        nv_log_err("[NV] nv_direct_write_with_attr: encryption not support!\r\n");\r
-        return ERRCODE_NV_ILLEGAL_OPERATION;\r
-    }\r
-#endif\r
-\r
-    uint64_t start_time = uapi_systick_get_ms();\r
-\r
-#if (CONFIG_NV_SUPPORT_ASYNCHRONOUS_STORE == NV_YES)\r
-    ret = nv_async_write_with_attr(key, kvalue, kvalue_length, attr, func);\r
-#else\r
-    ret = nv_direct_write_with_attr(key, kvalue, kvalue_length, attr, func);\r
-#endif\r
-    uint64_t end_time = uapi_systick_get_ms();\r
-    nv_log_debug("[NV] write key (key_id = 0x%x len = %d) ret = %d. takes %lld ms\r\n",\r
-        key, kvalue_length, ret, (end_time - start_time));\r
-    unused(start_time);\r
-    unused(end_time);\r
-    return ret;\r
-}\r
-\r
-errcode_t uapi_nv_write(uint16_t key, const uint8_t *kvalue, uint16_t kvalue_length)\r
-{\r
-    return uapi_nv_write_with_attr(key, kvalue, kvalue_length, NULL, NULL);\r
-}\r
-\r
-errcode_t uapi_nv_write_force(uint16_t key, const uint8_t *kvalue, uint16_t kvalue_length)\r
-{\r
-    if (kvalue == NULL || kvalue_length == 0) {\r
-        return ERRCODE_NV_INVALID_PARAMS;\r
-    }\r
-#ifdef CONFIG_NV_SUPPORT_WRITE_FORCE\r
-    return nv_direct_write_force(key, kvalue, kvalue_length);\r
-#endif\r
-    unused(key);\r
-    return ERRCODE_NOT_SUPPORT;\r
-}\r
-\r
-errcode_t uapi_nv_update_key_attr(uint16_t key, nv_key_attr_t *attr, nv_storage_completed_callback func)\r
-{\r
-    if (attr == NULL) {\r
-        return ERRCODE_NV_INVALID_PARAMS;\r
-    }\r
-#ifdef CONFIG_NV_SUPPORT_UPDATE_ATTR\r
-    return nv_direct_update_key_attr(key, attr, func);\r
-#endif\r
-    unused(key);\r
-    unused(func);\r
-    return ERRCODE_NOT_SUPPORT;\r
-}\r
-\r
-errcode_t uapi_nv_get_key_attr(uint16_t key, uint16_t *length, nv_key_attr_t *attr)\r
-{\r
-    if (attr == NULL) {\r
-        return ERRCODE_NV_INVALID_PARAMS;\r
-    }\r
-\r
-    return nv_direct_get_key_attr(key, length, attr);\r
-}\r
-\r
-errcode_t uapi_nv_read_with_attr(uint16_t key, uint16_t kvalue_max_length, uint16_t *kvalue_length, uint8_t *kvalue,\r
-                                 nv_key_attr_t *attr)\r
-{\r
-    errcode_t ret;\r
-\r
-    if (kvalue_length == NULL || kvalue == NULL || attr == NULL) {\r
-        return ERRCODE_NV_INVALID_PARAMS;\r
-    }\r
-\r
-    uint64_t start_time = uapi_systick_get_ms();\r
-\r
-#if (CONFIG_NV_SUPPORT_ASYNCHRONOUS_STORE == NV_YES)\r
-    ret = nv_async_read_with_attr(key, kvalue_max_length, kvalue_length, kvalue, attr);\r
-#else\r
-    ret = nv_direct_get_key_data(key, kvalue_max_length, kvalue_length, kvalue, attr);\r
-#endif\r
-\r
-    uint64_t end_time = uapi_systick_get_ms();\r
-    nv_log_debug("[NV] read key (key_id = 0x%x len = %d) ret = 0x%x. takes %lld ms\r\n",\r
-        key, *kvalue_length, ret, (end_time - start_time));\r
-    unused(start_time);\r
-    unused(end_time);\r
-    return ret;\r
-}\r
-\r
-errcode_t uapi_nv_read(uint16_t key, uint16_t kvalue_max_length, uint16_t *kvalue_length, uint8_t *kvalue)\r
-{\r
-    if (kvalue_length == NULL || kvalue == NULL) {\r
-        return ERRCODE_NV_INVALID_PARAMS;\r
-    }\r
-    nv_key_attr_t attr;\r
-    return uapi_nv_read_with_attr(key, kvalue_max_length, kvalue_length, kvalue, &attr);\r
-}\r
-\r
-errcode_t uapi_nv_delete_key(uint16_t key)\r
-{\r
-    unused(key);\r
-    return ERRCODE_NOT_SUPPORT;\r
-}\r
-\r
-bool uapi_nv_is_stored(uint16_t key, uint16_t kvalue_length, const uint8_t *kvalue)\r
-{\r
-    if (kvalue_length == 0 || kvalue == NULL) {\r
-        return false;\r
-    }\r
-\r
-    errcode_t ret = nv_direct_stored(key, kvalue_length, kvalue);\r
-    if (ret == ERRCODE_SUCC) {\r
-        return true;\r
-    } else {\r
-        return false;\r
-    }\r
-}\r
-\r
-errcode_t uapi_nv_get_store_status(nv_store_status_t *status)\r
-{\r
-    if (status == NULL) {\r
-        return ERRCODE_NV_INVALID_PARAMS;\r
-    }\r
-\r
-    uint64_t start_time = uapi_systick_get_ms();\r
-    errcode_t ret = nv_direct_get_store_status(status);\r
-    uint64_t end_time = uapi_systick_get_ms();\r
-    nv_log_debug("[NV] get store status take %lld ms\r\n", (end_time - start_time));\r
-    unused(start_time);\r
-    unused(end_time);\r
-    return ret;\r
-}\r
-\r
-errcode_t uapi_nv_backup(const nv_backup_mode_t *backup_mode)\r
-{\r
-#if (CONFIG_NV_SUPPORT_BACKUP_RESTORE == NV_YES)\r
-    if (backup_mode == NULL) {\r
-        return ERRCODE_NV_INVALID_PARAMS;\r
-    }\r
-\r
-    return nv_direct_backup_keys(backup_mode);\r
-#else\r
-    unused(backup_mode);\r
-    return ERRCODE_NOT_SUPPORT;\r
-#endif\r
-}\r
-\r
-errcode_t uapi_nv_set_restore_mode_all(void)\r
-{\r
-#if (CONFIG_NV_SUPPORT_BACKUP_RESTORE == NV_YES)\r
-\r
-    return nv_direct_set_restore_flag_all();\r
-#else\r
-    return ERRCODE_NOT_SUPPORT;\r
-#endif\r
-}\r
-\r
-errcode_t uapi_nv_set_restore_mode_partitial(const nv_restore_mode_t *restore_mode)\r
-{\r
-#if (CONFIG_NV_SUPPORT_BACKUP_RESTORE == NV_YES)\r
-    return nv_direct_set_restore_flag_partitial(restore_mode);\r
-#else\r
-    unused(restore_mode);\r
-    return ERRCODE_NOT_SUPPORT;\r
-#endif\r
-}\r
-\r
-errcode_t uapi_nv_flush(void)\r
-{\r
-#if (CONFIG_NV_SUPPORT_ASYNCHRONOUS_STORE == NV_YES)\r
-    return nv_async_flush();\r
-#else\r
-    return ERRCODE_NOT_SUPPORT;\r
-#endif\r
-}\r
-\r
-errcode_t uapi_nv_register_change_notify_proc(uint16_t min_key, uint16_t max_key, nv_changed_notify_func func)\r
-{\r
-    if ((min_key > max_key) || (func == NULL)) {\r
-        return ERRCODE_NV_INVALID_PARAMS;\r
-    }\r
-\r
-    if (nv_direct_get_nv_ctrl()->notify_regitser_max_nums == 0) {\r
-        return ERRCODE_NV_INVALID_PARAMS;\r
-    }\r
-#if (CONFIG_NV_SUPPORT_CHANGE_NOTIFY == NV_YES)\r
-    return nv_direct_add_func_to_notify_list(min_key, max_key, func);\r
-#endif\r
-    return ERRCODE_NOT_SUPPORT;\r
-}\r
+/*
+ * Copyright (c) @CompanyNameMagicTag 2016-2022. All rights reserved.
+ * Description: SOC KEY VALUE STORAGE IMPLEMENTATION
+ */
+
+#include "nv.h"
+#include "nv_storage.h"
+#include "nv_store.h"
+#include "nv_reset.h"
+#include "securec.h"
+#include "nv_porting.h"
+#include "common_def.h"
+#include "nv_config.h"
+#include "systick.h"
+#include "nv_async_store.h"
+#include "nv_update.h"
+#include "nv_notify.h"
+#include "nv_task_adapt.h"
+#include "nv_storage_handle.h"
+
+void uapi_nv_init(void)
+{
+    (void)nv_direct_ctrl_init();
+}
+
+errcode_t uapi_nv_write_with_attr(uint16_t key, const uint8_t *kvalue, uint16_t kvalue_length, nv_key_attr_t *attr,
+                                  nv_storage_completed_callback func)
+{
+    errcode_t ret;
+
+    if (kvalue == NULL || kvalue_length == 0) {
+        return ERRCODE_NV_INVALID_PARAMS;
+    }
+
+#if (CONFIG_NV_SUPPORT_ENCRYPT != NV_YES)
+    if ((attr != NULL && attr->encrypted == true)) {
+        nv_log_err("[NV] nv_direct_write_with_attr: encryption not support!\r\n");
+        return ERRCODE_NV_ILLEGAL_OPERATION;
+    }
+#endif
+
+    uint64_t start_time = uapi_systick_get_ms();
+
+#if (CONFIG_NV_SUPPORT_ASYNCHRONOUS_STORE == NV_YES)
+    ret = nv_async_write_with_attr(key, kvalue, kvalue_length, attr, func);
+#else
+    ret = nv_direct_write_with_attr(key, kvalue, kvalue_length, attr, func);
+#endif
+    uint64_t end_time = uapi_systick_get_ms();
+    nv_log_debug("[NV] write key (key_id = 0x%x len = %d) ret = %d. takes %lld ms\r\n",
+        key, kvalue_length, ret, (end_time - start_time));
+    unused(start_time);
+    unused(end_time);
+    return ret;
+}
+
+errcode_t uapi_nv_write(uint16_t key, const uint8_t *kvalue, uint16_t kvalue_length)
+{
+    nv_key_attr_t kattrib = {0};
+    kattrib.encrypted = false;
+    kattrib.non_upgrade = false;
+    kattrib.permanent = false;
+    return uapi_nv_write_with_attr(key, kvalue, kvalue_length, &kattrib, NULL);
+}
+
+errcode_t uapi_nv_write_force(uint16_t key, const uint8_t *kvalue, uint16_t kvalue_length)
+{
+    if (kvalue == NULL || kvalue_length == 0) {
+        return ERRCODE_NV_INVALID_PARAMS;
+    }
+#ifdef CONFIG_NV_SUPPORT_WRITE_FORCE
+    return nv_direct_write_force(key, kvalue, kvalue_length);
+#endif
+    unused(key);
+    return ERRCODE_NOT_SUPPORT;
+}
+
+errcode_t uapi_nv_update_key_attr(uint16_t key, nv_key_attr_t *attr, nv_storage_completed_callback func)
+{
+    if (attr == NULL) {
+        return ERRCODE_NV_INVALID_PARAMS;
+    }
+#ifdef CONFIG_NV_SUPPORT_UPDATE_ATTR
+    return nv_direct_update_key_attr(key, attr, func);
+#endif
+    unused(key);
+    unused(func);
+    return ERRCODE_NOT_SUPPORT;
+}
+
+errcode_t uapi_nv_get_key_attr(uint16_t key, uint16_t *length, nv_key_attr_t *attr)
+{
+    if (attr == NULL) {
+        return ERRCODE_NV_INVALID_PARAMS;
+    }
+
+    return nv_direct_get_key_attr(key, length, attr);
+}
+
+errcode_t uapi_nv_read_with_attr(uint16_t key, uint16_t kvalue_max_length, uint16_t *kvalue_length, uint8_t *kvalue,
+                                 nv_key_attr_t *attr)
+{
+    errcode_t ret;
+
+    if (kvalue_length == NULL || kvalue == NULL || attr == NULL) {
+        return ERRCODE_NV_INVALID_PARAMS;
+    }
+
+    uint64_t start_time = uapi_systick_get_ms();
+
+#if (CONFIG_NV_SUPPORT_ASYNCHRONOUS_STORE == NV_YES)
+    ret = nv_async_read_with_attr(key, kvalue_max_length, kvalue_length, kvalue, attr);
+#else
+    ret = nv_direct_get_key_data(key, kvalue_max_length, kvalue_length, kvalue, attr);
+#endif
+
+    uint64_t end_time = uapi_systick_get_ms();
+    nv_log_debug("[NV] read key (key_id = 0x%x len = %d) ret = 0x%x. takes %lld ms\r\n",
+        key, *kvalue_length, ret, (end_time - start_time));
+    unused(start_time);
+    unused(end_time);
+    return ret;
+}
+
+errcode_t uapi_nv_read(uint16_t key, uint16_t kvalue_max_length, uint16_t *kvalue_length, uint8_t *kvalue)
+{
+    if (kvalue_length == NULL || kvalue == NULL) {
+        return ERRCODE_NV_INVALID_PARAMS;
+    }
+    nv_key_attr_t attr;
+    return uapi_nv_read_with_attr(key, kvalue_max_length, kvalue_length, kvalue, &attr);
+}
+
+errcode_t uapi_nv_delete_key(uint16_t key)
+{
+    unused(key);
+    return ERRCODE_NOT_SUPPORT;
+}
+
+bool uapi_nv_is_stored(uint16_t key, uint16_t kvalue_length, const uint8_t *kvalue)
+{
+    if (kvalue_length == 0 || kvalue == NULL) {
+        return false;
+    }
+
+    errcode_t ret = nv_direct_stored(key, kvalue_length, kvalue);
+    if (ret == ERRCODE_SUCC) {
+        return true;
+    } else {
+        return false;
+    }
+}
+
+errcode_t uapi_nv_get_store_status(nv_store_status_t *status)
+{
+    if (status == NULL) {
+        return ERRCODE_NV_INVALID_PARAMS;
+    }
+
+    uint64_t start_time = uapi_systick_get_ms();
+    errcode_t ret = nv_direct_get_store_status(status);
+    uint64_t end_time = uapi_systick_get_ms();
+    nv_log_debug("[NV] get store status take %lld ms\r\n", (end_time - start_time));
+    unused(start_time);
+    unused(end_time);
+    return ret;
+}
+
+errcode_t uapi_nv_backup(const nv_backup_mode_t *backup_mode)
+{
+#if (CONFIG_NV_SUPPORT_BACKUP_RESTORE == NV_YES)
+    if (backup_mode == NULL) {
+        return ERRCODE_NV_INVALID_PARAMS;
+    }
+
+    return nv_direct_backup_keys(backup_mode);
+#else
+    unused(backup_mode);
+    return ERRCODE_NOT_SUPPORT;
+#endif
+}
+
+errcode_t uapi_nv_set_restore_mode_all(void)
+{
+#if (CONFIG_NV_SUPPORT_BACKUP_RESTORE == NV_YES)
+
+    return nv_direct_set_restore_flag_all();
+#else
+    return ERRCODE_NOT_SUPPORT;
+#endif
+}
+
+errcode_t uapi_nv_set_restore_mode_partitial(const nv_restore_mode_t *restore_mode)
+{
+#if (CONFIG_NV_SUPPORT_BACKUP_RESTORE == NV_YES)
+    return nv_direct_set_restore_flag_partitial(restore_mode);
+#else
+    unused(restore_mode);
+    return ERRCODE_NOT_SUPPORT;
+#endif
+}
+
+errcode_t uapi_nv_flush(void)
+{
+#if (CONFIG_NV_SUPPORT_ASYNCHRONOUS_STORE == NV_YES)
+    return nv_async_flush();
+#else
+    return ERRCODE_NOT_SUPPORT;
+#endif
+}
+
+errcode_t uapi_nv_register_change_notify_proc(uint16_t min_key, uint16_t max_key, nv_changed_notify_func func)
+{
+    if ((min_key > max_key) || (func == NULL)) {
+        return ERRCODE_NV_INVALID_PARAMS;
+    }
+
+    if (nv_direct_get_nv_ctrl()->notify_regitser_max_nums == 0) {
+        return ERRCODE_NV_INVALID_PARAMS;
+    }
+#if (CONFIG_NV_SUPPORT_CHANGE_NOTIFY == NV_YES)
+    return nv_direct_add_func_to_notify_list(min_key, max_key, func);
+#endif
+    return ERRCODE_NOT_SUPPORT;
+}
index 0c5fb35..4c0fe32 100755 (executable)
-/*\r
- * Copyright (c) @CompanyNameMagicTag 2016-2022. All rights reserved.\r
- * Description: SOC KEY VALUE STORAGE IMPLEMENTATION\r
- */\r
-\r
-#include "nv.h"\r
-#include "nv_storage.h"\r
-#include "nv_store.h"\r
-#include "nv_upg.h"\r
-#include "securec.h"\r
-#include "nv_porting.h"\r
-#include "common_def.h"\r
-#include "nv_reset.h"\r
-#include "nv_async_store.h"\r
-#include "osal_semaphore.h"\r
-#include "nv_update.h"\r
-#include "nv_notify.h"\r
-#include "nv_task_adapt.h"\r
-#include "nv_storage_handle.h"\r
-\r
-osal_semaphore nv_sem;\r
-#define MAX_BINARY_VAL 1\r
-\r
-STATIC nv_attributes_t nv_helper_convert_key_attr(const nv_key_attr_t *attr)\r
-{\r
-    nv_attributes_t attribute = NV_ATTRIBUTE_NORMAL;\r
-    bool is_support_crypt = false;\r
-    if (attr == NULL) {\r
-        return attribute;\r
-    }\r
-\r
-#if (CONFIG_NV_SUPPORT_ENCRYPT == NV_YES)\r
-    is_support_crypt = attr->encrypted;\r
-#endif\r
-\r
-    if (attr->permanent && is_support_crypt) {\r
-        attribute = NV_ATTRIBUTE_ENCRYPTED | NV_ATTRIBUTE_PERMANENT | NV_ATTRIBUTE_NON_UPGRADE;\r
-    } else if (attr->permanent) {\r
-        attribute = NV_ATTRIBUTE_PERMANENT | NV_ATTRIBUTE_NON_UPGRADE;\r
-    } else if (is_support_crypt) {\r
-        attribute = NV_ATTRIBUTE_ENCRYPTED | NV_ATTRIBUTE_NON_UPGRADE;\r
-    } else if (attr->non_upgrade) {\r
-        attribute = NV_ATTRIBUTE_NON_UPGRADE;\r
-    }\r
-    return attribute;\r
-}\r
-\r
-static uint16_t nv_storage_max_key_space(const nv_key_attr_t *attr)\r
-{\r
-    if (attr == NULL) {\r
-        return NV_NORMAL_KVALUE_MAX_LEN;\r
-    }\r
-    return (attr->encrypted ? NV_ENCRYPTED_KVALUE_MAX_LEN : NV_NORMAL_KVALUE_MAX_LEN);\r
-}\r
-\r
-nv_direct_ctrl_t g_nv_direct_ctrl;\r
-nv_direct_ctrl_t *nv_direct_get_nv_ctrl(void)\r
-{\r
-    return &g_nv_direct_ctrl;\r
-}\r
-\r
-errcode_t nv_direct_get_key_attr(uint16_t key_id, uint16_t *len, nv_key_attr_t *attr)\r
-{\r
-    kv_attributes_t get_attribute = 0;\r
-    errcode_t ret = ERRCODE_SUCC;\r
-\r
-    if (len == NULL || attr == NULL) {\r
-        return ERRCODE_NV_INVALID_PARAMS;\r
-    }\r
-\r
-    if (osal_sem_down_timeout(&nv_sem, 0xFFFFFFFF) != ERRCODE_SUCC) {\r
-        return ERRCODE_NV_SEM_WAIT_ERR;\r
-    }\r
-\r
-    *len = 0;\r
-    memset_s(attr, sizeof(nv_key_attr_t), 0, sizeof(nv_key_attr_t));\r
-    ret = kv_store_get_key_attr(KV_STORE_APPLICATION, key_id, len, &get_attribute);\r
-    if (ret == ERRCODE_SUCC) {\r
-        if (((uint32_t)get_attribute & NV_ATTRIBUTE_PERMANENT) != 0) {\r
-            attr->permanent = true;\r
-            attr->non_upgrade = true;\r
-        }\r
-        if (((uint32_t)get_attribute & NV_ATTRIBUTE_ENCRYPTED) != 0) {\r
-            attr->encrypted = true;\r
-            attr->non_upgrade = true;\r
-        }\r
-        if (((uint32_t)get_attribute & NV_ATTRIBUTE_NON_UPGRADE) != 0) {\r
-            attr->non_upgrade = true;\r
-        }\r
-    }\r
-    osal_sem_up(&nv_sem);\r
-    return ret;\r
-}\r
-\r
-errcode_t nv_direct_write_with_attr(uint16_t key_id, const uint8_t *kvalue, uint16_t kvalue_length, nv_key_attr_t *attr,\r
-    nv_storage_completed_callback func)\r
-{\r
-    errcode_t ret;\r
-    flash_task_node task_node = {0};\r
-    uint16_t len;\r
-    kv_attributes_t attribute = (kv_attributes_t)0;\r
-    unused(func);\r
-\r
-    if (kvalue_length > nv_storage_max_key_space(attr)) {\r
-        nv_log_err("[NV] nv_direct_write_with_attr: len exceeds the max size. key_id = 0x%x\r\n", key_id);\r
-        return ERRCODE_NV_NO_ENOUGH_SPACE;\r
-    }\r
-\r
-    if (osal_sem_down_timeout(&nv_sem, 0xFFFFFFFF) != ERRCODE_SUCC) {\r
-        nv_log_err("[NV] nv_direct_write_with_attr: semaphore error!\r\n");\r
-        return ERRCODE_NV_SEM_WAIT_ERR;\r
-    }\r
-\r
-    ret = kv_store_get_key_attr(KV_STORE_APPLICATION, key_id, &len, &attribute);\r
-    if (ret == ERRCODE_SUCC) {\r
-        if ((((uint32_t)attribute & NV_ATTRIBUTE_PERMANENT) != 0) ||\r
-            ((((uint32_t)attribute & NV_ATTRIBUTE_ENCRYPTED) != 0) && (attr != NULL && attr->encrypted == false))\r
-            || ((((uint32_t)attribute & NV_ATTRIBUTE_NON_UPGRADE) != 0) && (attr == NULL))) {\r
-            /* When old key is permanent, not permit to write */\r
-            /* When old key is encrypted, new key is non-encrypted, not permit to write */\r
-            /* When old key is non upgrade, new key is write by ordinary write, not permit to write */\r
-            nv_log_err("[NV] nv_direct_write_with_attr: operation not allowed! key_id = 0x%x\r\n", key_id);\r
-            osal_sem_up(&nv_sem);\r
-            return ERRCODE_NV_ILLEGAL_OPERATION;\r
-        }\r
-    }\r
-    if (attr != NULL) {\r
-        attribute = (uint8_t)nv_helper_convert_key_attr(attr);\r
-    }\r
-    task_node.state_code = FLASH_TASK_READY;\r
-    task_node.data.kv.key = key_id;\r
-    task_node.data.kv.kvalue = kvalue;\r
-    task_node.data.kv.kvalue_length = kvalue_length;\r
-    task_node.data.kv.force_write = false;\r
-    task_node.data.kv.attribute = attribute;\r
-    ret = kv_update_write_key(KV_STORE_APPLICATION, &task_node);\r
-    osal_sem_up(&nv_sem);\r
-    if (ret != ERRCODE_SUCC) {\r
-        nv_log_err("[NV] nv_direct_write_with_attr failed. key_id = 0x%x, ret = 0x%x\r\n", key_id, ret);\r
-        return ret;\r
-    }\r
-#if (CONFIG_NV_SUPPORT_CHANGE_NOTIFY == NV_YES)\r
-    nv_change_notify(key_id);\r
-#endif\r
-    return ERRCODE_SUCC;\r
-}\r
-\r
-#ifdef CONFIG_NV_SUPPORT_WRITE_FORCE\r
-errcode_t nv_direct_write_force(uint16_t key_id, const uint8_t *kvalue, uint16_t kvalue_length)\r
-{\r
-    errcode_t ret;\r
-    flash_task_node task_node = {0};\r
-    uint16_t len;\r
-    kv_attributes_t attribute = 0;\r
-\r
-    if (kvalue_length > NV_NORMAL_KVALUE_MAX_LEN) {\r
-        return ERRCODE_NV_NO_ENOUGH_SPACE;\r
-    }\r
-\r
-    if (osal_sem_down_timeout(&nv_sem, 0xFFFFFFFF) != ERRCODE_SUCC) {\r
-        return ERRCODE_NV_SEM_WAIT_ERR;\r
-    }\r
-\r
-    ret = kv_store_get_key_attr(KV_STORE_APPLICATION, key_id, &len, &attribute);\r
-    if (ret == ERRCODE_SUCC) {\r
-        if (((uint32_t)attribute & NV_ATTRIBUTE_ENCRYPTED) != 0) {\r
-            /* When old key is encrypted, not permit to write */\r
-            osal_sem_up(&nv_sem);\r
-            return ERRCODE_NV_ILLEGAL_OPERATION;\r
-        }\r
-    }\r
-\r
-    task_node.state_code = FLASH_TASK_READY;\r
-    task_node.data.kv.key = key_id;\r
-    task_node.data.kv.kvalue = kvalue;\r
-    task_node.data.kv.kvalue_length = kvalue_length;\r
-    task_node.data.kv.force_write = true;\r
-    task_node.data.kv.attribute = (uint8_t)NV_ATTRIBUTE_NORMAL;\r
-    ret = kv_update_write_key(KV_STORE_APPLICATION, &task_node);\r
-    osal_sem_up(&nv_sem);\r
-    if (ret != ERRCODE_SUCC) {\r
-        return ret;\r
-    }\r
-#if (CONFIG_NV_SUPPORT_CHANGE_NOTIFY == NV_YES)\r
-    nv_change_notify(key_id);\r
-#endif\r
-    return ERRCODE_SUCC;\r
-}\r
-#endif\r
-\r
-errcode_t nv_direct_get_key_data(\r
-    uint16_t key_id, uint16_t kvalue_max_length, uint16_t *kvalue_length, uint8_t *kvalue, nv_key_attr_t *attr)\r
-{\r
-    kv_attributes_t data_attribute = 0;\r
-\r
-    if (osal_sem_down_timeout(&nv_sem, 0xFFFFFFFF) != ERRCODE_SUCC) {\r
-        return ERRCODE_NV_SEM_WAIT_ERR;\r
-    }\r
-\r
-    kv_store_key_data_t key_data = {kvalue_max_length, 0, kvalue};\r
-    errcode_t ret_val = kv_store_get_key(KV_STORE_APPLICATION, key_id, &key_data, &data_attribute);\r
-    /* 如果在工作区没有找到该数据,可能存在数据被破坏情况,去备份区去找该数据 */\r
-    if (ret_val != ERRCODE_SUCC) {\r
-        ret_val = kv_store_read_backup_key(key_id, &key_data, &data_attribute);\r
-    }\r
-\r
-    if (ret_val == ERRCODE_SUCC) {\r
-        if (((uint32_t)data_attribute & NV_ATTRIBUTE_PERMANENT) != 0) {\r
-            attr->permanent = true;\r
-            attr->non_upgrade = true;\r
-        }\r
-        if (((uint32_t)data_attribute & NV_ATTRIBUTE_ENCRYPTED) != 0) {\r
-            attr->encrypted = true;\r
-            attr->non_upgrade = true;\r
-        }\r
-        if (((uint32_t)data_attribute & NV_ATTRIBUTE_NON_UPGRADE) != 0) {\r
-            attr->non_upgrade = true;\r
-        }\r
-    }\r
-\r
-    *kvalue_length = key_data.kvalue_actual_length;\r
-    osal_sem_up(&nv_sem);\r
-    return ret_val;\r
-}\r
-\r
-#ifdef CONFIG_NV_SUPPORT_UPDATE_ATTR\r
-errcode_t nv_direct_update_key_attr(uint16_t key_id, nv_key_attr_t *attr, nv_storage_completed_callback func)\r
-{\r
-    errcode_t ret_val;\r
-    flash_task_node task_node = {0};\r
-    uint16_t len;\r
-    kv_attributes_t attribute = 0;\r
-    nv_key_attr_t new_attr = {0};\r
-    unused(func);\r
-\r
-    memcpy_s(&new_attr, sizeof(nv_key_attr_t), attr, sizeof(nv_key_attr_t));\r
-    if (osal_sem_down_timeout(&nv_sem, 0xFFFFFFFF) != ERRCODE_SUCC) {\r
-        return ERRCODE_NV_SEM_WAIT_ERR;\r
-    }\r
-\r
-    ret_val = kv_store_get_key_attr(KV_STORE_APPLICATION, key_id, &len, &attribute);\r
-    if (ret_val != ERRCODE_SUCC) {\r
-        osal_sem_up(&nv_sem);\r
-        return ret_val;\r
-    }\r
-\r
-    if (((uint32_t)attribute & NV_ATTRIBUTE_PERMANENT) != 0) {\r
-        osal_sem_up(&nv_sem);\r
-        return ERRCODE_SUCC;\r
-    }\r
-\r
-    if (((uint32_t)attribute & NV_ATTRIBUTE_ENCRYPTED) != 0) {\r
-        /* if old key is encrypted, the new key must be encrypted too */\r
-        new_attr.encrypted = true;\r
-    }\r
-\r
-    task_node.state_code = FLASH_TASK_READY;\r
-    task_node.data.kv_attribute.key = key_id;\r
-    task_node.data.kv_attribute.attribute = (uint8_t)nv_helper_convert_key_attr(&new_attr);\r
-    ret_val = kv_update_modify_attribute(KV_STORE_APPLICATION, &task_node);\r
-    osal_sem_up(&nv_sem);\r
-    return ret_val;\r
-}\r
-#endif\r
-\r
-#ifdef CONFIG_NV_SUPPORT_DELETE_KEY\r
-errcode_t nv_direct_erase(uint16_t key_id)\r
-{\r
-    errcode_t ret_val;\r
-    uint16_t len = 0;\r
-    kv_attributes_t attribute = 0;\r
-    flash_task_node task_node = {0};\r
-    if (osal_sem_down_timeout(&nv_sem, 0xFFFFFFFF) != ERRCODE_SUCC) {\r
-        return ERRCODE_NV_SEM_WAIT_ERR;\r
-    }\r
-\r
-    ret_val = kv_store_get_key_attr(KV_STORE_APPLICATION, key_id, &len, &attribute);\r
-    if (ret_val != ERRCODE_SUCC) {\r
-        osal_sem_up(&nv_sem);\r
-        return ret_val;\r
-    }\r
-\r
-    if (((uint32_t)attribute & KV_ATTRIBUTE_PERMANENT) != 0) {\r
-        osal_sem_up(&nv_sem);\r
-        return ERRCODE_NV_ILLEGAL_OPERATION;\r
-    }\r
-\r
-    task_node.data.kv_erase.key = key_id;\r
-    ret_val = kv_update_erase_key(KV_STORE_APPLICATION, &task_node);\r
-    osal_sem_up(&nv_sem);\r
-    return ret_val;\r
-}\r
-#endif\r
-\r
-errcode_t nv_direct_get_store_status(nv_store_status_t *status)\r
-{\r
-    errcode_t ret_val = ERRCODE_FAIL;\r
-    if (osal_sem_down_timeout(&nv_sem, 0xFFFFFFFF) != ERRCODE_SUCC) {\r
-        return ERRCODE_NV_SEM_WAIT_ERR;\r
-    }\r
-\r
-    memset_s(status, sizeof(nv_store_status_t), 0, sizeof(nv_store_status_t));\r
-    ret_val = kv_store_get_status(KV_STORE_APPLICATION, status);\r
-    osal_sem_up(&nv_sem);\r
-    return ret_val;\r
-}\r
-\r
-errcode_t nv_direct_stored(uint16_t key_id, uint16_t kvalue_length, const uint8_t *kvalue)\r
-{\r
-    errcode_t ret = ERRCODE_SUCC;\r
-    uint8_t *stored_kvalue = NULL;\r
-    kv_attributes_t attribute = 0;\r
-\r
-    if (kvalue_length > NV_NORMAL_KVALUE_MAX_LEN) {\r
-        return ERRCODE_NV_NO_ENOUGH_SPACE;\r
-    }\r
-\r
-    stored_kvalue = (uint8_t *)(uintptr_t)kv_malloc(kvalue_length);\r
-    if (stored_kvalue == NULL) {\r
-        return ERRCODE_MALLOC;\r
-    }\r
-\r
-    if (osal_sem_down_timeout(&nv_sem, 0xFFFFFFFF) != ERRCODE_SUCC) {\r
-        kv_free(stored_kvalue);\r
-        return ERRCODE_NV_SEM_WAIT_ERR;\r
-    }\r
-\r
-    kv_store_key_data_t key_data = {kvalue_length, 0, stored_kvalue};\r
-    if (kv_store_get_key(KV_STORE_APPLICATION, key_id, &key_data, &attribute) != ERRCODE_SUCC) {\r
-        ret = ERRCODE_FAIL;\r
-    } else if ((key_data.kvalue_actual_length != kvalue_length) ||\r
-               (memcmp((void *)stored_kvalue, (void *)kvalue, kvalue_length) != 0)) {\r
-        ret = ERRCODE_FAIL;\r
-    }\r
-    osal_sem_up(&nv_sem);\r
-    kv_free(stored_kvalue);\r
-    return ret;\r
-}\r
-\r
-errcode_t nv_direct_backup_keys(const nv_backup_mode_t *backup_mode)\r
-{\r
-#if (CONFIG_NV_SUPPORT_BACKUP_RESTORE == NV_YES)\r
-    errcode_t ret;\r
-\r
-#if (CONFIG_NV_SUPPORT_ASYNCHRONOUS_STORE == NV_YES)\r
-    /* 保证备份前,NV消息队列中数据写入flash */\r
-    ret = uapi_nv_flush();\r
-    if (ret != ERRCODE_SUCC) {\r
-        return ret;\r
-    }\r
-#endif\r
-\r
-    if (osal_sem_down_timeout(&nv_sem, 0xFFFFFFFF) != ERRCODE_SUCC) {\r
-        return ERRCODE_NV_SEM_WAIT_ERR;\r
-    }\r
-\r
-    ret = kv_restore_set_region_flag(backup_mode->region_mode);\r
-    if (ret != ERRCODE_SUCC) {\r
-        osal_sem_up(&nv_sem);\r
-        return ret;\r
-    }\r
-    ret = kv_backup_delete_repeat_key();\r
-    if (ret != ERRCODE_SUCC) {\r
-        osal_sem_up(&nv_sem);\r
-        return ret;\r
-    }\r
-    ret = kv_backup_write_key();\r
-    osal_sem_up(&nv_sem);\r
-    return ret;\r
-#else\r
-    unused(backup_mode);\r
-    return ERRCODE_NOT_SUPPORT;\r
-#endif\r
-}\r
-\r
-errcode_t nv_direct_set_restore_flag_all(void)\r
-{\r
-#if (CONFIG_NV_SUPPORT_BACKUP_RESTORE == NV_YES)\r
-    nv_reset_mode_t nv_reset_mode = {0};\r
-    nv_reset_mode.mode = RESET_MODE_A;\r
-    return kv_enable_restore_flag(&nv_reset_mode);\r
-\r
-#else\r
-    return ERRCODE_NOT_SUPPORT;\r
-#endif\r
-}\r
-\r
-errcode_t nv_direct_set_restore_flag_partitial(const nv_restore_mode_t *nv_restore_mode)\r
-{\r
-#if (CONFIG_NV_SUPPORT_BACKUP_RESTORE == NV_YES)\r
-    if (nv_restore_mode == NULL) {\r
-        return ERRCODE_NV_INVALID_PARAMS;\r
-    }\r
-    nv_reset_mode_t nv_reset_mode = {0};\r
-    if (memcpy_s(nv_reset_mode.region_flag, KEY_ID_REGION_MAX_NUM, nv_restore_mode, KEY_ID_REGION_MAX_NUM) != EOK) {\r
-        return ERRCODE_MEMCPY;\r
-    }\r
-    nv_reset_mode.mode = RESET_MODE_B;\r
-    return kv_enable_restore_flag(&nv_reset_mode);\r
-#else\r
-    unused(nv_restore_mode);\r
-    return ERRCODE_NOT_SUPPORT;\r
-#endif\r
-}\r
-\r
-#if (CONFIG_NV_SUPPORT_CHANGE_NOTIFY == NV_YES)\r
-errcode_t nv_direct_add_func_to_notify_list(uint16_t min_key, uint16_t max_key, nv_changed_notify_func func)\r
-{\r
-    nv_direct_ctrl_t *nv_ctrl = nv_direct_get_nv_ctrl();\r
-    if (osal_sem_down_timeout(&nv_sem, 0xFFFFFFFF) != ERRCODE_SUCC) {\r
-        return ERRCODE_NV_SEM_WAIT_ERR;\r
-    }\r
-\r
-    nv_changed_proc_t *notify_list = nv_ctrl->nv_change_notify_list;\r
-    if (notify_list == NULL) {\r
-        osal_sem_up(&nv_sem);\r
-        return ERRCODE_NV_NOT_INITIALISED;\r
-    }\r
-\r
-    if (nv_ctrl->notify_registered_nums >= nv_ctrl->notify_regitser_max_nums) {\r
-        osal_sem_up(&nv_sem);\r
-        return ERRCODE_NV_NOTIFY_LIST_FULL;\r
-    }\r
-\r
-    if (!nv_change_notify_segment_is_valid(nv_ctrl, min_key, max_key)) {\r
-        osal_sem_up(&nv_sem);\r
-        return ERRCODE_NV_NOTIFY_SEGMENT_ERR;\r
-    }\r
-\r
-    uint8_t new_index = nv_ctrl->notify_registered_nums;\r
-    notify_list[new_index].min_key = min_key;\r
-    notify_list[new_index].max_key = max_key;\r
-    notify_list[new_index].func = func;\r
-    nv_ctrl->notify_registered_nums++;\r
-    osal_sem_up(&nv_sem);\r
-    return ERRCODE_SUCC;\r
-}\r
-#endif\r
-\r
-void nv_direct_ctrl_init(void)\r
-{\r
-    (void)kv_update_init((cores_t)KV_STORE_APPLICATION);\r
-    nv_direct_ctrl_t *nv_ctrl = nv_direct_get_nv_ctrl();\r
-    memset_s(nv_ctrl, sizeof(nv_direct_ctrl_t), 0, sizeof(nv_direct_ctrl_t));\r
-    if (osal_sem_binary_sem_init(&nv_sem, MAX_BINARY_VAL) != ERRCODE_SUCC) {\r
-        return;\r
-    }\r
-#if (CONFIG_NV_SUPPORT_CHANGE_NOTIFY == NV_YES)\r
-    (void)nv_direct_notify_list_init();\r
-#endif\r
-#if (CONFIG_NV_SUPPORT_BACKUP_RESTORE == NV_YES)\r
-    (void)kv_update_backup_init();\r
-#endif\r
-#if (CONFIG_NV_SUPPORT_BACKUP_RESTORE == NV_YES)\r
-    (void)kv_restore_all_keys();\r
-#endif\r
-#if (CONFIG_NV_SUPPORT_ASYNCHRONOUS_STORE == NV_YES)\r
-    (void)nv_async_init(KV_STORE_APPLICATION, kv_store_get_page_count(KV_STORE_APPLICATION));\r
-#endif\r
-    nv_log_info("nv init success!\r\n");\r
-}\r
+/*
+ * Copyright (c) @CompanyNameMagicTag 2016-2022. All rights reserved.
+ * Description: SOC KEY VALUE STORAGE IMPLEMENTATION
+ */
+
+#include "nv.h"
+#include "nv_storage.h"
+#include "nv_store.h"
+#include "nv_upg.h"
+#include "securec.h"
+#include "nv_porting.h"
+#include "common_def.h"
+#include "nv_reset.h"
+#include "nv_async_store.h"
+#include "osal_semaphore.h"
+#include "nv_update.h"
+#include "nv_notify.h"
+#include "nv_task_adapt.h"
+#include "nv_storage_handle.h"
+
+osal_semaphore nv_sem;
+#define MAX_BINARY_VAL 1
+
+STATIC nv_attributes_t nv_helper_convert_key_attr(const nv_key_attr_t *attr)
+{
+    nv_attributes_t attribute = NV_ATTRIBUTE_NORMAL;
+    bool is_support_crypt = false;
+    if (attr == NULL) {
+        return attribute;
+    }
+
+#if (CONFIG_NV_SUPPORT_ENCRYPT == NV_YES)
+    is_support_crypt = attr->encrypted;
+#endif
+
+    if (attr->permanent && is_support_crypt) {
+        attribute = NV_ATTRIBUTE_ENCRYPTED | NV_ATTRIBUTE_PERMANENT | NV_ATTRIBUTE_NON_UPGRADE;
+    } else if (attr->permanent) {
+        attribute = NV_ATTRIBUTE_PERMANENT | NV_ATTRIBUTE_NON_UPGRADE;
+    } else if (is_support_crypt) {
+        attribute = NV_ATTRIBUTE_ENCRYPTED | NV_ATTRIBUTE_NON_UPGRADE;
+    } else if (attr->non_upgrade) {
+        attribute = NV_ATTRIBUTE_NON_UPGRADE;
+    }
+    return attribute;
+}
+
+static uint16_t nv_storage_max_key_space(const nv_key_attr_t *attr)
+{
+    if (attr == NULL) {
+        return NV_NORMAL_KVALUE_MAX_LEN;
+    }
+    return (attr->encrypted ? NV_ENCRYPTED_KVALUE_MAX_LEN : NV_NORMAL_KVALUE_MAX_LEN);
+}
+
+nv_direct_ctrl_t g_nv_direct_ctrl;
+nv_direct_ctrl_t *nv_direct_get_nv_ctrl(void)
+{
+    return &g_nv_direct_ctrl;
+}
+
+errcode_t nv_direct_get_key_attr(uint16_t key_id, uint16_t *len, nv_key_attr_t *attr)
+{
+    kv_attributes_t get_attribute = 0;
+    errcode_t ret = ERRCODE_SUCC;
+
+    if (len == NULL || attr == NULL) {
+        return ERRCODE_NV_INVALID_PARAMS;
+    }
+
+    if (osal_sem_down_timeout(&nv_sem, 0xFFFFFFFF) != ERRCODE_SUCC) {
+        return ERRCODE_NV_SEM_WAIT_ERR;
+    }
+
+    *len = 0;
+    memset_s(attr, sizeof(nv_key_attr_t), 0, sizeof(nv_key_attr_t));
+    ret = kv_store_get_key_attr(KV_STORE_APPLICATION, key_id, len, &get_attribute);
+    if (ret == ERRCODE_SUCC) {
+        if (((uint32_t)get_attribute & NV_ATTRIBUTE_PERMANENT) != 0) {
+            attr->permanent = true;
+            attr->non_upgrade = true;
+        }
+        if (((uint32_t)get_attribute & NV_ATTRIBUTE_ENCRYPTED) != 0) {
+            attr->encrypted = true;
+            attr->non_upgrade = true;
+        }
+        if (((uint32_t)get_attribute & NV_ATTRIBUTE_NON_UPGRADE) != 0) {
+            attr->non_upgrade = true;
+        }
+    }
+    osal_sem_up(&nv_sem);
+    return ret;
+}
+
+errcode_t nv_direct_write_with_attr(uint16_t key_id, const uint8_t *kvalue, uint16_t kvalue_length, nv_key_attr_t *attr,
+    nv_storage_completed_callback func)
+{
+    errcode_t ret;
+    flash_task_node task_node = {0};
+    uint16_t len;
+    kv_attributes_t attribute = (kv_attributes_t)0;
+    unused(func);
+
+    if (kvalue_length > nv_storage_max_key_space(attr)) {
+        nv_log_err("[NV] nv_direct_write_with_attr: len exceeds the max size. key_id = 0x%x\r\n", key_id);
+        return ERRCODE_NV_NO_ENOUGH_SPACE;
+    }
+
+    if (osal_sem_down_timeout(&nv_sem, 0xFFFFFFFF) != ERRCODE_SUCC) {
+        nv_log_err("[NV] nv_direct_write_with_attr: semaphore error!\r\n");
+        return ERRCODE_NV_SEM_WAIT_ERR;
+    }
+
+    ret = kv_store_get_key_attr(KV_STORE_APPLICATION, key_id, &len, &attribute);
+    if (ret == ERRCODE_SUCC) {
+        if ((((uint32_t)attribute & NV_ATTRIBUTE_PERMANENT) != 0) ||
+            ((((uint32_t)attribute & NV_ATTRIBUTE_ENCRYPTED) != 0) && (attr != NULL && attr->encrypted == false))
+            || ((((uint32_t)attribute & NV_ATTRIBUTE_NON_UPGRADE) != 0) && (attr == NULL))) {
+            /* When old key is permanent, not permit to write */
+            /* When old key is encrypted, new key is non-encrypted, not permit to write */
+            /* When old key is non upgrade, new key is write by ordinary write, not permit to write */
+            nv_log_err("[NV] nv_direct_write_with_attr: operation not allowed! key_id = 0x%x\r\n", key_id);
+            osal_sem_up(&nv_sem);
+            return ERRCODE_NV_ILLEGAL_OPERATION;
+        }
+    }
+    if (attr != NULL) {
+        attribute = (uint8_t)nv_helper_convert_key_attr(attr);
+    }
+    task_node.state_code = FLASH_TASK_READY;
+    task_node.data.kv.key = key_id;
+    task_node.data.kv.kvalue = kvalue;
+    task_node.data.kv.kvalue_length = kvalue_length;
+    task_node.data.kv.force_write = false;
+    task_node.data.kv.attribute = attribute;
+    ret = kv_update_write_key(KV_STORE_APPLICATION, &task_node);
+    osal_sem_up(&nv_sem);
+    if (ret != ERRCODE_SUCC) {
+        nv_log_err("[NV] nv_direct_write_with_attr failed. key_id = 0x%x, ret = 0x%x\r\n", key_id, ret);
+        return ret;
+    }
+#if (CONFIG_NV_SUPPORT_CHANGE_NOTIFY == NV_YES)
+    nv_change_notify(key_id);
+#endif
+    return ERRCODE_SUCC;
+}
+
+#ifdef CONFIG_NV_SUPPORT_WRITE_FORCE
+errcode_t nv_direct_write_force(uint16_t key_id, const uint8_t *kvalue, uint16_t kvalue_length)
+{
+    errcode_t ret;
+    flash_task_node task_node = {0};
+    uint16_t len;
+    kv_attributes_t attribute = 0;
+
+    if (kvalue_length > NV_NORMAL_KVALUE_MAX_LEN) {
+        return ERRCODE_NV_NO_ENOUGH_SPACE;
+    }
+
+    if (osal_sem_down_timeout(&nv_sem, 0xFFFFFFFF) != ERRCODE_SUCC) {
+        return ERRCODE_NV_SEM_WAIT_ERR;
+    }
+
+    ret = kv_store_get_key_attr(KV_STORE_APPLICATION, key_id, &len, &attribute);
+    if (ret == ERRCODE_SUCC) {
+        if (((uint32_t)attribute & NV_ATTRIBUTE_ENCRYPTED) != 0) {
+            /* When old key is encrypted, not permit to write */
+            osal_sem_up(&nv_sem);
+            return ERRCODE_NV_ILLEGAL_OPERATION;
+        }
+    }
+
+    task_node.state_code = FLASH_TASK_READY;
+    task_node.data.kv.key = key_id;
+    task_node.data.kv.kvalue = kvalue;
+    task_node.data.kv.kvalue_length = kvalue_length;
+    task_node.data.kv.force_write = true;
+    task_node.data.kv.attribute = (uint8_t)NV_ATTRIBUTE_NORMAL;
+    ret = kv_update_write_key(KV_STORE_APPLICATION, &task_node);
+    osal_sem_up(&nv_sem);
+    if (ret != ERRCODE_SUCC) {
+        return ret;
+    }
+#if (CONFIG_NV_SUPPORT_CHANGE_NOTIFY == NV_YES)
+    nv_change_notify(key_id);
+#endif
+    return ERRCODE_SUCC;
+}
+#endif
+
+errcode_t nv_direct_get_key_data(
+    uint16_t key_id, uint16_t kvalue_max_length, uint16_t *kvalue_length, uint8_t *kvalue, nv_key_attr_t *attr)
+{
+    kv_attributes_t data_attribute = 0;
+
+    if (osal_sem_down_timeout(&nv_sem, 0xFFFFFFFF) != ERRCODE_SUCC) {
+        return ERRCODE_NV_SEM_WAIT_ERR;
+    }
+
+    kv_store_key_data_t key_data = {kvalue_max_length, 0, kvalue};
+    errcode_t ret_val = kv_store_get_key(KV_STORE_APPLICATION, key_id, &key_data, &data_attribute);
+    /* 如果在工作区没有找到该数据,可能存在数据被破坏情况,去备份区去找该数据 */
+    if (ret_val != ERRCODE_SUCC) {
+        ret_val = kv_store_read_backup_key(key_id, &key_data, &data_attribute);
+    }
+
+    if (ret_val == ERRCODE_SUCC) {
+        if (((uint32_t)data_attribute & NV_ATTRIBUTE_PERMANENT) != 0) {
+            attr->permanent = true;
+            attr->non_upgrade = true;
+        }
+        if (((uint32_t)data_attribute & NV_ATTRIBUTE_ENCRYPTED) != 0) {
+            attr->encrypted = true;
+            attr->non_upgrade = true;
+        }
+        if (((uint32_t)data_attribute & NV_ATTRIBUTE_NON_UPGRADE) != 0) {
+            attr->non_upgrade = true;
+        }
+    }
+
+    *kvalue_length = key_data.kvalue_actual_length;
+    osal_sem_up(&nv_sem);
+    return ret_val;
+}
+
+#ifdef CONFIG_NV_SUPPORT_UPDATE_ATTR
+errcode_t nv_direct_update_key_attr(uint16_t key_id, nv_key_attr_t *attr, nv_storage_completed_callback func)
+{
+    errcode_t ret_val;
+    flash_task_node task_node = {0};
+    uint16_t len;
+    kv_attributes_t attribute = 0;
+    nv_key_attr_t new_attr = {0};
+    unused(func);
+
+    memcpy_s(&new_attr, sizeof(nv_key_attr_t), attr, sizeof(nv_key_attr_t));
+    if (osal_sem_down_timeout(&nv_sem, 0xFFFFFFFF) != ERRCODE_SUCC) {
+        return ERRCODE_NV_SEM_WAIT_ERR;
+    }
+
+    ret_val = kv_store_get_key_attr(KV_STORE_APPLICATION, key_id, &len, &attribute);
+    if (ret_val != ERRCODE_SUCC) {
+        osal_sem_up(&nv_sem);
+        return ret_val;
+    }
+
+    if (((uint32_t)attribute & NV_ATTRIBUTE_PERMANENT) != 0) {
+        osal_sem_up(&nv_sem);
+        return ERRCODE_SUCC;
+    }
+
+    if (((uint32_t)attribute & NV_ATTRIBUTE_ENCRYPTED) != 0) {
+        /* if old key is encrypted, the new key must be encrypted too */
+        new_attr.encrypted = true;
+    }
+
+    task_node.state_code = FLASH_TASK_READY;
+    task_node.data.kv_attribute.key = key_id;
+    task_node.data.kv_attribute.attribute = (uint8_t)nv_helper_convert_key_attr(&new_attr);
+    ret_val = kv_update_modify_attribute(KV_STORE_APPLICATION, &task_node);
+    osal_sem_up(&nv_sem);
+    return ret_val;
+}
+#endif
+
+#ifdef CONFIG_NV_SUPPORT_DELETE_KEY
+errcode_t nv_direct_erase(uint16_t key_id)
+{
+    errcode_t ret_val;
+    uint16_t len = 0;
+    kv_attributes_t attribute = 0;
+    flash_task_node task_node = {0};
+    if (osal_sem_down_timeout(&nv_sem, 0xFFFFFFFF) != ERRCODE_SUCC) {
+        return ERRCODE_NV_SEM_WAIT_ERR;
+    }
+
+    ret_val = kv_store_get_key_attr(KV_STORE_APPLICATION, key_id, &len, &attribute);
+    if (ret_val != ERRCODE_SUCC) {
+        osal_sem_up(&nv_sem);
+        return ret_val;
+    }
+
+    if (((uint32_t)attribute & KV_ATTRIBUTE_PERMANENT) != 0) {
+        osal_sem_up(&nv_sem);
+        return ERRCODE_NV_ILLEGAL_OPERATION;
+    }
+
+    task_node.data.kv_erase.key = key_id;
+    ret_val = kv_update_erase_key(KV_STORE_APPLICATION, &task_node);
+    osal_sem_up(&nv_sem);
+    return ret_val;
+}
+#endif
+
+errcode_t nv_direct_get_store_status(nv_store_status_t *status)
+{
+    errcode_t ret_val = ERRCODE_FAIL;
+    if (osal_sem_down_timeout(&nv_sem, 0xFFFFFFFF) != ERRCODE_SUCC) {
+        return ERRCODE_NV_SEM_WAIT_ERR;
+    }
+
+    memset_s(status, sizeof(nv_store_status_t), 0, sizeof(nv_store_status_t));
+    ret_val = kv_store_get_status(KV_STORE_APPLICATION, status);
+    osal_sem_up(&nv_sem);
+    return ret_val;
+}
+
+errcode_t nv_direct_stored(uint16_t key_id, uint16_t kvalue_length, const uint8_t *kvalue)
+{
+    errcode_t ret = ERRCODE_SUCC;
+    uint8_t *stored_kvalue = NULL;
+    kv_attributes_t attribute = 0;
+
+    if (kvalue_length > NV_NORMAL_KVALUE_MAX_LEN) {
+        return ERRCODE_NV_NO_ENOUGH_SPACE;
+    }
+
+    stored_kvalue = (uint8_t *)(uintptr_t)kv_malloc(kvalue_length);
+    if (stored_kvalue == NULL) {
+        return ERRCODE_MALLOC;
+    }
+
+    if (osal_sem_down_timeout(&nv_sem, 0xFFFFFFFF) != ERRCODE_SUCC) {
+        kv_free(stored_kvalue);
+        return ERRCODE_NV_SEM_WAIT_ERR;
+    }
+
+    kv_store_key_data_t key_data = {kvalue_length, 0, stored_kvalue};
+    if (kv_store_get_key(KV_STORE_APPLICATION, key_id, &key_data, &attribute) != ERRCODE_SUCC) {
+        ret = ERRCODE_FAIL;
+    } else if ((key_data.kvalue_actual_length != kvalue_length) ||
+               (memcmp((void *)stored_kvalue, (void *)kvalue, kvalue_length) != 0)) {
+        ret = ERRCODE_FAIL;
+    }
+    osal_sem_up(&nv_sem);
+    kv_free(stored_kvalue);
+    return ret;
+}
+
+errcode_t nv_direct_backup_keys(const nv_backup_mode_t *backup_mode)
+{
+#if (CONFIG_NV_SUPPORT_BACKUP_RESTORE == NV_YES)
+    errcode_t ret;
+
+#if (CONFIG_NV_SUPPORT_ASYNCHRONOUS_STORE == NV_YES)
+    /* 保证备份前,NV消息队列中数据写入flash */
+    ret = uapi_nv_flush();
+    if (ret != ERRCODE_SUCC) {
+        return ret;
+    }
+#endif
+
+    if (osal_sem_down_timeout(&nv_sem, 0xFFFFFFFF) != ERRCODE_SUCC) {
+        return ERRCODE_NV_SEM_WAIT_ERR;
+    }
+
+    ret = kv_restore_set_region_flag(backup_mode->region_mode);
+    if (ret != ERRCODE_SUCC) {
+        osal_sem_up(&nv_sem);
+        return ret;
+    }
+    ret = kv_backup_delete_repeat_key();
+    if (ret != ERRCODE_SUCC) {
+        osal_sem_up(&nv_sem);
+        return ret;
+    }
+    ret = kv_backup_write_key();
+    osal_sem_up(&nv_sem);
+    return ret;
+#else
+    unused(backup_mode);
+    return ERRCODE_NOT_SUPPORT;
+#endif
+}
+
+errcode_t nv_direct_set_restore_flag_all(void)
+{
+#if (CONFIG_NV_SUPPORT_BACKUP_RESTORE == NV_YES)
+    nv_reset_mode_t nv_reset_mode = {0};
+    nv_reset_mode.mode = RESET_MODE_A;
+    return kv_enable_restore_flag(&nv_reset_mode);
+
+#else
+    return ERRCODE_NOT_SUPPORT;
+#endif
+}
+
+errcode_t nv_direct_set_restore_flag_partitial(const nv_restore_mode_t *nv_restore_mode)
+{
+#if (CONFIG_NV_SUPPORT_BACKUP_RESTORE == NV_YES)
+    if (nv_restore_mode == NULL) {
+        return ERRCODE_NV_INVALID_PARAMS;
+    }
+    nv_reset_mode_t nv_reset_mode = {0};
+    if (memcpy_s(nv_reset_mode.region_flag, KEY_ID_REGION_MAX_NUM, nv_restore_mode, KEY_ID_REGION_MAX_NUM) != EOK) {
+        return ERRCODE_MEMCPY;
+    }
+    nv_reset_mode.mode = RESET_MODE_B;
+    return kv_enable_restore_flag(&nv_reset_mode);
+#else
+    unused(nv_restore_mode);
+    return ERRCODE_NOT_SUPPORT;
+#endif
+}
+
+#if (CONFIG_NV_SUPPORT_CHANGE_NOTIFY == NV_YES)
+errcode_t nv_direct_add_func_to_notify_list(uint16_t min_key, uint16_t max_key, nv_changed_notify_func func)
+{
+    nv_direct_ctrl_t *nv_ctrl = nv_direct_get_nv_ctrl();
+    if (osal_sem_down_timeout(&nv_sem, 0xFFFFFFFF) != ERRCODE_SUCC) {
+        return ERRCODE_NV_SEM_WAIT_ERR;
+    }
+
+    nv_changed_proc_t *notify_list = nv_ctrl->nv_change_notify_list;
+    if (notify_list == NULL) {
+        osal_sem_up(&nv_sem);
+        return ERRCODE_NV_NOT_INITIALISED;
+    }
+
+    if (nv_ctrl->notify_registered_nums >= nv_ctrl->notify_regitser_max_nums) {
+        osal_sem_up(&nv_sem);
+        return ERRCODE_NV_NOTIFY_LIST_FULL;
+    }
+
+    if (!nv_change_notify_segment_is_valid(nv_ctrl, min_key, max_key)) {
+        osal_sem_up(&nv_sem);
+        return ERRCODE_NV_NOTIFY_SEGMENT_ERR;
+    }
+
+    uint8_t new_index = nv_ctrl->notify_registered_nums;
+    notify_list[new_index].min_key = min_key;
+    notify_list[new_index].max_key = max_key;
+    notify_list[new_index].func = func;
+    nv_ctrl->notify_registered_nums++;
+    osal_sem_up(&nv_sem);
+    return ERRCODE_SUCC;
+}
+#endif
+
+void nv_direct_ctrl_init(void)
+{
+    (void)kv_update_init((cores_t)KV_STORE_APPLICATION);
+    nv_direct_ctrl_t *nv_ctrl = nv_direct_get_nv_ctrl();
+    memset_s(nv_ctrl, sizeof(nv_direct_ctrl_t), 0, sizeof(nv_direct_ctrl_t));
+    if (osal_sem_binary_sem_init(&nv_sem, MAX_BINARY_VAL) != ERRCODE_SUCC) {
+        return;
+    }
+#if (CONFIG_NV_SUPPORT_CHANGE_NOTIFY == NV_YES)
+    (void)nv_direct_notify_list_init();
+#endif
+#if (CONFIG_NV_SUPPORT_BACKUP_RESTORE == NV_YES)
+    (void)kv_update_backup_init();
+#endif
+#if (CONFIG_NV_SUPPORT_BACKUP_RESTORE == NV_YES)
+    (void)kv_restore_all_keys();
+#endif
+#if (CONFIG_NV_SUPPORT_ASYNCHRONOUS_STORE == NV_YES)
+    (void)nv_async_init(KV_STORE_APPLICATION, kv_store_get_page_count(KV_STORE_APPLICATION));
+#endif
+    nv_log_info("nv init success!\r\n");
+}
index 0523b23..cca261f 100644 (file)
@@ -1,20 +1,20 @@
-/*\r
- * Copyright (c) @CompanyNameMagicTag 2023-2023. All rights reserved.\r
- * Description: NV Storage Library debug\r
- */\r
-\r
-#include "nv_debug.h"\r
-#include "nv_porting.h"\r
-#include "common_def.h"\r
-\r
-STATIC uint32_t g_nv_debug_level = NV_LOG_LEVEL_INFO;\r
-\r
-uint32_t nv_get_debug_level(void)\r
-{\r
-    return g_nv_debug_level;\r
-}\r
-\r
-void nv_set_debug_level(uint32_t level)\r
-{\r
-    g_nv_debug_level = level;\r
-}\r
+/*
+ * Copyright (c) @CompanyNameMagicTag 2023-2023. All rights reserved.
+ * Description: NV Storage Library debug
+ */
+
+#include "nv_debug.h"
+#include "nv_porting.h"
+#include "common_def.h"
+
+STATIC uint32_t g_nv_debug_level = NV_LOG_LEVEL_DBG;//NV_LOG_LEVEL_INFO;
+
+uint32_t nv_get_debug_level(void)
+{
+    return g_nv_debug_level;
+}
+
+void nv_set_debug_level(uint32_t level)
+{
+    g_nv_debug_level = level;
+}
index bcb9f4b..5265e3f 100644 (file)
@@ -1,37 +1,37 @@
-/*\r
- * Copyright (c) @CompanyNameMagicTag 2019-2023. All rights reserved.\r
- * Description: NV Storage Library debug\r
- */\r
-\r
-#ifndef NV_DEBUG_H\r
-#define NV_DEBUG_H\r
-\r
-#include "stdint.h"\r
-#include "errcode.h"\r
-\r
-#ifdef __cplusplus\r
-#if __cplusplus\r
-extern "C" {\r
-#endif /* __cplusplus */\r
-#endif /* __cplusplus */\r
-\r
-#define NV_LOG_LEVEL_ALERT    0\r
-#define NV_LOG_LEVEL_FATAL    1\r
-#define NV_LOG_LEVEL_ERROR    2\r
-#define NV_LOG_LEVEL_WARN     3\r
-#define NV_LOG_LEVEL_NOTICE   4\r
-#define NV_LOG_LEVEL_INFO     5\r
-#define NV_LOG_LEVEL_DBG      6\r
-#define NV_LOG_LEVEL_TRACE    7\r
-\r
-uint32_t nv_get_debug_level(void);\r
-\r
-void nv_set_debug_level(uint32_t level);\r
-\r
-#ifdef __cplusplus\r
-#if __cplusplus\r
-}\r
-#endif /* __cplusplus */\r
-#endif /* __cplusplus */\r
-\r
-#endif /* NV_DEBUG_H */\r
+/*
+ * Copyright (c) @CompanyNameMagicTag 2019-2023. All rights reserved.
+ * Description: NV Storage Library debug
+ */
+
+#ifndef NV_DEBUG_H
+#define NV_DEBUG_H
+
+#include "stdint.h"
+#include "errcode.h"
+
+#ifdef __cplusplus
+#if __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+#define NV_LOG_LEVEL_ALERT    0
+#define NV_LOG_LEVEL_FATAL    1
+#define NV_LOG_LEVEL_ERROR    2
+#define NV_LOG_LEVEL_WARN     3
+#define NV_LOG_LEVEL_NOTICE   4
+#define NV_LOG_LEVEL_INFO     5
+#define NV_LOG_LEVEL_DBG      6
+#define NV_LOG_LEVEL_TRACE    7
+
+uint32_t nv_get_debug_level(void);
+
+void nv_set_debug_level(uint32_t level);
+
+#ifdef __cplusplus
+#if __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+#endif /* NV_DEBUG_H */
index df44bae..01cea33 100755 (executable)
-/*\r
- * Copyright (c) @CompanyNameMagicTag 2019-2022. All rights reserved.\r
- * Description: KV Storage Library key access module implementation\r
- */\r
-\r
-#include "nv_key.h"\r
-#include "string.h"\r
-#include "nv_porting.h"\r
-#include "uapi_crc.h"\r
-#include "nv_nvregion.h"\r
-#include "common_def.h"\r
-\r
-#define KV_CLEARTEXT_PADDING_SIZE       (1UL << 2)   /* Currently these both need to be a power of 2... */\r
-#define KV_CIPHERTEXT_PADDING_SIZE      (1UL << 4)   /* ...due to implementation of kv_padded_length    */\r
-#define kv_padded_length(d, s)          (((d) + ((s) - 1)) & ~((s) - 1))\r
-#define kv_padded_cleartext_length(d)   kv_padded_length(d, KV_CLEARTEXT_PADDING_SIZE)\r
-#define kv_padded_ciphertext_length(d)  kv_padded_length(d, KV_CIPHERTEXT_PADDING_SIZE)\r
-#define KV_DMA_COPY_SIZE_ALIGN          32\r
-\r
-uint8_t g_nv_header_magic = KV_KEY_MAGIC;\r
-\r
-/* IOT-16672 Use ROM Lib function instead (enhanced to support KV requirements, as here) */\r
-errcode_t kv_key_helper_copy_flash(uint32_t dest_location, uint32_t src_location, uint16_t length)\r
-{\r
-    if (length == 0) {\r
-        return ERRCODE_NV_ZERO_LENGTH_COPY;\r
-    }\r
-    uint32_t src_addr = src_location - FLASH_PHYSICAL_ADDR_START;\r
-    uint16_t length_rounded = length & ~(KV_DMA_COPY_SIZE_ALIGN - 1);\r
-    uint16_t length_remainder = length & (KV_DMA_COPY_SIZE_ALIGN - 1);\r
-    uint16_t dest_offset = 0;\r
-    while (length_rounded > 0) {\r
-        if (kv_flash_read((uint32_t)(uintptr_t)src_addr, KV_DMA_COPY_SIZE_ALIGN,\r
-            (uint8_t *)(uintptr_t)(dest_location + dest_offset)) != ERRCODE_SUCC) {\r
-            return ERRCODE_NV_READ_FLASH_ERR;\r
-        }\r
-        dest_offset += KV_DMA_COPY_SIZE_ALIGN;\r
-        src_addr += KV_DMA_COPY_SIZE_ALIGN;\r
-        length_rounded -= KV_DMA_COPY_SIZE_ALIGN;\r
-    }\r
-\r
-    if (length_remainder > 0) {\r
-        if (kv_flash_read((uint32_t)(uintptr_t)src_addr, length_remainder,\r
-            (uint8_t *)(uintptr_t)(dest_location + dest_offset)) != ERRCODE_SUCC) {\r
-            return ERRCODE_NV_READ_FLASH_ERR;\r
-        }\r
-    }\r
-    return ERRCODE_SUCC;\r
-}\r
-\r
-#ifdef CONFIG_NV_SUPPORT_SINGLE_CORE_SYSTEM\r
-errcode_t kv_key_direct_write_flash(uint32_t dest, uint32_t length, const uint8_t *src)\r
-{\r
-    uint32_t dest_w = dest;\r
-    if ((dest >= FLASH_PHYSICAL_ADDR_START) &&\r
-            ((dest + length) <= FLASH_PHYSICAL_ADDR_END)) {\r
-        dest_w -= FLASH_PHYSICAL_ADDR_START;\r
-    } else {\r
-        return ERRCODE_FLASH_INVALID_PARAM_BEYOND_ADDR;\r
-    }\r
-\r
-    if (kv_flash_write(dest_w, length, src, false) != ERRCODE_SUCC) {\r
-        return ERRCODE_NV_READ_FLASH_ERR;\r
-    }\r
-\r
-    return ERRCODE_SUCC;\r
-}\r
-\r
-errcode_t kv_key_direct_erase_flash(uint32_t dest, const uint32_t size)\r
-{\r
-    uint32_t dest_w = dest;\r
-    if ((dest >= FLASH_PHYSICAL_ADDR_START) &&\r
-            ((dest + size) <= FLASH_PHYSICAL_ADDR_END)) {\r
-        dest_w -= FLASH_PHYSICAL_ADDR_START;\r
-    } else {\r
-        return ERRCODE_FLASH_INVALID_PARAM_BEYOND_ADDR;\r
-    }\r
-\r
-    if (kv_flash_erase(dest_w, size) != ERRCODE_SUCC) {\r
-        return ERRCODE_FAIL;\r
-    }\r
-\r
-    return ERRCODE_SUCC;\r
-}\r
-#endif\r
-\r
-errcode_t kv_key_write_flash(uint32_t dest, uint32_t length, const uint8_t *src)\r
-{\r
-#ifdef CONFIG_NV_SUPPORT_SINGLE_CORE_SYSTEM\r
-    return kv_key_direct_write_flash(dest, length, src);\r
-#else\r
-    return flash_task_drv_write(dest, length, src);\r
-#endif\r
-}\r
-\r
-errcode_t kv_key_erase_flash(uint32_t dest, const uint32_t size)\r
-{\r
-#ifdef CONFIG_NV_SUPPORT_SINGLE_CORE_SYSTEM\r
-    return kv_key_direct_erase_flash(dest, size);\r
-#else\r
-    return flash_task_drv_erase(dest, size);\r
-#endif\r
-}\r
-\r
-#if (CONFIG_NV_SUPPORT_ENCRYPT == NV_YES)\r
-STATIC errcode_t kv_key_decode_flash(uintptr_t dest, const uintptr_t src, uint32_t length, uint32_t crypto_handle)\r
-{\r
-    errcode_t ret;\r
-    uint8_t *kv_padded_data = NULL;\r
-\r
-    uint32_t padded_length = kv_key_padded_data_length(KV_ATTRIBUTE_ENCRYPTED, (uint16_t)length);\r
-    if (padded_length == length) {\r
-        ret = kv_key_helper_copy_flash((uint32_t)dest, (uint32_t)src, (uint16_t)length);\r
-        if (ret == ERRCODE_SUCC) {\r
-            return nv_crypto_decode(crypto_handle, dest, dest, length);\r
-        } else {\r
-            return ret;\r
-        }\r
-    } else {\r
-        kv_padded_data = (uint8_t *)kv_malloc(padded_length);\r
-        if (kv_padded_data == NULL) {\r
-            return ERRCODE_MALLOC;\r
-        }\r
-        ret = kv_key_helper_copy_flash((uint32_t)(uintptr_t)kv_padded_data, (uint32_t)(uintptr_t)src,\r
-            (uint16_t)padded_length);\r
-        if (ret != ERRCODE_SUCC) {\r
-            goto end;\r
-        }\r
-        ret = nv_crypto_decode(crypto_handle, (uintptr_t)kv_padded_data, (uintptr_t)kv_padded_data, padded_length);\r
-        if (ret != ERRCODE_SUCC) {\r
-            goto end;\r
-        }\r
-        if (memcpy_s((void *)dest, length, kv_padded_data, length) != EOK) {\r
-            ret = ERRCODE_MEMCPY;\r
-            goto end;\r
-        }\r
-    }\r
-end:\r
-    kv_free(kv_padded_data);\r
-    return ret;\r
-}\r
-#endif\r
-\r
-STATIC errcode_t kv_key_read_data_from_flash(uintptr_t dest, const uintptr_t src, uint32_t length,\r
-    uint32_t crypto_handle)\r
-{\r
-    if (crypto_handle == INVAILD_CRYPTO_HANDLE) {\r
-        /* Decrypt not required, just return */\r
-        return kv_key_helper_copy_flash((uint32_t)dest, (uint32_t)src, (uint16_t)length);\r
-    } else {\r
-        /* Data needs decrypting */\r
-#if (CONFIG_NV_SUPPORT_ENCRYPT == NV_YES)\r
-        return kv_key_decode_flash(dest, src, length, crypto_handle);\r
-#else\r
-        return ERRCODE_FAIL;\r
-#endif\r
-    }\r
-}\r
-\r
-errcode_t kv_key_read_data(kv_key_handle_t *key, uint8_t *dest_location)\r
-{\r
-    errcode_t res = ERRCODE_SUCC;\r
-    uint32_t crypto_handle = INVAILD_CRYPTO_HANDLE;\r
-    uint32_t key_data_offset = 0;\r
-    uint32_t key_data_location = (uint32_t)(uintptr_t)key->key_location + (uint32_t)sizeof(kv_key_header_t);\r
-    uint32_t decryptable_data_len = key->header.length;\r
-    /* Check whether data is encrypted */\r
-#if (CONFIG_NV_SUPPORT_ENCRYPT == NV_YES)\r
-    if (key->header.enc_key == AES_KDFKEY_SDRK_TYPE) {\r
-        /* Read key data, using AES engine if encrypted */\r
-        res = nv_crypto_claim_aes(&crypto_handle, &(key->header));\r
-        if (res != ERRCODE_SUCC) {\r
-            nv_crypto_release_aes(crypto_handle);\r
-            return res;\r
-        }\r
-    }\r
-#endif\r
-\r
-    /* Read key data, using AES engine if encrypted */\r
-    while (key_data_offset < decryptable_data_len) {\r
-        uint32_t chunk_len = uapi_min(NV_KEY_DATA_CHUNK_LEN, decryptable_data_len - key_data_offset);\r
-\r
-        res = kv_key_read_data_from_flash((uintptr_t)(dest_location + key_data_offset),\r
-                                          (uintptr_t)key_data_location + key_data_offset,\r
-                                          chunk_len, crypto_handle);\r
-        if (res != ERRCODE_SUCC) {\r
-            break;\r
-        }\r
-        key_data_offset += chunk_len;\r
-    }\r
-#if (CONFIG_NV_SUPPORT_ENCRYPT == NV_YES)\r
-    if (crypto_handle != INVAILD_CRYPTO_HANDLE) {\r
-        nv_crypto_release_aes(crypto_handle);\r
-    }\r
-#endif\r
-    return res;\r
-}\r
-\r
-STATIC errcode_t kv_helper_compare_key_data_chunks(const kv_key_handle_t *key, const uint8_t *compare_data,\r
-                                                   kv_helper_compare_key_data_info_t *info)\r
-{\r
-    errcode_t res = ERRCODE_SUCC;\r
-\r
-    uintptr_t key_data_location = (uintptr_t)key->key_location + (uintptr_t)sizeof(kv_key_header_t);\r
-    uint32_t key_data_offset = 0;\r
-    while (key_data_offset < key->header.length) {\r
-        const uint16_t chunk_len = (uint16_t)uapi_min(NV_KEY_DATA_CHUNK_LEN, key->header.length - key_data_offset);\r
-        res = kv_key_read_data_from_flash((uintptr_t)info->key_data_chunk, (key_data_location + key_data_offset),\r
-                                          chunk_len, info->crypto_handle);\r
-        if (res != ERRCODE_SUCC) {\r
-            break;\r
-        }\r
-\r
-        uint32_t compare_length = uapi_min(chunk_len, key->header.length - key_data_offset);\r
-        if (info->compare_data_chunk != NULL) {\r
-            /* Compare data in flash */\r
-            res = kv_key_helper_copy_flash((uint32_t)(uintptr_t)info->compare_data_chunk,\r
-                                           (uint32_t)(uintptr_t)compare_data + key_data_offset,\r
-                                           (uint16_t)compare_length);\r
-            if (res != ERRCODE_SUCC) {\r
-                break;\r
-            }\r
-            if (memcmp(info->key_data_chunk, info->compare_data_chunk, compare_length) != 0) {\r
-                return ERRCODE_NV_DATA_MISMATCH;\r
-            }\r
-        } else {\r
-            /* Compare data in RAM */\r
-            if (memcmp(info->key_data_chunk, compare_data + key_data_offset, compare_length) != 0) {\r
-                return ERRCODE_NV_DATA_MISMATCH;\r
-            }\r
-        }\r
-        key_data_offset += chunk_len;\r
-    }\r
-\r
-    return res;\r
-}\r
-\r
-errcode_t kv_helper_compare_key_data(kv_key_handle_t *key, const uint8_t *compare_data, uint16_t compare_length)\r
-{\r
-    kv_helper_compare_key_data_info_t info = {INVAILD_CRYPTO_HANDLE, NULL, NULL};\r
-    errcode_t res;\r
-\r
-    if (key->header.length != compare_length) {\r
-        return ERRCODE_NV_LENGTH_MISMATCH;\r
-    }\r
-\r
-    /* Key data *will* be in flash and could be encrypted */\r
-    info.key_data_chunk = (uint8_t *)kv_malloc(NV_KEY_DATA_CHUNK_LEN);\r
-    if (info.key_data_chunk == NULL) {\r
-        return ERRCODE_MALLOC;\r
-    }\r
-\r
-    /* Compare data *could* be in flash and will not be encrypted */\r
-    if (\r
-#ifdef CONFIG_NV_SUPPORT_SINGLE_CORE_SYSTEM\r
-        ((uintptr_t)(compare_data + compare_length) >= FLASH_PHYSICAL_ADDR_START) &&\r
-#endif\r
-        (uintptr_t)(compare_data + compare_length) <= FLASH_PHYSICAL_ADDR_END)  {\r
-        info.compare_data_chunk = (uint8_t *)kv_malloc(NV_KEY_DATA_CHUNK_LEN);\r
-        if (info.compare_data_chunk == NULL) {\r
-            res = ERRCODE_MALLOC;\r
-            /* Ensure there is not a memory leak */\r
-            goto ret_free;\r
-        }\r
-    }\r
-\r
-#if (CONFIG_NV_SUPPORT_ENCRYPT == NV_YES)\r
-    if (key->header.enc_key == AES_KDFKEY_SDRK_TYPE) {\r
-        /* Read key data, using AES engine if encrypted */\r
-        res = nv_crypto_claim_aes(&(info.crypto_handle), &(key->header));\r
-        if (res != ERRCODE_SUCC) {\r
-            goto ret_free;\r
-        }\r
-    }\r
-#endif\r
-\r
-    res = kv_helper_compare_key_data_chunks(key, compare_data, &info);\r
-\r
-ret_free:\r
-#if (CONFIG_NV_SUPPORT_ENCRYPT == NV_YES)\r
-    if (info.crypto_handle != INVAILD_CRYPTO_HANDLE) {\r
-        nv_crypto_release_aes(info.crypto_handle);\r
-    }\r
-#endif\r
-    kv_free(info.compare_data_chunk);\r
-    kv_free(info.key_data_chunk);\r
-    return res;\r
-}\r
-\r
-bool kv_key_is_erased(const kv_key_handle_t *key)\r
-{\r
-    if ((key->header.magic != g_nv_header_magic) ||\r
-        (key->header.valid != KV_KEY_VALID) ||\r
-        (key->header.length == 0xFFFF) ||\r
-        (key->header.length == 0)) {\r
-        return true;\r
-    }\r
-\r
-    return false;\r
-}\r
-\r
-bool kv_key_is_valid(kv_key_handle_t *key)\r
-{\r
-    bool res = kv_key_is_erased(key);\r
-    if (res == true) {\r
-        return false;\r
-    }\r
-\r
-    return (kv_key_validation(key, false) == ERRCODE_SUCC);\r
-}\r
-\r
-/**\r
- * Attempt to match pertinent bits in a key with a search_pattern\r
- * @param key_handle      Handle of a valid key\r
- * @param search_pattern  The pattern of bits to match in the key\r
- * @param search_mask     A mask to select the pertinent bits in the key for matching\r
- * @return                true if pattern matches, false otherwise\r
- */\r
-errcode_t kv_key_does_pattern_match(const kv_key_handle_t *key, kv_key_id search_pattern, kv_key_id search_mask)\r
-{\r
-    /* Match pertinent bits in the key with the search_pattern */\r
-    if ((key->header.key_id & search_mask) != search_pattern) {\r
-        return ERRCODE_NV_SEARCH_PATTERN_MISMATCH;\r
-    }\r
-    return ERRCODE_SUCC;\r
-}\r
-\r
-errcode_t kv_key_does_filter_match(kv_key_handle_t *key, kv_key_filter_t *search_filter)\r
-{\r
-    /* If no search filter is given then match every key */\r
-    if (search_filter != NULL) {\r
-        errcode_t res;\r
-        res = kv_key_does_pattern_match(key, search_filter->pattern, search_filter->mask);\r
-        if (res != ERRCODE_SUCC) {\r
-            return res;\r
-        }\r
-\r
-        if (((uint32_t)search_filter->type & (uint32_t)KV_KEY_FILTER_TYPE_ANY) != (uint32_t)KV_KEY_FILTER_TYPE_ANY) {\r
-            /* Determine key type */\r
-            kv_key_filter_type_t key_type;\r
-            if ((((uint32_t)kv_key_attributes(key)) & ((uint32_t)KV_ATTRIBUTE_PERMANENT)) != 0) {\r
-                key_type = KV_KEY_FILTER_TYPE_PERMANENT;\r
-            } else {\r
-                key_type = KV_KEY_FILTER_TYPE_NORMAL;\r
-            }\r
-            if (((uint32_t)search_filter->type & (uint32_t)key_type) == 0) {\r
-                return ERRCODE_NV_SEARCH_KEY_TYPE_MISMATCH;\r
-            }\r
-        }\r
-\r
-        if (((uint32_t)search_filter->state & (uint32_t)KV_KEY_FILTER_STATE_ANY) != (uint32_t)KV_KEY_FILTER_STATE_ANY) {\r
-            /* Determine key state */\r
-            kv_key_filter_state_t key_state;\r
-            if (kv_key_is_valid(key)) {\r
-                key_state = KV_KEY_FILTER_STATE_VALID;\r
-            } else {\r
-                key_state = KV_KEY_FILTER_STATE_INVALID;\r
-            }\r
-            if (((uint32_t)search_filter->state & (uint32_t)key_state) == 0) {\r
-                return ERRCODE_NV_SEARCH_KEY_STATE_MISMATCH;\r
-            }\r
-        }\r
-    }\r
-\r
-    return ERRCODE_SUCC;\r
-}\r
-\r
-STATIC bool kv_key_header_is_full_ff(kv_key_header_t *key_header, uint8_t len)\r
-{\r
-    kv_key_header_t header_cmp;\r
-    uint8_t cmp_len = (len > (uint8_t)sizeof(kv_key_header_t)) ? ((uint8_t)sizeof(kv_key_header_t)) : len;\r
-\r
-    (void)memset_s(&header_cmp, sizeof(kv_key_header_t), 0xFF, sizeof(kv_key_header_t)); /* 0xFF is initial value */\r
-\r
-    if (memcmp(key_header, &header_cmp, cmp_len) == 0) {\r
-        return true;\r
-    }\r
-    return false;\r
-}\r
-\r
-errcode_t kv_key_get_handle_from_location(kv_key_location key_location, kv_key_handle_t *key)\r
-{\r
-    key->header.length = 0xFFFF;  /* Would not expect a flash read to fail, but just in case... */\r
-    errcode_t res = kv_key_helper_copy_flash((uint32_t)(uintptr_t)&key->header, (uint32_t)(uintptr_t)key_location,\r
-                                             sizeof(kv_key_header_t));\r
-    if (res != ERRCODE_SUCC) {\r
-        return res;\r
-    }\r
-\r
-    key->key_location = key_location;\r
-\r
-    if (kv_key_header_is_full_ff(&key->header, (uint8_t)sizeof(kv_key_header_t))) {\r
-        /* Last key has been read */\r
-        return ERRCODE_NV_KEY_NOT_FOUND;\r
-    }\r
-\r
-    if (g_nv_header_magic == KV_KEY_MAGIC && key->header.magic != KV_KEY_MAGIC) {\r
-        /* Wrong key has been read */\r
-        return ERRCODE_NV_INVALID_KEY_HEADER;\r
-    }\r
-    return ERRCODE_SUCC;\r
-}\r
-\r
-errcode_t kv_key_locations_in_same_page(kv_key_location first_key_location, kv_key_location second_key_location)\r
-{\r
-    uintptr_t first_page_location = (uintptr_t)first_key_location & ~(KV_PAGE_SIZE - 1);\r
-    uintptr_t second_page_location = ((uintptr_t)second_key_location +\r
-        (uintptr_t)sizeof(kv_key_header_t)) & ~(KV_PAGE_SIZE - 1);\r
-    if (first_page_location != second_page_location) {\r
-        return ERRCODE_FAIL;\r
-    }\r
-    return ERRCODE_SUCC;\r
-}\r
-\r
-#if (CONFIG_NV_SUPPORT_SKIP_CORRUPT_KEY == NV_YES)\r
-errcode_t kv_key_get_next_magic_position(kv_key_location key_location, kv_key_handle_t *key)\r
-{\r
-    uint32_t src = (uint32_t)(uintptr_t)key_location;\r
-    kv_nvregion_area_t* nvregion_area =  nv_get_region_area();\r
-    uint32_t start_page_loc = nvregion_area->nv_data_addr - FLASH_PHYSICAL_ADDR_START;\r
-    uint32_t next_page_loc =  ((((src - start_page_loc) / KV_PAGE_SIZE) + 1) * KV_PAGE_SIZE) + start_page_loc;\r
-\r
-    /* 从传入位置的下一位开始读 */\r
-    src = src + 1;\r
-    bool found_ending = false;\r
-    kv_key_location tmp_location;\r
-\r
-    for (; src < next_page_loc - sizeof(kv_key_header_t); src++) {\r
-        (void)memset_s(&(key->header), sizeof(kv_key_header_t), 0, sizeof(kv_key_header_t));\r
-        if (kv_key_helper_copy_flash((uint32_t)(uintptr_t)&key->header, src, sizeof(kv_key_header_t)) != ERRCODE_SUCC) {\r
-            return ERRCODE_NV_READ_FLASH_ERR;\r
-        }\r
-\r
-        if (key->header.magic == KV_KEY_MAGIC &&\r
-            (key->header.valid == KV_KEY_INVALID || key->header.valid == KV_KEY_VALID)) {\r
-            key->key_location = (kv_key_location)(uintptr_t)src;\r
-            /* 找到有效的Key */\r
-            if (kv_key_validate_integrity(key, true) == ERRCODE_SUCC) {\r
-                nv_log_debug("[NV][magic] Get valid next key (location = 0x%x).\r\n", key->key_location);\r
-                return ERRCODE_SUCC;\r
-            }\r
-        }\r
-\r
-        if (kv_key_header_is_full_ff(&key->header, (uint8_t)sizeof(kv_key_header_t))) {\r
-            /* 找到一块全F区域,暂时标记为数据结尾 */\r
-            if (!found_ending) {\r
-                found_ending = true;\r
-                tmp_location = (kv_key_location)(uintptr_t)src;\r
-            }\r
-            /* 若此段为全F,直接跳到下一段进行读取,不以1的步长行进 */\r
-            src += (uint32_t)sizeof(kv_key_header_t) - 1;\r
-        } else if (found_ending) {\r
-            /* 如又找到一块非全F区域,则上次标记的位置不是数据结尾,取消标记 */\r
-            found_ending = false;\r
-        }\r
-    }\r
-    if (found_ending) {\r
-        key->key_location = tmp_location;\r
-    } else {\r
-        /* 如未找到数据结尾, 则在最后继续查找更短一些的全FF数据 */\r
-        for (src = next_page_loc - (uint32_t)sizeof(kv_key_header_t); src < next_page_loc; src++) {\r
-            uint32_t read_len = next_page_loc - src;\r
-            if (kv_key_helper_copy_flash((uint32_t)(uintptr_t)&key->header, src, (uint16_t)read_len) != ERRCODE_SUCC) {\r
-                return ERRCODE_NV_READ_FLASH_ERR;\r
-            }\r
-            if (kv_key_header_is_full_ff(&key->header, (uint8_t)read_len)) {\r
-                key->key_location = (kv_key_location)(uintptr_t)src;\r
-                nv_log_debug("[NV][magic] Get next key on end 2 (location = 0x%x).\r\n", key->key_location);\r
-                return ERRCODE_NV_KEY_NOT_FOUND;\r
-            }\r
-        }\r
-        key->key_location = (kv_key_location)(uintptr_t)src;\r
-    }\r
-\r
-    return ERRCODE_NV_KEY_NOT_FOUND;\r
-}\r
-\r
-STATIC errcode_t kv_key_get_next_key_from_location(kv_key_location cur_key_loc, kv_key_location next_key_loc,\r
-    kv_key_handle_t *key)\r
-{\r
-    if (kv_key_locations_in_same_page(cur_key_loc, next_key_loc) != ERRCODE_SUCC) {\r
-        /* Reached the end of the KV page */\r
-        return ERRCODE_NV_KEY_NOT_FOUND;\r
-    }\r
-\r
-    return kv_key_get_handle_from_location(next_key_loc, key);\r
-}\r
-\r
-STATIC errcode_t kv_key_get_next_handle_with_corrupt_key(kv_key_handle_t *key, kv_key_validate_status_t key_status)\r
-{\r
-    kv_key_handle_t cur_key;\r
-    errcode_t res = ERRCODE_SUCC;\r
-\r
-    /* 如果当前KEY是错误Key,直接需要通过magic找到下一个key */\r
-    if (key_status == KV_KEY_VALIDATE_WRONG) {\r
-        return kv_key_get_next_magic_position(key->key_location, key);\r
-    }\r
-\r
-    if (kv_key_header_is_full_ff(&key->header, (uint8_t)sizeof(kv_key_header_t))) {\r
-        /* Last key has been read */\r
-        return ERRCODE_NV_KEY_NOT_FOUND;\r
-    }\r
-\r
-    if (key->header.magic != KV_KEY_MAGIC) {\r
-        /* corrupt key has been read, then get next key by magic */\r
-        nv_log_info("[NV] header magic error(location = 0x%x)! Get next key by magic.\r\n", key->key_location);\r
-        return kv_key_get_next_magic_position(key->key_location, key);\r
-    }\r
-\r
-    uint16_t offset = kv_key_flash_size(key);\r
-    kv_key_location next_key_location = (kv_key_location)((uintptr_t)key->key_location + offset);\r
-\r
-    (void)memcpy_s(&cur_key, sizeof(kv_key_handle_t), key, sizeof(kv_key_handle_t));\r
-\r
-    /* 出现下面两种情况之一时:\r
-       1. 下一个Key的位置与当前Key不在一个page内\r
-       2. 下一个key的位置指向数据结尾\r
-       首先验证当前key,如果当前KEY校验成功,则说明key length是可信的,说明确实找到了数据结尾,返回ERRCODE_NV_KEY_NOT_FOUND;\r
-       如果当前KEY校验不成功,则说明key length可能是不正确的,则需要通过magic找到下一个key。\r
-    */\r
-    res = kv_key_get_next_key_from_location(key->key_location, next_key_location, key);\r
-    if (res != ERRCODE_SUCC) {\r
-        if (key_status == KV_KEY_VALIDATE_CORRECT || (kv_key_validate_integrity(&cur_key, true) == ERRCODE_SUCC)) {\r
-            key->key_location = next_key_location;\r
-            if (res == ERRCODE_NV_INVALID_KEY_HEADER) {\r
-                res = ERRCODE_SUCC;\r
-            }\r
-            return res;\r
-        } else {\r
-            /* 如果当前KEY校验不成功,则说明key length可能是不正确的,则需要通过magic找到下一个KEY */\r
-            nv_log_info("[NV] validate failed (location = 0x%x)! Get next key by magic.\r\n", cur_key.key_location);\r
-            return kv_key_get_next_magic_position(cur_key.key_location, key);\r
-        }\r
-    }\r
-\r
-    return res;\r
-}\r
-#endif /* #ifdef CONFIG_NV_SUPPORT_SKIP_CORRUPT_KEY */\r
-\r
-STATIC errcode_t kv_key_get_next_handle_direct(kv_key_handle_t *key)\r
-{\r
-    if (key->header.length == 0xFFFF) {\r
-        /* Last key has been read */\r
-        return ERRCODE_NV_KEY_NOT_FOUND;\r
-    }\r
-\r
-    uint16_t offset = kv_key_flash_size(key);\r
-    kv_key_location new_key_location = (kv_key_location)((uintptr_t)key->key_location + offset);\r
-    if (kv_key_locations_in_same_page(key->key_location, new_key_location) != ERRCODE_SUCC) {\r
-        /* Reached the end of the KV page */\r
-        return ERRCODE_NV_KEY_NOT_FOUND;\r
-    }\r
-\r
-    return kv_key_get_handle_from_location(new_key_location, key);\r
-}\r
-\r
-errcode_t kv_key_get_next_handle(kv_key_handle_t *key, kv_key_validate_status_t key_status)\r
-{\r
-    unused(key_status);\r
-#if (CONFIG_NV_SUPPORT_SKIP_CORRUPT_KEY == NV_YES)\r
-    if (g_nv_header_magic == KV_KEY_MAGIC) {\r
-        return kv_key_get_next_handle_with_corrupt_key(key, key_status);\r
-    } else {\r
-        return kv_key_get_next_handle_direct(key);\r
-    }\r
-#else\r
-    return kv_key_get_next_handle_direct(key);\r
-#endif\r
-}\r
-\r
-STATIC void kv_key_fix_header_for_validate(kv_key_header_t *key_header, bool ignor_invalid)\r
-{\r
-    if (ignor_invalid && key_header->valid == KV_KEY_INVALID) {\r
-        key_header->valid = KV_KEY_VALID;\r
-        if (g_nv_header_magic == KV_KEY_NO_MAGIC) {\r
-            key_header->magic = g_nv_header_magic;\r
-        }\r
-    }\r
-}\r
-\r
-STATIC void kv_key_hash_crc_tag_start(kv_key_handle_t *key, uint32_t *crc_ret)\r
-{\r
-    *crc_ret = 0;\r
-    if (key->header.enc_key != AES_KDFKEY_SDRK_TYPE) {\r
-        return;\r
-    }\r
-\r
-#if ((CONFIG_NV_SUPPORT_ENCRYPT == NV_YES) && (CONFIG_NV_SUPPORT_HASH_FOR_CRYPT == NV_YES))\r
-    (void)nv_crypto_start_hash();\r
-#endif\r
-}\r
-\r
-STATIC void kv_key_hash_crc_tag_update(kv_key_handle_t *key, uint8_t *data_chunk, uint32_t data_len, uint32_t *crc_ret)\r
-{\r
-    *crc_ret = uapi_crc32(*crc_ret, data_chunk, data_len);\r
-    if (key->header.enc_key != AES_KDFKEY_SDRK_TYPE) {\r
-        return;\r
-    }\r
-\r
-#if ((CONFIG_NV_SUPPORT_ENCRYPT == NV_YES) && (CONFIG_NV_SUPPORT_HASH_FOR_CRYPT == NV_YES))\r
-    nv_crypto_update_hash(data_chunk, data_len);\r
-#endif\r
-}\r
-\r
-STATIC void kv_key_hash_crc_tag_finish(kv_key_handle_t *key, uint8_t *calculated_hash, uint32_t crc_value,\r
-    uint32_t crypto_handle)\r
-{\r
-    unused(crypto_handle);\r
-    uint32_t crc_ret = kv_crc32_swap(crc_value);\r
-\r
-    if (key->header.enc_key != AES_KDFKEY_SDRK_TYPE) {\r
-        (void)memcpy_s((void *)calculated_hash, KV_CRYPTO_CRC_SIZE, (const void *)&crc_ret, KV_CRYPTO_CRC_SIZE);\r
-        return;\r
-    }\r
-\r
-#if (CONFIG_NV_SUPPORT_ENCRYPT == NV_YES)\r
-#if (CONFIG_NV_SUPPORT_HASH_FOR_CRYPT == NV_YES)\r
-    nv_crypto_complete_hash(calculated_hash);\r
-    (void)memcpy_s((void *)(calculated_hash + KV_CRYPTO_HASH_SIZE - KV_CRYPTO_CRC_SIZE), KV_CRYPTO_CRC_SIZE,\r
-        (const void *)&crc_ret, KV_CRYPTO_CRC_SIZE);\r
-#else\r
-    (void)memcpy_s((void *)(calculated_hash + KV_CRYPTO_HASH_SIZE - KV_CRYPTO_CRC_SIZE), KV_CRYPTO_CRC_SIZE,\r
-        (const void *)&crc_ret, KV_CRYPTO_CRC_SIZE);\r
-#endif /* (CONFIG_NV_SUPPORT_HASH_FOR_CRYPT == NV_YES) */\r
-#endif /* #if (CONFIG_NV_SUPPORT_ENCRYPT == NV_YES) */\r
-}\r
-\r
-STATIC errcode_t kv_key_hash_crc_tag_verify(kv_key_handle_t *key, uint8_t *read_hash_crc, uint8_t *cal_hash_crc,\r
-    uint32_t crypto_handle, bool only_crc)\r
-{\r
-    unused(crypto_handle);\r
-    unused(only_crc);\r
-    errcode_t res = ERRCODE_SUCC;\r
-\r
-    if (key->header.enc_key != AES_KDFKEY_SDRK_TYPE) {\r
-        if (memcmp(cal_hash_crc, read_hash_crc, KV_CRYPTO_CRC_SIZE) != 0) {\r
-            res = ERRCODE_NV_HASH_MISMATCH;\r
-        }\r
-        return res;\r
-    }\r
-\r
-#if (CONFIG_NV_SUPPORT_ENCRYPT != NV_YES)\r
-    /* 不支持加密的情况下直接返回失败 */\r
-    return ERRCODE_NV_HASH_MISMATCH;\r
-#else\r
-    if (only_crc) {\r
-        /* 只校验CRC的场景,校验最后4个字节的CRC(密文的CRC) */\r
-        if (memcmp(cal_hash_crc + KV_CRYPTO_HASH_SIZE - KV_CRYPTO_CRC_SIZE,\r
-            read_hash_crc + KV_CRYPTO_HASH_SIZE - KV_CRYPTO_CRC_SIZE, KV_CRYPTO_CRC_SIZE) != 0) {\r
-            res = ERRCODE_NV_HASH_MISMATCH;\r
-        }\r
-        return res;\r
-    }\r
-#if (CONFIG_NV_SUPPORT_HASH_FOR_CRYPT == NV_YES)\r
-    /* 使用HASH校验的场景,校验HASH的前28个字节 */\r
-    if (memcmp(cal_hash_crc, read_hash_crc, KV_CRYPTO_HASH_SIZE - KV_CRYPTO_CRC_SIZE) != 0) {\r
-        res = ERRCODE_NV_HASH_MISMATCH;\r
-    }\r
-    return res;\r
-#else\r
-    /* 使用GCM TAG的场景,直接校验16字节的TAG */\r
-    return nv_crypto_validate_tag(crypto_handle);\r
-#endif /* (CONFIG_NV_SUPPORT_HASH_FOR_CRYPT == NV_YES)) */\r
-#endif /* #if (CONFIG_NV_SUPPORT_ENCRYPT != NV_YES) */\r
-}\r
-\r
-STATIC errcode_t kv_key_validate_hash_chunks(kv_key_handle_t *key, uint8_t *read_data_chunk, uint8_t *cal_hash_crc,\r
-    uint32_t crypto_handle, bool ignor_invalid)\r
-{\r
-    errcode_t res;\r
-    kv_key_header_t *key_header = (kv_key_header_t *)read_data_chunk;\r
-    uintptr_t key_location = (uintptr_t)key->key_location;\r
-    uint32_t crc_ret = 0;\r
-    uint32_t hash_crc_len = ((key->header.enc_key == AES_KDFKEY_SDRK_TYPE) ? KV_CRYPTO_HASH_SIZE : KV_CRYPTO_CRC_SIZE);\r
-\r
-    kv_key_hash_crc_tag_start(key, &crc_ret);\r
-\r
-    /* Read header first, which is never encrypted */\r
-    res = kv_key_read_data_from_flash((uintptr_t)read_data_chunk, key_location,\r
-        sizeof(kv_key_header_t), INVAILD_CRYPTO_HANDLE);\r
-    if (res != ERRCODE_SUCC) {\r
-        return res;\r
-    }\r
-\r
-    kv_key_fix_header_for_validate(key_header, ignor_invalid);\r
-\r
-    kv_key_hash_crc_tag_update(key, read_data_chunk, sizeof(kv_key_header_t), &crc_ret);\r
-\r
-    const kv_attributes_t attributes = kv_key_attributes(key);\r
-    uint32_t decryptable_data_len = kv_key_padded_data_length(attributes, key->header.length);\r
-#if (CONFIG_NV_SUPPORT_HASH_FOR_CRYPT == NV_NO)\r
-    if (crypto_handle != INVAILD_CRYPTO_HANDLE) {\r
-        /* 在使用GCM TAG时,先读取一次TAG并设置给解密模块 */\r
-        /* Read key hash, which could be unencrypted */\r
-        uintptr_t hash_location = key_location + (uintptr_t)sizeof(kv_key_header_t) + (uintptr_t)decryptable_data_len;\r
-        (void)kv_key_read_data_from_flash((uintptr_t)read_data_chunk, hash_location,\r
-            KV_CRYPTO_HASH_SIZE, INVAILD_CRYPTO_HANDLE);\r
-        (void)nv_crypto_set_tag(crypto_handle, read_data_chunk, NV_AES_GCM_TAG_LENGTH);\r
-    }\r
-#endif\r
-\r
-    /* Read rest of key data, which could be encrypted */\r
-    uint32_t key_data_offset = 0;\r
-    key_location += (uintptr_t)sizeof(kv_key_header_t);\r
-    while (key_data_offset < decryptable_data_len) {\r
-        uint32_t chunk_len = uapi_min(NV_KEY_DATA_CHUNK_LEN, decryptable_data_len - key_data_offset);\r
-\r
-        res = kv_key_read_data_from_flash((uintptr_t)read_data_chunk, (key_location + key_data_offset),\r
-                                          chunk_len, crypto_handle);\r
-        if (res != ERRCODE_SUCC) {\r
-            return res;\r
-        }\r
-\r
-        kv_key_hash_crc_tag_update(key, read_data_chunk, chunk_len, &crc_ret);\r
-        key_data_offset += chunk_len;\r
-    }\r
-\r
-    /* Read key hash, which could be unencrypted */\r
-    res = kv_key_read_data_from_flash((uintptr_t)read_data_chunk, (key_location + key_data_offset),\r
-                                      hash_crc_len, INVAILD_CRYPTO_HANDLE);\r
-\r
-    kv_key_hash_crc_tag_finish(key, cal_hash_crc, crc_ret, crypto_handle);\r
-    return res;\r
-}\r
-\r
-/*\r
- * 校验KEY的完整性。\r
- * 非加密KEY, 校验CRC;\r
- * 加密KEY, 如CONFIG_NV_SUPPORT_HASH_FOR_CRYPT为YES,校验明文HASH;\r
- *          如CONFIG_NV_SUPPORT_HASH_FOR_CRYPT为NO,校验密文的CRC(CRC存放在16字节Tag之后)。\r
- */\r
-errcode_t kv_key_validate_integrity(kv_key_handle_t *key, bool ignor_invalid)\r
-{\r
-    uint32_t crypto_handle = INVAILD_CRYPTO_HANDLE;\r
-\r
-    if (key->header.length > NV_NORMAL_KVALUE_MAX_LEN) {\r
-        return ERRCODE_NV_INVALID_KEY_HEADER;\r
-    }\r
-\r
-    uint8_t *calculated_hash = (uint8_t *)kv_malloc(KV_CRYPTO_HASH_SIZE);\r
-    if (calculated_hash == NULL) {\r
-        return ERRCODE_MALLOC;\r
-    }\r
-\r
-    uint8_t *read_data_chunk = (uint8_t *)kv_malloc(NV_KEY_DATA_CHUNK_LEN);\r
-    if (read_data_chunk == NULL) {\r
-        kv_free(calculated_hash);\r
-        return ERRCODE_MALLOC;\r
-    }\r
-\r
-    errcode_t res = kv_key_validate_hash_chunks(key, read_data_chunk, calculated_hash, crypto_handle, ignor_invalid);\r
-    if (res != ERRCODE_SUCC) {\r
-        goto err;\r
-    }\r
-\r
-    res = kv_key_hash_crc_tag_verify(key, read_data_chunk, calculated_hash, crypto_handle, true);\r
-\r
-err:\r
-    kv_free(read_data_chunk);\r
-    kv_free(calculated_hash);\r
-    return res;\r
-}\r
-\r
-/*\r
- * 校验KEY的正确性:\r
- * 非加密KEY校验CRC\r
- * 加密KEY, 如CONFIG_NV_SUPPORT_HASH_FOR_CRYPT为YES,校验明文HASH;\r
- *          如CONFIG_NV_SUPPORT_HASH_FOR_CRYPT为NO,则校验GCM Tag。\r
- */\r
-errcode_t kv_key_validation(kv_key_handle_t *key, bool ignor_invalid)\r
-{\r
-    errcode_t res;\r
-    uint32_t crypto_handle = INVAILD_CRYPTO_HANDLE;\r
-\r
-    if (key->header.length > NV_NORMAL_KVALUE_MAX_LEN) {\r
-        return ERRCODE_NV_INVALID_KEY_HEADER;\r
-    }\r
-\r
-    uint8_t *calculated_hash = (uint8_t *)kv_malloc(KV_CRYPTO_HASH_SIZE);\r
-    if (calculated_hash == NULL) {\r
-        return ERRCODE_MALLOC;\r
-    }\r
-    (void)memset_s(calculated_hash, KV_CRYPTO_HASH_SIZE, 0, KV_CRYPTO_HASH_SIZE);\r
-\r
-    uint8_t *read_data_chunk = (uint8_t *)kv_malloc(NV_KEY_DATA_CHUNK_LEN);\r
-    if (read_data_chunk == NULL) {\r
-        kv_free(calculated_hash);\r
-        return ERRCODE_MALLOC;\r
-    }\r
-\r
-    (void)memset_s(read_data_chunk, NV_KEY_DATA_CHUNK_LEN, 0, NV_KEY_DATA_CHUNK_LEN);\r
-\r
-#if (CONFIG_NV_SUPPORT_ENCRYPT == NV_YES)\r
-    if (key->header.enc_key != 0) {\r
-        /* Read key data, using AES engine if encrypted */\r
-        res = nv_crypto_claim_aes(&crypto_handle, &(key->header));\r
-        if (res != ERRCODE_SUCC) {\r
-            goto err;\r
-        }\r
-    }\r
-#endif\r
-\r
-    res = kv_key_validate_hash_chunks(key, read_data_chunk, calculated_hash, crypto_handle, ignor_invalid);\r
-    if (res != ERRCODE_SUCC) {\r
-        goto err;\r
-    }\r
-\r
-    res = kv_key_hash_crc_tag_verify(key, read_data_chunk, calculated_hash, crypto_handle, false);\r
-\r
-err:\r
-    kv_free(read_data_chunk);\r
-    kv_free(calculated_hash);\r
-\r
-#if (CONFIG_NV_SUPPORT_ENCRYPT == NV_YES)\r
-    if (crypto_handle != INVAILD_CRYPTO_HANDLE) {\r
-        nv_crypto_release_aes(crypto_handle);\r
-    }\r
-#endif\r
-    return res;\r
-}\r
-\r
-kv_attributes_t kv_key_attributes(const kv_key_handle_t *key)\r
-{\r
-    kv_attributes_t attributes = 0;\r
-\r
-    if (key->header.type != KV_KEY_TYPE_NORMAL) {\r
-        attributes = (kv_attributes_t)((uint32_t)attributes | (uint32_t)KV_ATTRIBUTE_PERMANENT);\r
-    }\r
-    if (key->header.enc_key != 0) {\r
-        attributes = (kv_attributes_t)((uint32_t)attributes | (uint32_t)KV_ATTRIBUTE_ENCRYPTED);\r
-    }\r
-    if (key->header.upgrade != KV_KEY_TYPE_NORMAL) {\r
-        attributes = (kv_attributes_t)((uint32_t)attributes | (uint32_t)KV_ATTRIBUTE_NON_UPGRADE);\r
-    }\r
-    return attributes;\r
-}\r
-\r
-uint16_t kv_key_padded_data_length(kv_attributes_t attributes, uint16_t unpadded_length)\r
-{\r
-    if (((uint32_t)attributes & (uint32_t)KV_ATTRIBUTE_ENCRYPTED) != 0) {\r
-        return kv_padded_ciphertext_length(unpadded_length);\r
-    } else {\r
-        return kv_padded_cleartext_length(unpadded_length);\r
-    }\r
-}\r
-\r
-uint16_t kv_key_flash_size(kv_key_handle_t *key)\r
-{\r
-    uint16_t size;\r
-    kv_attributes_t attributes;\r
-    uint16_t hash_crc_size;\r
-\r
-    if (key->header.enc_key == AES_KDFKEY_SDRK_TYPE) {\r
-        hash_crc_size = KV_CRYPTO_HASH_SIZE;\r
-    } else {\r
-        hash_crc_size = KV_CRYPTO_CRC_SIZE;\r
-    }\r
-\r
-    size = (uint16_t)sizeof(kv_key_header_t) + hash_crc_size;\r
-\r
-    attributes = kv_key_attributes(key);\r
-    size += kv_key_padded_data_length(attributes, key->header.length);\r
-\r
-    return size;\r
-}\r
-\r
-void kv_key_build_from_new(kv_key_handle_t *key, const kv_key_details_t *new_key, kv_key_location key_location)\r
-{\r
-    key->header.key_id = new_key->key_id;\r
-    key->header.length = (uint16_t)new_key->kvalue_length;\r
-    key->header.magic = g_nv_header_magic;\r
-    key->header.valid = KV_KEY_VALID;\r
-    key->header.type = KV_KEY_TYPE_NORMAL;\r
-    if (((uint32_t)new_key->attributes & (uint32_t)KV_ATTRIBUTE_PERMANENT) != 0) {\r
-        key->header.type = KV_KEY_TYPE_PERMANENT;\r
-    }\r
-    key->header.upgrade = KV_KEY_TYPE_NORMAL;\r
-    if (((uint32_t)new_key->attributes & (uint32_t)KV_ATTRIBUTE_NON_UPGRADE) != 0) {\r
-        key->header.upgrade = 0;\r
-        key->header.version = key->header.version + 1;\r
-    }\r
-    key->header.enc_key = 0;\r
-    if (((uint32_t)new_key->attributes & (uint32_t)KV_ATTRIBUTE_ENCRYPTED) != 0) {\r
-        key->header.enc_key = AES_KDFKEY_SDRK_TYPE;\r
-#if (CONFIG_NV_SUPPORT_ENCRYPT == NV_YES)\r
-        nv_crypto_generate_random(&key->header.rnd);\r
-#endif\r
-        key->header.version = key->header.version + 1;\r
-    }\r
-\r
-    key->key_location = key_location;\r
-}\r
-\r
-uint32_t kv_crc32_swap(uint32_t crc)\r
-{\r
-    return ((crc >> CRC_SWAP_SIZE24) | ((crc >> CRC_SWAP_SIZE8) & 0xFF00) |\r
-        ((crc << CRC_SWAP_SIZE8) & 0xFF0000) | (crc << CRC_SWAP_SIZE24));\r
+/*
+ * Copyright (c) @CompanyNameMagicTag 2019-2022. All rights reserved.
+ * Description: KV Storage Library key access module implementation
+ */
+
+#include "nv_key.h"
+#include "string.h"
+#include "nv_porting.h"
+#include "uapi_crc.h"
+#include "nv_nvregion.h"
+#include "common_def.h"
+
+#define KV_CLEARTEXT_PADDING_SIZE       (1UL << 2)   /* Currently these both need to be a power of 2... */
+#define KV_CIPHERTEXT_PADDING_SIZE      (1UL << 4)   /* ...due to implementation of kv_padded_length    */
+#define kv_padded_length(d, s)          (((d) + ((s) - 1)) & ~((s) - 1))
+#define kv_padded_cleartext_length(d)   kv_padded_length(d, KV_CLEARTEXT_PADDING_SIZE)
+#define kv_padded_ciphertext_length(d)  kv_padded_length(d, KV_CIPHERTEXT_PADDING_SIZE)
+#define KV_DMA_COPY_SIZE_ALIGN          32
+
+uint8_t g_nv_header_magic = KV_KEY_MAGIC;
+
+/* IOT-16672 Use ROM Lib function instead (enhanced to support KV requirements, as here) */
+errcode_t kv_key_helper_copy_flash(uint32_t dest_location, uint32_t src_location, uint16_t length)
+{
+    if (length == 0) {
+        return ERRCODE_NV_ZERO_LENGTH_COPY;
+    }
+    uint32_t src_addr = src_location - FLASH_PHYSICAL_ADDR_START;
+    uint16_t length_rounded = length & ~(KV_DMA_COPY_SIZE_ALIGN - 1);
+    uint16_t length_remainder = length & (KV_DMA_COPY_SIZE_ALIGN - 1);
+    uint16_t dest_offset = 0;
+    while (length_rounded > 0) {
+        if (kv_flash_read((uint32_t)(uintptr_t)src_addr, KV_DMA_COPY_SIZE_ALIGN,
+            (uint8_t *)(uintptr_t)(dest_location + dest_offset)) != ERRCODE_SUCC) {
+            return ERRCODE_NV_READ_FLASH_ERR;
+        }
+        dest_offset += KV_DMA_COPY_SIZE_ALIGN;
+        src_addr += KV_DMA_COPY_SIZE_ALIGN;
+        length_rounded -= KV_DMA_COPY_SIZE_ALIGN;
+    }
+
+    if (length_remainder > 0) {
+        if (kv_flash_read((uint32_t)(uintptr_t)src_addr, length_remainder,
+            (uint8_t *)(uintptr_t)(dest_location + dest_offset)) != ERRCODE_SUCC) {
+            return ERRCODE_NV_READ_FLASH_ERR;
+        }
+    }
+    return ERRCODE_SUCC;
+}
+
+#ifdef CONFIG_NV_SUPPORT_SINGLE_CORE_SYSTEM
+errcode_t kv_key_direct_write_flash(uint32_t dest, uint32_t length, const uint8_t *src)
+{
+    uint32_t dest_w = dest;
+    if ((dest >= FLASH_PHYSICAL_ADDR_START) &&
+            ((dest + length) <= FLASH_PHYSICAL_ADDR_END)) {
+        dest_w -= FLASH_PHYSICAL_ADDR_START;
+    } else {
+        return ERRCODE_FLASH_INVALID_PARAM_BEYOND_ADDR;
+    }
+
+    if (kv_flash_write(dest_w, length, src, false) != ERRCODE_SUCC) {
+        return ERRCODE_NV_READ_FLASH_ERR;
+    }
+
+    return ERRCODE_SUCC;
+}
+
+errcode_t kv_key_direct_erase_flash(uint32_t dest, const uint32_t size)
+{
+    uint32_t dest_w = dest;
+    if ((dest >= FLASH_PHYSICAL_ADDR_START) &&
+            ((dest + size) <= FLASH_PHYSICAL_ADDR_END)) {
+        dest_w -= FLASH_PHYSICAL_ADDR_START;
+    } else {
+        return ERRCODE_FLASH_INVALID_PARAM_BEYOND_ADDR;
+    }
+
+    if (kv_flash_erase(dest_w, size) != ERRCODE_SUCC) {
+        return ERRCODE_FAIL;
+    }
+
+    return ERRCODE_SUCC;
+}
+#endif
+
+errcode_t kv_key_write_flash(uint32_t dest, uint32_t length, const uint8_t *src)
+{
+#ifdef CONFIG_NV_SUPPORT_SINGLE_CORE_SYSTEM
+    return kv_key_direct_write_flash(dest, length, src);
+#else
+    return flash_task_drv_write(dest, length, src);
+#endif
+}
+
+errcode_t kv_key_erase_flash(uint32_t dest, const uint32_t size)
+{
+#ifdef CONFIG_NV_SUPPORT_SINGLE_CORE_SYSTEM
+    return kv_key_direct_erase_flash(dest, size);
+#else
+    return flash_task_drv_erase(dest, size);
+#endif
+}
+
+#if (CONFIG_NV_SUPPORT_ENCRYPT == NV_YES)
+STATIC errcode_t kv_key_decode_flash(uintptr_t dest, const uintptr_t src, uint32_t length, uint32_t crypto_handle)
+{
+    errcode_t ret;
+    uint8_t *kv_padded_data = NULL;
+
+    uint32_t padded_length = kv_key_padded_data_length(KV_ATTRIBUTE_ENCRYPTED, (uint16_t)length);
+    if (padded_length == length) {
+        ret = kv_key_helper_copy_flash((uint32_t)dest, (uint32_t)src, (uint16_t)length);
+        if (ret == ERRCODE_SUCC) {
+            return nv_crypto_decode(crypto_handle, dest, dest, length);
+        } else {
+            return ret;
+        }
+    } else {
+        kv_padded_data = (uint8_t *)kv_malloc(padded_length);
+        if (kv_padded_data == NULL) {
+            return ERRCODE_MALLOC;
+        }
+        ret = kv_key_helper_copy_flash((uint32_t)(uintptr_t)kv_padded_data, (uint32_t)(uintptr_t)src,
+            (uint16_t)padded_length);
+        if (ret != ERRCODE_SUCC) {
+            goto end;
+        }
+        ret = nv_crypto_decode(crypto_handle, (uintptr_t)kv_padded_data, (uintptr_t)kv_padded_data, padded_length);
+        if (ret != ERRCODE_SUCC) {
+            goto end;
+        }
+        if (memcpy_s((void *)dest, length, kv_padded_data, length) != EOK) {
+            ret = ERRCODE_MEMCPY;
+            goto end;
+        }
+    }
+end:
+    kv_free(kv_padded_data);
+    return ret;
+}
+#endif
+
+STATIC errcode_t kv_key_read_data_from_flash(uintptr_t dest, const uintptr_t src, uint32_t length,
+    uint32_t crypto_handle)
+{
+    if (crypto_handle == INVAILD_CRYPTO_HANDLE) {
+        /* Decrypt not required, just return */
+        return kv_key_helper_copy_flash((uint32_t)dest, (uint32_t)src, (uint16_t)length);
+    } else {
+        /* Data needs decrypting */
+#if (CONFIG_NV_SUPPORT_ENCRYPT == NV_YES)
+        return kv_key_decode_flash(dest, src, length, crypto_handle);
+#else
+        return ERRCODE_FAIL;
+#endif
+    }
+}
+
+errcode_t kv_key_read_data(kv_key_handle_t *key, uint8_t *dest_location)
+{
+    errcode_t res = ERRCODE_SUCC;
+    uint32_t crypto_handle = INVAILD_CRYPTO_HANDLE;
+    uint32_t key_data_offset = 0;
+    uint32_t key_data_location = (uint32_t)(uintptr_t)key->key_location + (uint32_t)sizeof(kv_key_header_t);
+    uint32_t decryptable_data_len = key->header.length;
+    /* Check whether data is encrypted */
+#if (CONFIG_NV_SUPPORT_ENCRYPT == NV_YES)
+    if (key->header.enc_key == AES_KDFKEY_SDRK_TYPE) {
+        /* Read key data, using AES engine if encrypted */
+        res = nv_crypto_claim_aes(&crypto_handle, &(key->header));
+        if (res != ERRCODE_SUCC) {
+            nv_crypto_release_aes(crypto_handle);
+            return res;
+        }
+    }
+#endif
+
+    /* Read key data, using AES engine if encrypted */
+    while (key_data_offset < decryptable_data_len) {
+        uint32_t chunk_len = uapi_min(NV_KEY_DATA_CHUNK_LEN, decryptable_data_len - key_data_offset);
+
+        res = kv_key_read_data_from_flash((uintptr_t)(dest_location + key_data_offset),
+                                          (uintptr_t)key_data_location + key_data_offset,
+                                          chunk_len, crypto_handle);
+        if (res != ERRCODE_SUCC) {
+            break;
+        }
+        key_data_offset += chunk_len;
+    }
+#if (CONFIG_NV_SUPPORT_ENCRYPT == NV_YES)
+    if (crypto_handle != INVAILD_CRYPTO_HANDLE) {
+        nv_crypto_release_aes(crypto_handle);
+    }
+#endif
+    return res;
+}
+
+STATIC errcode_t kv_helper_compare_key_data_chunks(const kv_key_handle_t *key, const uint8_t *compare_data,
+                                                   kv_helper_compare_key_data_info_t *info)
+{
+    errcode_t res = ERRCODE_SUCC;
+
+    uintptr_t key_data_location = (uintptr_t)key->key_location + (uintptr_t)sizeof(kv_key_header_t);
+    uint32_t key_data_offset = 0;
+    while (key_data_offset < key->header.length) {
+        const uint16_t chunk_len = (uint16_t)uapi_min(NV_KEY_DATA_CHUNK_LEN, key->header.length - key_data_offset);
+        res = kv_key_read_data_from_flash((uintptr_t)info->key_data_chunk, (key_data_location + key_data_offset),
+                                          chunk_len, info->crypto_handle);
+        if (res != ERRCODE_SUCC) {
+            break;
+        }
+
+        uint32_t compare_length = uapi_min(chunk_len, key->header.length - key_data_offset);
+        if (info->compare_data_chunk != NULL) {
+            /* Compare data in flash */
+            res = kv_key_helper_copy_flash((uint32_t)(uintptr_t)info->compare_data_chunk,
+                                           (uint32_t)(uintptr_t)compare_data + key_data_offset,
+                                           (uint16_t)compare_length);
+            if (res != ERRCODE_SUCC) {
+                break;
+            }
+            if (memcmp(info->key_data_chunk, info->compare_data_chunk, compare_length) != 0) {
+                return ERRCODE_NV_DATA_MISMATCH;
+            }
+        } else {
+            /* Compare data in RAM */
+            if (memcmp(info->key_data_chunk, compare_data + key_data_offset, compare_length) != 0) {
+                return ERRCODE_NV_DATA_MISMATCH;
+            }
+        }
+        key_data_offset += chunk_len;
+    }
+
+    return res;
+}
+
+errcode_t kv_helper_compare_key_data(kv_key_handle_t *key, const uint8_t *compare_data, uint16_t compare_length)
+{
+    kv_helper_compare_key_data_info_t info = {INVAILD_CRYPTO_HANDLE, NULL, NULL};
+    errcode_t res;
+
+    if (key->header.length != compare_length) {
+        return ERRCODE_NV_LENGTH_MISMATCH;
+    }
+
+    /* Key data *will* be in flash and could be encrypted */
+    info.key_data_chunk = (uint8_t *)kv_malloc(NV_KEY_DATA_CHUNK_LEN);
+    if (info.key_data_chunk == NULL) {
+        return ERRCODE_MALLOC;
+    }
+
+    /* Compare data *could* be in flash and will not be encrypted */
+    if (
+#ifdef CONFIG_NV_SUPPORT_SINGLE_CORE_SYSTEM
+        ((uintptr_t)(compare_data + compare_length) >= FLASH_PHYSICAL_ADDR_START) &&
+#endif
+        (uintptr_t)(compare_data + compare_length) <= FLASH_PHYSICAL_ADDR_END)  {
+        info.compare_data_chunk = (uint8_t *)kv_malloc(NV_KEY_DATA_CHUNK_LEN);
+        if (info.compare_data_chunk == NULL) {
+            res = ERRCODE_MALLOC;
+            /* Ensure there is not a memory leak */
+            goto ret_free;
+        }
+    }
+
+#if (CONFIG_NV_SUPPORT_ENCRYPT == NV_YES)
+    if (key->header.enc_key == AES_KDFKEY_SDRK_TYPE) {
+        /* Read key data, using AES engine if encrypted */
+        res = nv_crypto_claim_aes(&(info.crypto_handle), &(key->header));
+        if (res != ERRCODE_SUCC) {
+            goto ret_free;
+        }
+    }
+#endif
+
+    res = kv_helper_compare_key_data_chunks(key, compare_data, &info);
+
+ret_free:
+#if (CONFIG_NV_SUPPORT_ENCRYPT == NV_YES)
+    if (info.crypto_handle != INVAILD_CRYPTO_HANDLE) {
+        nv_crypto_release_aes(info.crypto_handle);
+    }
+#endif
+    kv_free(info.compare_data_chunk);
+    kv_free(info.key_data_chunk);
+    return res;
+}
+
+bool kv_key_is_erased(const kv_key_handle_t *key)
+{
+    if ((key->header.magic != g_nv_header_magic) ||
+        (key->header.valid != KV_KEY_VALID) ||
+        (key->header.length == 0xFFFF) ||
+        (key->header.length == 0)) {
+        return true;
+    }
+
+    return false;
+}
+
+bool kv_key_is_valid(kv_key_handle_t *key)
+{
+    bool res = kv_key_is_erased(key);
+    if (res == true) {
+        return false;
+    }
+
+    return (kv_key_validation(key, false) == ERRCODE_SUCC);
+}
+
+/**
+ * Attempt to match pertinent bits in a key with a search_pattern
+ * @param key_handle      Handle of a valid key
+ * @param search_pattern  The pattern of bits to match in the key
+ * @param search_mask     A mask to select the pertinent bits in the key for matching
+ * @return                true if pattern matches, false otherwise
+ */
+errcode_t kv_key_does_pattern_match(const kv_key_handle_t *key, kv_key_id search_pattern, kv_key_id search_mask)
+{
+    /* Match pertinent bits in the key with the search_pattern */
+    if ((key->header.key_id & search_mask) != search_pattern) {
+        return ERRCODE_NV_SEARCH_PATTERN_MISMATCH;
+    }
+    return ERRCODE_SUCC;
+}
+
+errcode_t kv_key_does_filter_match(kv_key_handle_t *key, kv_key_filter_t *search_filter)
+{
+    /* If no search filter is given then match every key */
+    if (search_filter != NULL) {
+        errcode_t res;
+        res = kv_key_does_pattern_match(key, search_filter->pattern, search_filter->mask);
+        if (res != ERRCODE_SUCC) {
+            return res;
+        }
+
+        if (((uint32_t)search_filter->type & (uint32_t)KV_KEY_FILTER_TYPE_ANY) != (uint32_t)KV_KEY_FILTER_TYPE_ANY) {
+            /* Determine key type */
+            kv_key_filter_type_t key_type;
+            if ((((uint32_t)kv_key_attributes(key)) & ((uint32_t)KV_ATTRIBUTE_PERMANENT)) != 0) {
+                key_type = KV_KEY_FILTER_TYPE_PERMANENT;
+            } else {
+                key_type = KV_KEY_FILTER_TYPE_NORMAL;
+            }
+            if (((uint32_t)search_filter->type & (uint32_t)key_type) == 0) {
+                return ERRCODE_NV_SEARCH_KEY_TYPE_MISMATCH;
+            }
+        }
+
+        if (((uint32_t)search_filter->state & (uint32_t)KV_KEY_FILTER_STATE_ANY) != (uint32_t)KV_KEY_FILTER_STATE_ANY) {
+            /* Determine key state */
+            kv_key_filter_state_t key_state;
+            if (kv_key_is_valid(key)) {
+                key_state = KV_KEY_FILTER_STATE_VALID;
+            } else {
+                key_state = KV_KEY_FILTER_STATE_INVALID;
+            }
+            if (((uint32_t)search_filter->state & (uint32_t)key_state) == 0) {
+                return ERRCODE_NV_SEARCH_KEY_STATE_MISMATCH;
+            }
+        }
+    }
+
+    return ERRCODE_SUCC;
+}
+
+STATIC bool kv_key_header_is_full_ff(kv_key_header_t *key_header, uint8_t len)
+{
+    kv_key_header_t header_cmp;
+    uint8_t cmp_len = (len > (uint8_t)sizeof(kv_key_header_t)) ? ((uint8_t)sizeof(kv_key_header_t)) : len;
+
+    (void)memset_s(&header_cmp, sizeof(kv_key_header_t), 0xFF, sizeof(kv_key_header_t)); /* 0xFF is initial value */
+
+    if (memcmp(key_header, &header_cmp, cmp_len) == 0) {
+        return true;
+    }
+    return false;
+}
+
+errcode_t kv_key_get_handle_from_location(kv_key_location key_location, kv_key_handle_t *key)
+{
+    key->header.length = 0xFFFF;  /* Would not expect a flash read to fail, but just in case... */
+    errcode_t res = kv_key_helper_copy_flash((uint32_t)(uintptr_t)&key->header, (uint32_t)(uintptr_t)key_location,
+                                             sizeof(kv_key_header_t));
+    if (res != ERRCODE_SUCC) {
+        return res;
+    }
+
+    key->key_location = key_location;
+
+    if (kv_key_header_is_full_ff(&key->header, (uint8_t)sizeof(kv_key_header_t))) {
+        /* Last key has been read */
+        return ERRCODE_NV_KEY_NOT_FOUND;
+    }
+
+    if (g_nv_header_magic == KV_KEY_MAGIC && key->header.magic != KV_KEY_MAGIC) {
+        /* Wrong key has been read */
+        return ERRCODE_NV_INVALID_KEY_HEADER;
+    }
+    return ERRCODE_SUCC;
+}
+
+errcode_t kv_key_locations_in_same_page(kv_key_location first_key_location, kv_key_location second_key_location)
+{
+    uintptr_t first_page_location = (uintptr_t)first_key_location & ~(KV_PAGE_SIZE - 1);
+    uintptr_t second_page_location = ((uintptr_t)second_key_location +
+        (uintptr_t)sizeof(kv_key_header_t)) & ~(KV_PAGE_SIZE - 1);
+    if (first_page_location != second_page_location) {
+        return ERRCODE_FAIL;
+    }
+    return ERRCODE_SUCC;
+}
+
+#if (CONFIG_NV_SUPPORT_SKIP_CORRUPT_KEY == NV_YES)
+errcode_t kv_key_get_next_magic_position(kv_key_location key_location, kv_key_handle_t *key)
+{
+    uint32_t src = (uint32_t)(uintptr_t)key_location;
+    kv_nvregion_area_t* nvregion_area =  nv_get_region_area();
+    uint32_t start_page_loc = nvregion_area->nv_data_addr - FLASH_PHYSICAL_ADDR_START;
+    uint32_t next_page_loc =  ((((src - start_page_loc) / KV_PAGE_SIZE) + 1) * KV_PAGE_SIZE) + start_page_loc;
+
+    /* 从传入位置的下一位开始读 */
+    src = src + 1;
+    bool found_ending = false;
+    kv_key_location tmp_location;
+
+    for (; src < next_page_loc - sizeof(kv_key_header_t); src++) {
+        (void)memset_s(&(key->header), sizeof(kv_key_header_t), 0, sizeof(kv_key_header_t));
+        if (kv_key_helper_copy_flash((uint32_t)(uintptr_t)&key->header, src, sizeof(kv_key_header_t)) != ERRCODE_SUCC) {
+            return ERRCODE_NV_READ_FLASH_ERR;
+        }
+
+        if (key->header.magic == KV_KEY_MAGIC &&
+            (key->header.valid == KV_KEY_INVALID || key->header.valid == KV_KEY_VALID)) {
+            key->key_location = (kv_key_location)(uintptr_t)src;
+            /* 找到有效的Key */
+            if (kv_key_validate_integrity(key, true) == ERRCODE_SUCC) {
+                nv_log_debug("[NV][magic] Get valid next key (location = 0x%x).\r\n", key->key_location);
+                return ERRCODE_SUCC;
+            }
+        }
+
+        if (kv_key_header_is_full_ff(&key->header, (uint8_t)sizeof(kv_key_header_t))) {
+            /* 找到一块全F区域,暂时标记为数据结尾 */
+            if (!found_ending) {
+                found_ending = true;
+                tmp_location = (kv_key_location)(uintptr_t)src;
+            }
+            /* 若此段为全F,直接跳到下一段进行读取,不以1的步长行进 */
+            src += (uint32_t)sizeof(kv_key_header_t) - 1;
+        } else if (found_ending) {
+            /* 如又找到一块非全F区域,则上次标记的位置不是数据结尾,取消标记 */
+            found_ending = false;
+        }
+    }
+    if (found_ending) {
+        key->key_location = tmp_location;
+    } else {
+        /* 如未找到数据结尾, 则在最后继续查找更短一些的全FF数据 */
+        for (src = next_page_loc - (uint32_t)sizeof(kv_key_header_t); src < next_page_loc; src++) {
+            uint32_t read_len = next_page_loc - src;
+            if (kv_key_helper_copy_flash((uint32_t)(uintptr_t)&key->header, src, (uint16_t)read_len) != ERRCODE_SUCC) {
+                return ERRCODE_NV_READ_FLASH_ERR;
+            }
+            if (kv_key_header_is_full_ff(&key->header, (uint8_t)read_len)) {
+                key->key_location = (kv_key_location)(uintptr_t)src;
+                nv_log_debug("[NV][magic] Get next key on end 2 (location = 0x%x).\r\n", key->key_location);
+                return ERRCODE_NV_KEY_NOT_FOUND;
+            }
+        }
+        key->key_location = (kv_key_location)(uintptr_t)src;
+    }
+
+    return ERRCODE_NV_KEY_NOT_FOUND;
+}
+
+STATIC errcode_t kv_key_get_next_key_from_location(kv_key_location cur_key_loc, kv_key_location next_key_loc,
+    kv_key_handle_t *key)
+{
+    if (kv_key_locations_in_same_page(cur_key_loc, next_key_loc) != ERRCODE_SUCC) {
+        /* Reached the end of the KV page */
+        return ERRCODE_NV_KEY_NOT_FOUND;
+    }
+
+    return kv_key_get_handle_from_location(next_key_loc, key);
+}
+
+STATIC errcode_t kv_key_get_next_handle_with_corrupt_key(kv_key_handle_t *key, kv_key_validate_status_t key_status)
+{
+    kv_key_handle_t cur_key;
+    errcode_t res = ERRCODE_SUCC;
+
+    /* 如果当前KEY是错误Key,直接需要通过magic找到下一个key */
+    if (key_status == KV_KEY_VALIDATE_WRONG) {
+        return kv_key_get_next_magic_position(key->key_location, key);
+    }
+
+    if (kv_key_header_is_full_ff(&key->header, (uint8_t)sizeof(kv_key_header_t))) {
+        /* Last key has been read */
+        return ERRCODE_NV_KEY_NOT_FOUND;
+    }
+
+    if (key->header.magic != KV_KEY_MAGIC) {
+        /* corrupt key has been read, then get next key by magic */
+        nv_log_info("[NV] header magic error(location = 0x%x)! Get next key by magic.\r\n", key->key_location);
+        return kv_key_get_next_magic_position(key->key_location, key);
+    }
+
+    uint16_t offset = kv_key_flash_size(key);
+    kv_key_location next_key_location = (kv_key_location)((uintptr_t)key->key_location + offset);
+
+    (void)memcpy_s(&cur_key, sizeof(kv_key_handle_t), key, sizeof(kv_key_handle_t));
+
+    /* 出现下面两种情况之一时:
+       1. 下一个Key的位置与当前Key不在一个page内
+       2. 下一个key的位置指向数据结尾
+       首先验证当前key,如果当前KEY校验成功,则说明key length是可信的,说明确实找到了数据结尾,返回ERRCODE_NV_KEY_NOT_FOUND;
+       如果当前KEY校验不成功,则说明key length可能是不正确的,则需要通过magic找到下一个key。
+    */
+    res = kv_key_get_next_key_from_location(key->key_location, next_key_location, key);
+    if (res != ERRCODE_SUCC) {
+        if (key_status == KV_KEY_VALIDATE_CORRECT || (kv_key_validate_integrity(&cur_key, true) == ERRCODE_SUCC)) {
+            key->key_location = next_key_location;
+            if (res == ERRCODE_NV_INVALID_KEY_HEADER) {
+                res = ERRCODE_SUCC;
+            }
+            return res;
+        } else {
+            /* 如果当前KEY校验不成功,则说明key length可能是不正确的,则需要通过magic找到下一个KEY */
+            nv_log_info("[NV] validate failed (location = 0x%x)! Get next key by magic.\r\n", cur_key.key_location);
+            return kv_key_get_next_magic_position(cur_key.key_location, key);
+        }
+    }
+
+    return res;
+}
+#endif /* #ifdef CONFIG_NV_SUPPORT_SKIP_CORRUPT_KEY */
+
+STATIC errcode_t kv_key_get_next_handle_direct(kv_key_handle_t *key)
+{
+    if (key->header.length == 0xFFFF) {
+        /* Last key has been read */
+        return ERRCODE_NV_KEY_NOT_FOUND;
+    }
+
+    uint16_t offset = kv_key_flash_size(key);
+    kv_key_location new_key_location = (kv_key_location)((uintptr_t)key->key_location + offset);
+    if (kv_key_locations_in_same_page(key->key_location, new_key_location) != ERRCODE_SUCC) {
+        /* Reached the end of the KV page */
+        return ERRCODE_NV_KEY_NOT_FOUND;
+    }
+
+    return kv_key_get_handle_from_location(new_key_location, key);
+}
+
+errcode_t kv_key_get_next_handle(kv_key_handle_t *key, kv_key_validate_status_t key_status)
+{
+    unused(key_status);
+#if (CONFIG_NV_SUPPORT_SKIP_CORRUPT_KEY == NV_YES)
+    if (g_nv_header_magic == KV_KEY_MAGIC) {
+        return kv_key_get_next_handle_with_corrupt_key(key, key_status);
+    } else {
+        return kv_key_get_next_handle_direct(key);
+    }
+#else
+    return kv_key_get_next_handle_direct(key);
+#endif
+}
+
+STATIC void kv_key_fix_header_for_validate(kv_key_header_t *key_header, bool ignor_invalid)
+{
+    if (ignor_invalid && key_header->valid == KV_KEY_INVALID) {
+        key_header->valid = KV_KEY_VALID;
+        if (g_nv_header_magic == KV_KEY_NO_MAGIC) {
+            key_header->magic = g_nv_header_magic;
+        }
+    }
+}
+
+STATIC void kv_key_hash_crc_tag_start(kv_key_handle_t *key, uint32_t *crc_ret)
+{
+    *crc_ret = 0;
+    if (key->header.enc_key != AES_KDFKEY_SDRK_TYPE) {
+        return;
+    }
+
+#if ((CONFIG_NV_SUPPORT_ENCRYPT == NV_YES) && (CONFIG_NV_SUPPORT_HASH_FOR_CRYPT == NV_YES))
+    (void)nv_crypto_start_hash();
+#endif
+}
+
+STATIC void kv_key_hash_crc_tag_update(kv_key_handle_t *key, uint8_t *data_chunk, uint32_t data_len, uint32_t *crc_ret)
+{
+    *crc_ret = uapi_crc32(*crc_ret, data_chunk, data_len);
+    if (key->header.enc_key != AES_KDFKEY_SDRK_TYPE) {
+        return;
+    }
+
+#if ((CONFIG_NV_SUPPORT_ENCRYPT == NV_YES) && (CONFIG_NV_SUPPORT_HASH_FOR_CRYPT == NV_YES))
+    nv_crypto_update_hash(data_chunk, data_len);
+#endif
+}
+
+STATIC void kv_key_hash_crc_tag_finish(kv_key_handle_t *key, uint8_t *calculated_hash, uint32_t crc_value,
+    uint32_t crypto_handle)
+{
+    unused(crypto_handle);
+    uint32_t crc_ret = kv_crc32_swap(crc_value);
+
+    if (key->header.enc_key != AES_KDFKEY_SDRK_TYPE) {
+        (void)memcpy_s((void *)calculated_hash, KV_CRYPTO_CRC_SIZE, (const void *)&crc_ret, KV_CRYPTO_CRC_SIZE);
+        return;
+    }
+
+#if (CONFIG_NV_SUPPORT_ENCRYPT == NV_YES)
+#if (CONFIG_NV_SUPPORT_HASH_FOR_CRYPT == NV_YES)
+    nv_crypto_complete_hash(calculated_hash);
+    (void)memcpy_s((void *)(calculated_hash + KV_CRYPTO_HASH_SIZE - KV_CRYPTO_CRC_SIZE), KV_CRYPTO_CRC_SIZE,
+        (const void *)&crc_ret, KV_CRYPTO_CRC_SIZE);
+#else
+    (void)memcpy_s((void *)(calculated_hash + KV_CRYPTO_HASH_SIZE - KV_CRYPTO_CRC_SIZE), KV_CRYPTO_CRC_SIZE,
+        (const void *)&crc_ret, KV_CRYPTO_CRC_SIZE);
+#endif /* (CONFIG_NV_SUPPORT_HASH_FOR_CRYPT == NV_YES) */
+#endif /* #if (CONFIG_NV_SUPPORT_ENCRYPT == NV_YES) */
+}
+
+STATIC errcode_t kv_key_hash_crc_tag_verify(kv_key_handle_t *key, uint8_t *read_hash_crc, uint8_t *cal_hash_crc,
+    uint32_t crypto_handle, bool only_crc)
+{
+    unused(crypto_handle);
+    unused(only_crc);
+    errcode_t res = ERRCODE_SUCC;
+
+    if (key->header.enc_key != AES_KDFKEY_SDRK_TYPE) {
+        if (memcmp(cal_hash_crc, read_hash_crc, KV_CRYPTO_CRC_SIZE) != 0) {
+            res = ERRCODE_NV_HASH_MISMATCH;
+        }
+        return res;
+    }
+
+#if (CONFIG_NV_SUPPORT_ENCRYPT != NV_YES)
+    /* 不支持加密的情况下直接返回失败 */
+    return ERRCODE_NV_HASH_MISMATCH;
+#else
+    if (only_crc) {
+        /* 只校验CRC的场景,校验最后4个字节的CRC(密文的CRC) */
+        if (memcmp(cal_hash_crc + KV_CRYPTO_HASH_SIZE - KV_CRYPTO_CRC_SIZE,
+            read_hash_crc + KV_CRYPTO_HASH_SIZE - KV_CRYPTO_CRC_SIZE, KV_CRYPTO_CRC_SIZE) != 0) {
+            res = ERRCODE_NV_HASH_MISMATCH;
+        }
+        return res;
+    }
+#if (CONFIG_NV_SUPPORT_HASH_FOR_CRYPT == NV_YES)
+    /* 使用HASH校验的场景,校验HASH的前28个字节 */
+    if (memcmp(cal_hash_crc, read_hash_crc, KV_CRYPTO_HASH_SIZE - KV_CRYPTO_CRC_SIZE) != 0) {
+        res = ERRCODE_NV_HASH_MISMATCH;
+    }
+    return res;
+#else
+    /* 使用GCM TAG的场景,直接校验16字节的TAG */
+    return nv_crypto_validate_tag(crypto_handle);
+#endif /* (CONFIG_NV_SUPPORT_HASH_FOR_CRYPT == NV_YES)) */
+#endif /* #if (CONFIG_NV_SUPPORT_ENCRYPT != NV_YES) */
+}
+
+STATIC errcode_t kv_key_validate_hash_chunks(kv_key_handle_t *key, uint8_t *read_data_chunk, uint8_t *cal_hash_crc,
+    uint32_t crypto_handle, bool ignor_invalid)
+{
+    errcode_t res;
+    kv_key_header_t *key_header = (kv_key_header_t *)read_data_chunk;
+    uintptr_t key_location = (uintptr_t)key->key_location;
+    uint32_t crc_ret = 0;
+    uint32_t hash_crc_len = ((key->header.enc_key == AES_KDFKEY_SDRK_TYPE) ? KV_CRYPTO_HASH_SIZE : KV_CRYPTO_CRC_SIZE);
+
+    kv_key_hash_crc_tag_start(key, &crc_ret);
+
+    /* Read header first, which is never encrypted */
+    res = kv_key_read_data_from_flash((uintptr_t)read_data_chunk, key_location,
+        sizeof(kv_key_header_t), INVAILD_CRYPTO_HANDLE);
+    if (res != ERRCODE_SUCC) {
+        return res;
+    }
+
+    kv_key_fix_header_for_validate(key_header, ignor_invalid);
+
+    kv_key_hash_crc_tag_update(key, read_data_chunk, sizeof(kv_key_header_t), &crc_ret);
+
+    const kv_attributes_t attributes = kv_key_attributes(key);
+    uint32_t decryptable_data_len = kv_key_padded_data_length(attributes, key->header.length);
+#if (CONFIG_NV_SUPPORT_HASH_FOR_CRYPT == NV_NO)
+    if (crypto_handle != INVAILD_CRYPTO_HANDLE) {
+        /* 在使用GCM TAG时,先读取一次TAG并设置给解密模块 */
+        /* Read key hash, which could be unencrypted */
+        uintptr_t hash_location = key_location + (uintptr_t)sizeof(kv_key_header_t) + (uintptr_t)decryptable_data_len;
+        (void)kv_key_read_data_from_flash((uintptr_t)read_data_chunk, hash_location,
+            KV_CRYPTO_HASH_SIZE, INVAILD_CRYPTO_HANDLE);
+        (void)nv_crypto_set_tag(crypto_handle, read_data_chunk, NV_AES_GCM_TAG_LENGTH);
+    }
+#endif
+
+    /* Read rest of key data, which could be encrypted */
+    uint32_t key_data_offset = 0;
+    key_location += (uintptr_t)sizeof(kv_key_header_t);
+    while (key_data_offset < decryptable_data_len) {
+        uint32_t chunk_len = uapi_min(NV_KEY_DATA_CHUNK_LEN, decryptable_data_len - key_data_offset);
+
+        res = kv_key_read_data_from_flash((uintptr_t)read_data_chunk, (key_location + key_data_offset),
+                                          chunk_len, crypto_handle);
+        if (res != ERRCODE_SUCC) {
+            return res;
+        }
+
+        kv_key_hash_crc_tag_update(key, read_data_chunk, chunk_len, &crc_ret);
+        key_data_offset += chunk_len;
+    }
+
+    /* Read key hash, which could be unencrypted */
+    res = kv_key_read_data_from_flash((uintptr_t)read_data_chunk, (key_location + key_data_offset),
+                                      hash_crc_len, INVAILD_CRYPTO_HANDLE);
+
+    kv_key_hash_crc_tag_finish(key, cal_hash_crc, crc_ret, crypto_handle);
+    return res;
+}
+
+/*
+ * 校验KEY的完整性。
+ * 非加密KEY, 校验CRC;
+ * 加密KEY, 如CONFIG_NV_SUPPORT_HASH_FOR_CRYPT为YES,校验明文HASH;
+ *          如CONFIG_NV_SUPPORT_HASH_FOR_CRYPT为NO,校验密文的CRC(CRC存放在16字节Tag之后)。
+ */
+errcode_t kv_key_validate_integrity(kv_key_handle_t *key, bool ignor_invalid)
+{
+    uint32_t crypto_handle = INVAILD_CRYPTO_HANDLE;
+
+    if (key->header.length > NV_NORMAL_KVALUE_MAX_LEN) {
+        return ERRCODE_NV_INVALID_KEY_HEADER;
+    }
+
+    uint8_t *calculated_hash = (uint8_t *)kv_malloc(KV_CRYPTO_HASH_SIZE);
+    if (calculated_hash == NULL) {
+        return ERRCODE_MALLOC;
+    }
+
+    uint8_t *read_data_chunk = (uint8_t *)kv_malloc(NV_KEY_DATA_CHUNK_LEN);
+    if (read_data_chunk == NULL) {
+        kv_free(calculated_hash);
+        return ERRCODE_MALLOC;
+    }
+
+    errcode_t res = kv_key_validate_hash_chunks(key, read_data_chunk, calculated_hash, crypto_handle, ignor_invalid);
+    if (res != ERRCODE_SUCC) {
+        goto err;
+    }
+
+    res = kv_key_hash_crc_tag_verify(key, read_data_chunk, calculated_hash, crypto_handle, true);
+
+err:
+    kv_free(read_data_chunk);
+    kv_free(calculated_hash);
+    return res;
+}
+
+/*
+ * 校验KEY的正确性:
+ * 非加密KEY校验CRC
+ * 加密KEY, 如CONFIG_NV_SUPPORT_HASH_FOR_CRYPT为YES,校验明文HASH;
+ *          如CONFIG_NV_SUPPORT_HASH_FOR_CRYPT为NO,则校验GCM Tag。
+ */
+errcode_t kv_key_validation(kv_key_handle_t *key, bool ignor_invalid)
+{
+    errcode_t res;
+    uint32_t crypto_handle = INVAILD_CRYPTO_HANDLE;
+
+    if (key->header.length > NV_NORMAL_KVALUE_MAX_LEN) {
+        return ERRCODE_NV_INVALID_KEY_HEADER;
+    }
+
+    uint8_t *calculated_hash = (uint8_t *)kv_malloc(KV_CRYPTO_HASH_SIZE);
+    if (calculated_hash == NULL) {
+        return ERRCODE_MALLOC;
+    }
+    (void)memset_s(calculated_hash, KV_CRYPTO_HASH_SIZE, 0, KV_CRYPTO_HASH_SIZE);
+
+    uint8_t *read_data_chunk = (uint8_t *)kv_malloc(NV_KEY_DATA_CHUNK_LEN);
+    if (read_data_chunk == NULL) {
+        kv_free(calculated_hash);
+        return ERRCODE_MALLOC;
+    }
+
+    (void)memset_s(read_data_chunk, NV_KEY_DATA_CHUNK_LEN, 0, NV_KEY_DATA_CHUNK_LEN);
+
+#if (CONFIG_NV_SUPPORT_ENCRYPT == NV_YES)
+    if (key->header.enc_key != 0) {
+        /* Read key data, using AES engine if encrypted */
+        res = nv_crypto_claim_aes(&crypto_handle, &(key->header));
+        if (res != ERRCODE_SUCC) {
+            goto err;
+        }
+    }
+#endif
+
+    res = kv_key_validate_hash_chunks(key, read_data_chunk, calculated_hash, crypto_handle, ignor_invalid);
+    if (res != ERRCODE_SUCC) {
+        goto err;
+    }
+
+    res = kv_key_hash_crc_tag_verify(key, read_data_chunk, calculated_hash, crypto_handle, false);
+
+err:
+    kv_free(read_data_chunk);
+    kv_free(calculated_hash);
+
+#if (CONFIG_NV_SUPPORT_ENCRYPT == NV_YES)
+    if (crypto_handle != INVAILD_CRYPTO_HANDLE) {
+        nv_crypto_release_aes(crypto_handle);
+    }
+#endif
+    return res;
+}
+
+kv_attributes_t kv_key_attributes(const kv_key_handle_t *key)
+{
+    kv_attributes_t attributes = 0;
+
+    if (key->header.type != KV_KEY_TYPE_NORMAL) {
+        attributes = (kv_attributes_t)((uint32_t)attributes | (uint32_t)KV_ATTRIBUTE_PERMANENT);
+    }
+    if (key->header.enc_key != 0) {
+        attributes = (kv_attributes_t)((uint32_t)attributes | (uint32_t)KV_ATTRIBUTE_ENCRYPTED);
+    }
+    if (key->header.upgrade != KV_KEY_TYPE_NORMAL) {
+        attributes = (kv_attributes_t)((uint32_t)attributes | (uint32_t)KV_ATTRIBUTE_NON_UPGRADE);
+    }
+    return attributes;
+}
+
+uint16_t kv_key_padded_data_length(kv_attributes_t attributes, uint16_t unpadded_length)
+{
+    if (((uint32_t)attributes & (uint32_t)KV_ATTRIBUTE_ENCRYPTED) != 0) {
+        return kv_padded_ciphertext_length(unpadded_length);
+    } else {
+        return kv_padded_cleartext_length(unpadded_length);
+    }
+}
+
+uint16_t kv_key_flash_size(kv_key_handle_t *key)
+{
+    uint16_t size;
+    kv_attributes_t attributes;
+    uint16_t hash_crc_size;
+
+    if (key->header.enc_key == AES_KDFKEY_SDRK_TYPE) {
+        hash_crc_size = KV_CRYPTO_HASH_SIZE;
+    } else {
+        hash_crc_size = KV_CRYPTO_CRC_SIZE;
+    }
+
+    size = (uint16_t)sizeof(kv_key_header_t) + hash_crc_size;
+
+    attributes = kv_key_attributes(key);
+    size += kv_key_padded_data_length(attributes, key->header.length);
+
+    return size;
+}
+
+void kv_key_build_from_new(kv_key_handle_t *key, const kv_key_details_t *new_key, kv_key_location key_location)
+{
+    key->header.key_id = new_key->key_id;
+    key->header.length = (uint16_t)new_key->kvalue_length;
+    key->header.magic = g_nv_header_magic;
+    key->header.valid = KV_KEY_VALID;
+    key->header.type = KV_KEY_TYPE_NORMAL;
+    if (((uint32_t)new_key->attributes & (uint32_t)KV_ATTRIBUTE_PERMANENT) != 0) {
+        key->header.type = KV_KEY_TYPE_PERMANENT;
+    }
+    key->header.upgrade = KV_KEY_TYPE_NORMAL;
+    if (((uint32_t)new_key->attributes & (uint32_t)KV_ATTRIBUTE_NON_UPGRADE) != 0) {
+        key->header.upgrade = 0;
+        key->header.version = key->header.version + 1;
+    }
+    key->header.enc_key = 0;
+    if (((uint32_t)new_key->attributes & (uint32_t)KV_ATTRIBUTE_ENCRYPTED) != 0) {
+        key->header.enc_key = AES_KDFKEY_SDRK_TYPE;
+#if (CONFIG_NV_SUPPORT_ENCRYPT == NV_YES)
+        nv_crypto_generate_random(&key->header.rnd);
+#endif
+        key->header.version = key->header.version + 1;
+    }
+
+    key->key_location = key_location;
+}
+
+uint32_t kv_crc32_swap(uint32_t crc)
+{
+    return ((crc >> CRC_SWAP_SIZE24) | ((crc >> CRC_SWAP_SIZE8) & 0xFF00) |
+        ((crc << CRC_SWAP_SIZE8) & 0xFF0000) | (crc << CRC_SWAP_SIZE24));
 }
\ No newline at end of file
index 33c36a1..52f4988 100755 (executable)
-/*\r
- * Copyright (c) @CompanyNameMagicTag 2019-2022. All rights reserved.\r
- * Description: KV Storage Library key access interface\r
- */\r
-\r
-#ifndef NV_KEY_H\r
-#define NV_KEY_H\r
-\r
-#include "stdbool.h"\r
-#include "errcode.h"\r
-\r
-#ifdef __cplusplus\r
-#if __cplusplus\r
-extern "C" {\r
-#endif /* __cplusplus */\r
-#endif /* __cplusplus */\r
-\r
-#define KV_KEY_MAGIC      0xA9\r
-#define KV_KEY_VALID      0xFF\r
-#define KV_KEY_INVALID    0\r
-#define KV_KEY_NO_MAGIC   0xFF\r
-\r
-#define KV_KEY_TYPE_NORMAL     0xFF\r
-#define KV_KEY_TYPE_PERMANENT  0\r
-\r
-#define KV_KEY_FORCE_UPDATE    0xf0\r
-\r
-#define KV_CRYPTO_HASH_SIZE     32\r
-#define KV_CRYPTO_CRC_SIZE      4\r
-#define KV_CRYPTO_CRC32_SIZE    32\r
-#define AES_BLOCK_SIZE          16\r
-#define NV_AES_GCM_TAG_LENGTH   16\r
-#define MIN_AES_DECRYPT_LEN     (2 * AES_BLOCK_SIZE)\r
-#define AES_KDFKEY_SDRK_TYPE    0x52\r
-#define CRC_SWAP_SIZE8          8\r
-#define CRC_SWAP_SIZE24         24\r
-#define INVAILD_CRYPTO_HANDLE   0xFFFFFFFF\r
-\r
-typedef enum {\r
-    KV_KEY_FILTER_STATE_VALID    = 0x01,\r
-    KV_KEY_FILTER_STATE_INVALID  = 0x02,\r
-    KV_KEY_FILTER_STATE_ANY      = 0x03\r
-} kv_key_filter_state_t;\r
-\r
-typedef enum {\r
-    KV_KEY_FILTER_TYPE_NORMAL    = 0x01,\r
-    KV_KEY_FILTER_TYPE_PERMANENT = 0x02,\r
-    KV_KEY_FILTER_TYPE_ANY       = 0x03\r
-} kv_key_filter_type_t;\r
-\r
-/**\r
- * KV key attribute flags\r
- */\r
-typedef enum {\r
-    KV_ATTRIBUTE_PERMANENT   = 0x1,    /* Key is permanent and can't be deleted or modified */\r
-    KV_ATTRIBUTE_ENCRYPTED   = 0x2,    /* Key is encrypted in flash */\r
-    KV_ATTRIBUTE_NON_UPGRADE = 0x4     /* key cannot be modified during the upgrade. */\r
-} kv_attributes_t;\r
-\r
-typedef enum {\r
-    KV_KEY_NOT_VALIDATE,\r
-    KV_KEY_VALIDATE_CORRECT,\r
-    KV_KEY_VALIDATE_WRONG\r
-} kv_key_validate_status_t;\r
-\r
-typedef uint16_t kv_key_id;\r
-\r
-/** Represents the location in flash of a KV key.  Provided in such a way that it can't be dereferenced,\r
- * as flash is not directly addressable */\r
-typedef const void *kv_key_location;\r
-\r
-/** Defines a set of conditions to match when searching through stores for keys */\r
-typedef struct {\r
-    kv_key_location      location;  /* (retained) location is out of context here */\r
-    kv_key_id            pattern;   /* Pattern of bits matched against a key_id, after mask has been applied */\r
-    kv_key_id            mask;      /* Mask is applied to a key id before matching pattern */\r
-    kv_key_filter_state_t  state;     /* Include only keys of the specified state in search results */\r
-    kv_key_filter_type_t   type;      /* Include only keys of the specified type in search results */\r
-} kv_key_filter_t;\r
-\r
-/** KV store key header */\r
-typedef struct {\r
-    uint8_t   magic;     /* Magic number to indicate the start of the item              */\r
-    uint8_t   valid;     /* flag to indicate whether the value is valid.                */\r
-    uint16_t  length;    /* Length of the key_data field in bytes                       */\r
-    uint8_t   type;      /* Normal (0xFF) or permanent (0x00)                           */\r
-    uint8_t   upgrade;   /* Indicating whether upgradeable(not.0x00)                    */\r
-    uint16_t  key_id;    /* The Key ID                                                  */\r
-    uint16_t  enc_key;   /* Allows some customisation of the data AES key used,         */\r
-                       /* 0x0 - key_data is plaintext, Others - key_data is encrypted   */\r
-    uint16_t  version;   /* Version of the key                                          */\r
-    uint32_t  rnd;       /* align the header to be 16bytes, random number               */\r
-} kv_key_header_t;\r
-\r
-/** A KV key handle, which provides both key header information and the location of key data in flash */\r
-typedef struct {\r
-    kv_key_header_t    header;\r
-    kv_key_location  key_location;   /* Location in flash of the KV key */\r
-} kv_key_handle_t;\r
-\r
-typedef struct {\r
-    kv_key_id key_id;\r
-    bool focre_write;\r
-    const uint8_t *kvalue;\r
-    uint32_t kvalue_length;\r
-    kv_attributes_t attributes;\r
-} kv_key_details_t;\r
-typedef struct {\r
-    uint32_t crypto_handle;\r
-    uint8_t *key_data_chunk;\r
-    uint8_t *compare_data_chunk;\r
-} kv_helper_compare_key_data_info_t;\r
-\r
-extern uint8_t g_nv_header_magic;\r
-\r
-errcode_t kv_key_helper_copy_flash(uint32_t dest_location, uint32_t src_location, uint16_t length);\r
-errcode_t kv_key_direct_write_flash(uint32_t dest, uint32_t length, const uint8_t *src);\r
-errcode_t kv_key_direct_erase_flash(uint32_t dest, const uint32_t size);\r
-errcode_t kv_key_write_flash(uint32_t dest, uint32_t length, const uint8_t *src);\r
-errcode_t kv_key_erase_flash(uint32_t dest, const uint32_t size);\r
-bool kv_key_is_erased(const kv_key_handle_t *key);\r
-errcode_t kv_key_validate_integrity(kv_key_handle_t *key, bool ignor_invalid);\r
-errcode_t kv_key_validation(kv_key_handle_t *key, bool ignor_invalid);\r
-bool kv_key_is_valid(kv_key_handle_t *key);\r
-errcode_t kv_key_does_pattern_match(const kv_key_handle_t *key, kv_key_id search_pattern, kv_key_id search_mask);\r
-errcode_t kv_key_does_filter_match(kv_key_handle_t *key, kv_key_filter_t *search_filter);\r
-errcode_t kv_key_get_handle_from_location(kv_key_location key_location, kv_key_handle_t *key);\r
-errcode_t kv_key_locations_in_same_page(kv_key_location first_key_location, kv_key_location second_key_location);\r
-errcode_t kv_key_get_next_handle(kv_key_handle_t *key, kv_key_validate_status_t key_status);\r
-kv_attributes_t kv_key_attributes(const kv_key_handle_t *key);\r
-uint16_t   kv_key_padded_data_length(kv_attributes_t attributes, uint16_t unpadded_length);\r
-uint16_t   kv_key_flash_size(kv_key_handle_t *key);\r
-errcode_t kv_key_read_data(kv_key_handle_t *key, uint8_t *dest_location);\r
-errcode_t kv_helper_compare_key_data(kv_key_handle_t *key, const uint8_t *compare_data, uint16_t compare_length);\r
-void kv_key_build_from_new(kv_key_handle_t *key, const kv_key_details_t *new_key, kv_key_location key_location);\r
-errcode_t kv_key_get_next_magic_position(kv_key_location key_location, kv_key_handle_t *key);\r
-\r
-uint32_t kv_crc32_swap(uint32_t crc);\r
-\r
-#ifdef __cplusplus\r
-#if __cplusplus\r
-}\r
-#endif /* __cplusplus */\r
-#endif /* __cplusplus */\r
-\r
-#endif  /* NV_KEY_H */\r
+/*
+ * Copyright (c) @CompanyNameMagicTag 2019-2022. All rights reserved.
+ * Description: KV Storage Library key access interface
+ */
+
+#ifndef NV_KEY_H
+#define NV_KEY_H
+
+#include "stdbool.h"
+#include "errcode.h"
+
+#ifdef __cplusplus
+#if __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+#define KV_KEY_MAGIC      0xA9
+#define KV_KEY_VALID      0xFF
+#define KV_KEY_INVALID    0
+#define KV_KEY_NO_MAGIC   0xFF
+
+#define KV_KEY_TYPE_NORMAL     0xFF
+#define KV_KEY_TYPE_PERMANENT  0
+
+#define KV_KEY_FORCE_UPDATE    0xf0
+
+#define KV_CRYPTO_HASH_SIZE     32
+#define KV_CRYPTO_CRC_SIZE      4
+#define KV_CRYPTO_CRC32_SIZE    32
+#define AES_BLOCK_SIZE          16
+#define NV_AES_GCM_TAG_LENGTH   16
+#define MIN_AES_DECRYPT_LEN     (2 * AES_BLOCK_SIZE)
+#define AES_KDFKEY_SDRK_TYPE    0x52
+#define CRC_SWAP_SIZE8          8
+#define CRC_SWAP_SIZE24         24
+#define INVAILD_CRYPTO_HANDLE   0xFFFFFFFF
+
+typedef enum {
+    KV_KEY_FILTER_STATE_VALID    = 0x01,
+    KV_KEY_FILTER_STATE_INVALID  = 0x02,
+    KV_KEY_FILTER_STATE_ANY      = 0x03
+} kv_key_filter_state_t;
+
+typedef enum {
+    KV_KEY_FILTER_TYPE_NORMAL    = 0x01,
+    KV_KEY_FILTER_TYPE_PERMANENT = 0x02,
+    KV_KEY_FILTER_TYPE_ANY       = 0x03
+} kv_key_filter_type_t;
+
+/**
+ * KV key attribute flags
+ */
+typedef enum {
+    KV_ATTRIBUTE_PERMANENT   = 0x1,    /* Key is permanent and can't be deleted or modified */
+    KV_ATTRIBUTE_ENCRYPTED   = 0x2,    /* Key is encrypted in flash */
+    KV_ATTRIBUTE_NON_UPGRADE = 0x4     /* key cannot be modified during the upgrade. */
+} kv_attributes_t;
+
+typedef enum {
+    KV_KEY_NOT_VALIDATE,
+    KV_KEY_VALIDATE_CORRECT,
+    KV_KEY_VALIDATE_WRONG
+} kv_key_validate_status_t;
+
+typedef uint16_t kv_key_id;
+
+/** Represents the location in flash of a KV key.  Provided in such a way that it can't be dereferenced,
+ * as flash is not directly addressable */
+typedef const void *kv_key_location;
+
+/** Defines a set of conditions to match when searching through stores for keys */
+typedef struct {
+    kv_key_location      location;  /* (retained) location is out of context here */
+    kv_key_id            pattern;   /* Pattern of bits matched against a key_id, after mask has been applied */
+    kv_key_id            mask;      /* Mask is applied to a key id before matching pattern */
+    kv_key_filter_state_t  state;     /* Include only keys of the specified state in search results */
+    kv_key_filter_type_t   type;      /* Include only keys of the specified type in search results */
+} kv_key_filter_t;
+
+/** KV store key header */
+typedef struct {
+    uint8_t   magic;     /* Magic number to indicate the start of the item              */
+    uint8_t   valid;     /* flag to indicate whether the value is valid.                */
+    uint16_t  length;    /* Length of the key_data field in bytes                       */
+    uint8_t   type;      /* Normal (0xFF) or permanent (0x00)                           */
+    uint8_t   upgrade;   /* Indicating whether upgradeable(not.0x00)                    */
+    uint16_t  key_id;    /* The Key ID                                                  */
+    uint16_t  enc_key;   /* Allows some customisation of the data AES key used,         */
+                       /* 0x0 - key_data is plaintext, Others - key_data is encrypted   */
+    uint16_t  version;   /* Version of the key                                          */
+    uint32_t  rnd;       /* align the header to be 16bytes, random number               */
+} kv_key_header_t;
+
+/** A KV key handle, which provides both key header information and the location of key data in flash */
+typedef struct {
+    kv_key_header_t    header;
+    kv_key_location  key_location;   /* Location in flash of the KV key */
+} kv_key_handle_t;
+
+typedef struct {
+    kv_key_id key_id;
+    bool focre_write;
+    const uint8_t *kvalue;
+    uint32_t kvalue_length;
+    kv_attributes_t attributes;
+} kv_key_details_t;
+typedef struct {
+    uint32_t crypto_handle;
+    uint8_t *key_data_chunk;
+    uint8_t *compare_data_chunk;
+} kv_helper_compare_key_data_info_t;
+
+extern uint8_t g_nv_header_magic;
+
+errcode_t kv_key_helper_copy_flash(uint32_t dest_location, uint32_t src_location, uint16_t length);
+errcode_t kv_key_direct_write_flash(uint32_t dest, uint32_t length, const uint8_t *src);
+errcode_t kv_key_direct_erase_flash(uint32_t dest, const uint32_t size);
+errcode_t kv_key_write_flash(uint32_t dest, uint32_t length, const uint8_t *src);
+errcode_t kv_key_erase_flash(uint32_t dest, const uint32_t size);
+bool kv_key_is_erased(const kv_key_handle_t *key);
+errcode_t kv_key_validate_integrity(kv_key_handle_t *key, bool ignor_invalid);
+errcode_t kv_key_validation(kv_key_handle_t *key, bool ignor_invalid);
+bool kv_key_is_valid(kv_key_handle_t *key);
+errcode_t kv_key_does_pattern_match(const kv_key_handle_t *key, kv_key_id search_pattern, kv_key_id search_mask);
+errcode_t kv_key_does_filter_match(kv_key_handle_t *key, kv_key_filter_t *search_filter);
+errcode_t kv_key_get_handle_from_location(kv_key_location key_location, kv_key_handle_t *key);
+errcode_t kv_key_locations_in_same_page(kv_key_location first_key_location, kv_key_location second_key_location);
+errcode_t kv_key_get_next_handle(kv_key_handle_t *key, kv_key_validate_status_t key_status);
+kv_attributes_t kv_key_attributes(const kv_key_handle_t *key);
+uint16_t   kv_key_padded_data_length(kv_attributes_t attributes, uint16_t unpadded_length);
+uint16_t   kv_key_flash_size(kv_key_handle_t *key);
+errcode_t kv_key_read_data(kv_key_handle_t *key, uint8_t *dest_location);
+errcode_t kv_helper_compare_key_data(kv_key_handle_t *key, const uint8_t *compare_data, uint16_t compare_length);
+void kv_key_build_from_new(kv_key_handle_t *key, const kv_key_details_t *new_key, kv_key_location key_location);
+errcode_t kv_key_get_next_magic_position(kv_key_location key_location, kv_key_handle_t *key);
+
+uint32_t kv_crc32_swap(uint32_t crc);
+
+#ifdef __cplusplus
+#if __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+#endif  /* NV_KEY_H */
index 3348cb0..225c63c 100755 (executable)
-/*\r
- * Copyright (c) @CompanyNameMagicTag 2019-2022. All rights reserved.\r
- * Description: KV Storage Library non-volatile region access module implementation\r
- */\r
-\r
-#include "nv_nvregion.h"\r
-#include "nv_page.h"\r
-#include "nv_store.h"\r
-#include "nv_porting.h"\r
-#include "nv_config.h"\r
-#include "common_def.h"\r
-#ifndef CONFIG_NV_SUPPORT_SINGLE_CORE_SYSTEM\r
-#include "flash_task_mutex.h"\r
-#include "flash_task_adapt.h"\r
-#endif\r
-\r
-static kv_nvregion_map_t g_kv_nvregion_map = {NULL, NULL, 0};\r
-static kv_nvregion_area_t g_kv_nvregion_area = {KV_STORE_START_ADDR, KV_STORE_DATA_SIZE,\r
-    KV_BACKUP_START_ADDR, KV_BACKUP_DATA_SIZE};\r
-uint32_t g_kv_nvregion_use_times[KV_STORE_DATA_SIZE / KV_PAGE_SIZE] = {0};\r
-\r
-kv_nvregion_map_t* kv_nvregion_get_map(void)\r
-{\r
-    return &g_kv_nvregion_map;\r
-}\r
-\r
-uint32_t kv_nvregion_get_use_times(kv_page_location page_location)\r
-{\r
-    uint32_t page_number = kv_nvregion_get_page_number(page_location);\r
-    if (page_number >= g_kv_nvregion_map.num_entries) {\r
-        return (uint32_t)-1;\r
-    }\r
-\r
-    return g_kv_nvregion_map.entries[page_number].sequence_number;\r
-}\r
-\r
-static void kv_nvregion_clear_map_entry(kv_page_header_t *map_entry)\r
-{\r
-    (void)memset_s(map_entry, sizeof(kv_page_header_t), 0, sizeof(kv_page_header_t));\r
-}\r
-\r
-static errcode_t kv_nvregion_is_valid_map_entry(const kv_page_header_t *map_entry)\r
-{\r
-    if ((map_entry->details.store_id != 0) && (map_entry->details.store_id != 0xFFFF) &&\r
-        (~map_entry->inverted_details_word == *(uint32_t *)(uintptr_t)&map_entry->details) &&\r
-        (~map_entry->inverted_sequence_number == map_entry->sequence_number)) {\r
-            return ERRCODE_SUCC;\r
-    }\r
-    return ERRCODE_FAIL;\r
-}\r
-\r
-static void kv_nvregion_filter_duplicate_map_entries(kv_page_header_t *new_entry)\r
-{\r
-    kv_page_header_t *existing_entry = g_kv_nvregion_map.entries;\r
-    while (existing_entry < new_entry) {\r
-        if ((existing_entry->details.store_id == new_entry->details.store_id) &&\r
-            (existing_entry->details.page_index == new_entry->details.page_index)) {\r
-            if (existing_entry->sequence_number <= new_entry->sequence_number) {\r
-                /* An existing map entry is older than the new one, use the new one */\r
-                /* Two entries have the same sequence number.  This is unexpected. */\r
-                /* For the moment use the new entry, but it could be better to try and determine based on content */\r
-                /* e.g. amount of free space, number of erased keys, corrupted keys */\r
-                kv_nvregion_clear_map_entry(existing_entry);\r
-            } else {\r
-                /* An existing map entry is more recent than the new one */\r
-                kv_nvregion_clear_map_entry(new_entry);\r
-                break;\r
-            }\r
-        }\r
-        existing_entry++;\r
-    }\r
-}\r
-\r
-STATIC void kv_nvregion_free_resource(void)\r
-{\r
-    if (g_kv_nvregion_map.entries != NULL) {\r
-        kv_free(g_kv_nvregion_map.entries);\r
-        g_kv_nvregion_map.entries = NULL;\r
-    }\r
-    if (g_kv_nvregion_map.page_status_map != NULL) {\r
-        kv_free(g_kv_nvregion_map.page_status_map);\r
-        g_kv_nvregion_map.page_status_map = NULL;\r
-    }\r
-}\r
-\r
-STATIC errcode_t kv_nvregion_init_map(void)\r
-{\r
-    /* Create blank NV region map */\r
-    uint32_t num_entries = g_kv_nvregion_area.nv_data_size / KV_PAGE_SIZE;\r
-    if (num_entries == 0) {\r
-        return ERRCODE_NV_INVALID_PARAMS;\r
-    }\r
-\r
-    /* Obtain details of NV memory region */\r
-    if (((g_kv_nvregion_area.nv_data_addr & (KV_PAGE_SIZE - 1)) != 0) ||\r
-        ((g_kv_nvregion_area.nv_data_size & (KV_PAGE_SIZE - 1)) != 0) ||\r
-        ((g_kv_nvregion_area.nv_data_size & ~(KV_PAGE_SIZE - 1)) == 0)) {\r
-        /* NV Data address or size not aligned to a page boundry */\r
-        return ERRCODE_FAIL;\r
-    }\r
-\r
-    /* Free up any existing NV region map */\r
-    if (num_entries != g_kv_nvregion_map.num_entries) {\r
-        kv_nvregion_free_resource();\r
-    }\r
-\r
-    if (g_kv_nvregion_map.entries == NULL) {\r
-        g_kv_nvregion_map.entries = (kv_page_header_t *)kv_malloc(num_entries * sizeof(kv_page_header_t));\r
-    }\r
-\r
-    if (g_kv_nvregion_map.page_status_map == NULL) {\r
-        g_kv_nvregion_map.page_status_map =\r
-            (nv_page_status_map_t *)kv_malloc(num_entries * sizeof(nv_page_status_map_t));\r
-    }\r
-\r
-    if ((g_kv_nvregion_map.entries == NULL) || (g_kv_nvregion_map.page_status_map == NULL)) {\r
-        kv_nvregion_free_resource();\r
-        return ERRCODE_MALLOC;\r
-    }\r
-\r
-    (void)memset_s(g_kv_nvregion_map.entries, num_entries * sizeof(kv_page_header_t), 0,\r
-        num_entries * sizeof(kv_page_header_t));\r
-    (void)memset_s(g_kv_nvregion_map.page_status_map, num_entries * sizeof(nv_page_status_map_t), 0,\r
-        num_entries * sizeof(nv_page_status_map_t));\r
-    g_kv_nvregion_map.num_entries = num_entries;\r
-    return ERRCODE_SUCC;\r
-}\r
-\r
-static errcode_t kv_nvregion_build_map(void)\r
-{\r
-    errcode_t ret;\r
-    unused(ret);\r
-    uint32_t nv_page = g_kv_nvregion_area.nv_data_addr;\r
-\r
-    for (uint32_t i = 0; i < g_kv_nvregion_map.num_entries; i++) {\r
-        kv_page_header_t *new_entry = &g_kv_nvregion_map.entries[i];\r
-        ret = kv_key_helper_copy_flash((uint32_t)(uintptr_t)new_entry, (uint32_t)nv_page, sizeof(kv_page_header_t));\r
-\r
-        if (kv_nvregion_is_valid_map_entry(new_entry) == ERRCODE_SUCC\r
-            && new_entry->details.store_id != KV_STORE_ID_BACKUP) {\r
-            if (new_entry->details.ver == 0) {\r
-                g_nv_header_magic = KV_KEY_NO_MAGIC;\r
-            }\r
-            kv_nvregion_filter_duplicate_map_entries(new_entry);\r
-            kv_page_handle_t page;\r
-            page.page_location = (kv_page_location)(uintptr_t)nv_page;\r
-            kv_page_read_status_to_map(&page, &(g_kv_nvregion_map.page_status_map[i]));\r
-        } else {\r
-            kv_nvregion_clear_map_entry(new_entry);\r
-        }\r
-\r
-        nv_page += KV_PAGE_SIZE;\r
-    }\r
-    nv_log_debug("[NV] g_nv_header_magic = 0x%x.\r\n", g_nv_header_magic);\r
-    return ERRCODE_SUCC;\r
-}\r
-\r
-void kv_nvregion_init(uint32_t nv_data_addr, uint32_t nv_data_size, uint32_t nv_backup_addr, uint32_t nv_backup_size)\r
-{\r
-    g_kv_nvregion_area.nv_data_addr = nv_data_addr;\r
-    g_kv_nvregion_area.nv_data_size = nv_data_size;\r
-    g_kv_nvregion_area.nv_backup_addr =  nv_backup_addr;\r
-    g_kv_nvregion_area.nv_backup_size = nv_backup_size;\r
-}\r
-\r
-kv_nvregion_area_t* nv_get_region_area(void)\r
-{\r
-    return  &g_kv_nvregion_area;\r
-}\r
-\r
-errcode_t kv_nvregion_scan(void)\r
-{\r
-    errcode_t res;\r
-    res = kv_nvregion_init_map();\r
-    if (res != ERRCODE_SUCC) {\r
-        return res;\r
-    }\r
-    return kv_nvregion_build_map();\r
-}\r
-\r
-errcode_t kv_nvregion_create_page(uint16_t store_id, uint8_t page_index)\r
-{\r
-    errcode_t res;\r
-    kv_page_location page_location;\r
-\r
-    if ((g_kv_nvregion_map.entries == NULL) || (g_kv_nvregion_map.num_entries == 0)) {\r
-        return ERRCODE_NV_NOT_INITIALISED;\r
-    }\r
-    if (store_id == 0) {\r
-        return ERRCODE_INVALID_PARAM;\r
-    }\r
-\r
-    res = kv_nvregion_find_unused_page(&page_location);\r
-    if (res != ERRCODE_SUCC) {\r
-        return res;\r
-    }\r
-\r
-    res = kv_nvregion_erase_page(page_location);\r
-    if (res != ERRCODE_SUCC) {\r
-        return res;\r
-    }\r
-\r
-    res = kv_nvregion_write_page(page_location, store_id, page_index);\r
-    if (res != ERRCODE_SUCC) {\r
-        return res;\r
-    }\r
-\r
-    return kv_nvregion_scan();\r
-}\r
-\r
-errcode_t kv_nvregion_find_page(uint16_t store_id, uint8_t page_index,\r
-                                kv_page_location *location, kv_page_header_t *header)\r
-{\r
-    if ((g_kv_nvregion_map.entries == NULL) || (g_kv_nvregion_map.num_entries == 0)) {\r
-        return ERRCODE_NV_NOT_INITIALISED;\r
-    }\r
-    if (store_id == 0) {\r
-        return ERRCODE_INVALID_PARAM;\r
-    }\r
-    for (uint32_t i = 0; i < g_kv_nvregion_map.num_entries; i++) {\r
-        kv_page_header_t *map_entry = &g_kv_nvregion_map.entries[i];\r
-        if ((map_entry->details.store_id == store_id) && (map_entry->details.page_index == page_index)) {\r
-            if (location != NULL) {\r
-                uint32_t nv_page = g_kv_nvregion_area.nv_data_addr;\r
-                nv_page += KV_PAGE_SIZE * i;\r
-                *location = (kv_page_location)(uintptr_t)nv_page;\r
-            }\r
-            if (header != NULL) {\r
-                (void)memcpy_s(header, sizeof(kv_page_header_t), map_entry, sizeof(kv_page_header_t));\r
-            }\r
-            return ERRCODE_SUCC;\r
-        }\r
-    }\r
-    return ERRCODE_NV_PAGE_NOT_FOUND;\r
-}\r
-\r
-errcode_t kv_nvregion_find_unused_page(kv_page_location *location)\r
-{\r
-    if ((g_kv_nvregion_map.entries == NULL) || (g_kv_nvregion_map.num_entries == 0)) {\r
-        return ERRCODE_NV_NOT_INITIALISED;\r
-    }\r
-\r
-    for (uint32_t i = 0; i < g_kv_nvregion_map.num_entries; i++) {\r
-        kv_page_header_t *map_entry = &g_kv_nvregion_map.entries[i];\r
-\r
-        if ((map_entry->details.store_id == 0) && (map_entry->details.page_index == 0) &&\r
-            (map_entry->inverted_details_word == 0) &&\r
-            (map_entry->sequence_number == 0) && (map_entry->inverted_sequence_number == 0)) {\r
-            if (location != NULL) {\r
-                uint32_t nv_page = g_kv_nvregion_area.nv_data_addr;\r
-                nv_page += KV_PAGE_SIZE * i;\r
-                *location = (kv_page_location)(uintptr_t)nv_page;\r
-            }\r
-            return ERRCODE_SUCC;\r
-        }\r
-    }\r
-    return ERRCODE_NV_PAGE_NOT_FOUND;\r
-}\r
-\r
-errcode_t kv_nvregion_erase_page(kv_page_location page_location)\r
-{\r
-    uint32_t nv_page_addr = (uint32_t)(uintptr_t)page_location;\r
-    errcode_t ret;\r
-\r
-    if ((nv_page_addr < g_kv_nvregion_area.nv_data_addr) ||\r
-        (nv_page_addr >= (g_kv_nvregion_area.nv_data_addr + g_kv_nvregion_area.nv_data_size))) {\r
-        return ERRCODE_INVALID_PARAM;\r
-    }\r
-\r
-    ret = kv_key_erase_flash(nv_page_addr, KV_PAGE_SIZE);\r
-    return ret;\r
-}\r
-\r
-errcode_t kv_nvregion_write_page(kv_page_location page_location, uint16_t store_id, uint8_t page_index)\r
-{\r
-    uint32_t written;\r
-    kv_page_header_t page_header;\r
-    unused(written);\r
-\r
-    /* Build header for KV page */\r
-    page_header.details.store_id = store_id;\r
-    page_header.details.page_index = page_index;\r
-    page_header.details.ver = (g_nv_header_magic == KV_KEY_MAGIC) ? 1 : 0;\r
-    page_header.inverted_details_word = ~*(uint32_t *)(uintptr_t)&page_header.details;\r
-    page_header.sequence_number = 0;\r
-    page_header.inverted_sequence_number = ~page_header.sequence_number;\r
-\r
-    return kv_key_write_flash((uint32_t)(uintptr_t)page_location, sizeof(kv_page_header_t),\r
-                              (uint8_t *)&page_header);\r
-}\r
-\r
-uint32_t kv_nvregion_get_page_number(kv_page_location page_location)\r
-{\r
-    uint32_t page_number = ((uint32_t)(uintptr_t)page_location - g_kv_nvregion_area.nv_data_addr) / KV_PAGE_SIZE;\r
-    if (page_number >= g_kv_nvregion_map.num_entries) {\r
-        return (uint32_t)-1;\r
-    }\r
-    return page_number;\r
+/*
+ * Copyright (c) @CompanyNameMagicTag 2019-2022. All rights reserved.
+ * Description: KV Storage Library non-volatile region access module implementation
+ */
+
+#include "nv_nvregion.h"
+#include "nv_page.h"
+#include "nv_store.h"
+#include "nv_porting.h"
+#include "nv_config.h"
+#include "common_def.h"
+#ifndef CONFIG_NV_SUPPORT_SINGLE_CORE_SYSTEM
+#include "flash_task_mutex.h"
+#include "flash_task_adapt.h"
+#endif
+
+static kv_nvregion_map_t g_kv_nvregion_map = {NULL, NULL, 0};
+static kv_nvregion_area_t g_kv_nvregion_area = {KV_STORE_START_ADDR, KV_STORE_DATA_SIZE,
+    KV_BACKUP_START_ADDR, KV_BACKUP_DATA_SIZE};
+uint32_t g_kv_nvregion_use_times[KV_STORE_DATA_SIZE / KV_PAGE_SIZE] = {0};
+
+kv_nvregion_map_t* kv_nvregion_get_map(void)
+{
+    return &g_kv_nvregion_map;
+}
+
+uint32_t kv_nvregion_get_use_times(kv_page_location page_location)
+{
+    uint32_t page_number = kv_nvregion_get_page_number(page_location);
+    if (page_number >= g_kv_nvregion_map.num_entries) {
+        return (uint32_t)-1;
+    }
+
+    return g_kv_nvregion_map.entries[page_number].sequence_number;
+}
+
+static void kv_nvregion_clear_map_entry(kv_page_header_t *map_entry)
+{
+    (void)memset_s(map_entry, sizeof(kv_page_header_t), 0, sizeof(kv_page_header_t));
+}
+
+static errcode_t kv_nvregion_is_valid_map_entry(const kv_page_header_t *map_entry)
+{
+    if ((map_entry->details.store_id != 0) && (map_entry->details.store_id != 0xFFFF) &&
+        (~map_entry->inverted_details_word == *(uint32_t *)(uintptr_t)&map_entry->details) &&
+        (~map_entry->inverted_sequence_number == map_entry->sequence_number)) {
+            return ERRCODE_SUCC;
+    }
+    return ERRCODE_FAIL;
+}
+
+static void kv_nvregion_filter_duplicate_map_entries(kv_page_header_t *new_entry)
+{
+    kv_page_header_t *existing_entry = g_kv_nvregion_map.entries;
+    while (existing_entry < new_entry) {
+        if ((existing_entry->details.store_id == new_entry->details.store_id) &&
+            (existing_entry->details.page_index == new_entry->details.page_index)) {
+            if (existing_entry->sequence_number <= new_entry->sequence_number) {
+                /* An existing map entry is older than the new one, use the new one */
+                /* Two entries have the same sequence number.  This is unexpected. */
+                /* For the moment use the new entry, but it could be better to try and determine based on content */
+                /* e.g. amount of free space, number of erased keys, corrupted keys */
+                kv_nvregion_clear_map_entry(existing_entry);
+            } else {
+                /* An existing map entry is more recent than the new one */
+                kv_nvregion_clear_map_entry(new_entry);
+                break;
+            }
+        }
+        existing_entry++;
+    }
+}
+
+STATIC void kv_nvregion_free_resource(void)
+{
+    if (g_kv_nvregion_map.entries != NULL) {
+        kv_free(g_kv_nvregion_map.entries);
+        g_kv_nvregion_map.entries = NULL;
+    }
+    if (g_kv_nvregion_map.page_status_map != NULL) {
+        kv_free(g_kv_nvregion_map.page_status_map);
+        g_kv_nvregion_map.page_status_map = NULL;
+    }
+}
+
+STATIC errcode_t kv_nvregion_init_map(void)
+{
+    /* Create blank NV region map */
+    uint32_t num_entries = g_kv_nvregion_area.nv_data_size / KV_PAGE_SIZE;
+    if (num_entries == 0) {
+        return ERRCODE_NV_INVALID_PARAMS;
+    }
+
+    /* Obtain details of NV memory region */
+    if (((g_kv_nvregion_area.nv_data_addr & (KV_PAGE_SIZE - 1)) != 0) ||
+        ((g_kv_nvregion_area.nv_data_size & (KV_PAGE_SIZE - 1)) != 0) ||
+        ((g_kv_nvregion_area.nv_data_size & ~(KV_PAGE_SIZE - 1)) == 0)) {
+        /* NV Data address or size not aligned to a page boundry */
+        return ERRCODE_FAIL;
+    }
+
+    /* Free up any existing NV region map */
+    if (num_entries != g_kv_nvregion_map.num_entries) {
+        kv_nvregion_free_resource();
+    }
+
+    if (g_kv_nvregion_map.entries == NULL) {
+        g_kv_nvregion_map.entries = (kv_page_header_t *)kv_malloc(num_entries * sizeof(kv_page_header_t));
+    }
+
+    if (g_kv_nvregion_map.page_status_map == NULL) {
+        g_kv_nvregion_map.page_status_map =
+            (nv_page_status_map_t *)kv_malloc(num_entries * sizeof(nv_page_status_map_t));
+    }
+
+    if ((g_kv_nvregion_map.entries == NULL) || (g_kv_nvregion_map.page_status_map == NULL)) {
+        kv_nvregion_free_resource();
+        return ERRCODE_MALLOC;
+    }
+
+    (void)memset_s(g_kv_nvregion_map.entries, num_entries * sizeof(kv_page_header_t), 0,
+        num_entries * sizeof(kv_page_header_t));
+    (void)memset_s(g_kv_nvregion_map.page_status_map, num_entries * sizeof(nv_page_status_map_t), 0,
+        num_entries * sizeof(nv_page_status_map_t));
+    g_kv_nvregion_map.num_entries = num_entries;
+    return ERRCODE_SUCC;
+}
+
+static errcode_t kv_nvregion_build_map(void)
+{
+    errcode_t ret;
+    unused(ret);
+    uint32_t nv_page = g_kv_nvregion_area.nv_data_addr;
+
+    for (uint32_t i = 0; i < g_kv_nvregion_map.num_entries; i++) {
+        kv_page_header_t *new_entry = &g_kv_nvregion_map.entries[i];
+        ret = kv_key_helper_copy_flash((uint32_t)(uintptr_t)new_entry, (uint32_t)nv_page, sizeof(kv_page_header_t));
+
+        if (kv_nvregion_is_valid_map_entry(new_entry) == ERRCODE_SUCC
+            && new_entry->details.store_id != KV_STORE_ID_BACKUP) {
+            if (new_entry->details.ver == 0) {
+                g_nv_header_magic = KV_KEY_NO_MAGIC;
+            }
+            kv_nvregion_filter_duplicate_map_entries(new_entry);
+            kv_page_handle_t page;
+            page.page_location = (kv_page_location)(uintptr_t)nv_page;
+            kv_page_read_status_to_map(&page, &(g_kv_nvregion_map.page_status_map[i]));
+        } else {
+            kv_nvregion_clear_map_entry(new_entry);
+        }
+
+        nv_page += KV_PAGE_SIZE;
+    }
+    nv_log_debug("[NV] g_nv_header_magic = 0x%x.\r\n", g_nv_header_magic);
+    return ERRCODE_SUCC;
+}
+
+void kv_nvregion_init(uint32_t nv_data_addr, uint32_t nv_data_size, uint32_t nv_backup_addr, uint32_t nv_backup_size)
+{
+    g_kv_nvregion_area.nv_data_addr = nv_data_addr;
+    g_kv_nvregion_area.nv_data_size = nv_data_size;
+    g_kv_nvregion_area.nv_backup_addr =  nv_backup_addr;
+    g_kv_nvregion_area.nv_backup_size = nv_backup_size;
+}
+
+kv_nvregion_area_t* nv_get_region_area(void)
+{
+    return  &g_kv_nvregion_area;
+}
+
+errcode_t kv_nvregion_scan(void)
+{
+    errcode_t res;
+    res = kv_nvregion_init_map();
+    if (res != ERRCODE_SUCC) {
+        return res;
+    }
+    return kv_nvregion_build_map();
+}
+
+errcode_t kv_nvregion_create_page(uint16_t store_id, uint8_t page_index)
+{
+    errcode_t res;
+    kv_page_location page_location;
+
+    if ((g_kv_nvregion_map.entries == NULL) || (g_kv_nvregion_map.num_entries == 0)) {
+        return ERRCODE_NV_NOT_INITIALISED;
+    }
+    if (store_id == 0) {
+        return ERRCODE_INVALID_PARAM;
+    }
+
+    res = kv_nvregion_find_unused_page(&page_location);
+    if (res != ERRCODE_SUCC) {
+        return res;
+    }
+
+    res = kv_nvregion_erase_page(page_location);
+    if (res != ERRCODE_SUCC) {
+        return res;
+    }
+
+    res = kv_nvregion_write_page(page_location, store_id, page_index);
+    if (res != ERRCODE_SUCC) {
+        return res;
+    }
+
+    return kv_nvregion_scan();
+}
+
+errcode_t kv_nvregion_find_page(uint16_t store_id, uint8_t page_index,
+                                kv_page_location *location, kv_page_header_t *header)
+{
+    if ((g_kv_nvregion_map.entries == NULL) || (g_kv_nvregion_map.num_entries == 0)) {
+        return ERRCODE_NV_NOT_INITIALISED;
+    }
+    if (store_id == 0) {
+        return ERRCODE_INVALID_PARAM;
+    }
+    for (uint32_t i = 0; i < g_kv_nvregion_map.num_entries; i++) {
+        kv_page_header_t *map_entry = &g_kv_nvregion_map.entries[i];
+        if ((map_entry->details.store_id == store_id) && (map_entry->details.page_index == page_index)) {
+            if (location != NULL) {
+                uint32_t nv_page = g_kv_nvregion_area.nv_data_addr;
+                nv_page += KV_PAGE_SIZE * i;
+                *location = (kv_page_location)(uintptr_t)nv_page;
+            }
+            if (header != NULL) {
+                (void)memcpy_s(header, sizeof(kv_page_header_t), map_entry, sizeof(kv_page_header_t));
+            }
+            return ERRCODE_SUCC;
+        }
+    }
+    return ERRCODE_NV_PAGE_NOT_FOUND;
+}
+
+errcode_t kv_nvregion_find_unused_page(kv_page_location *location)
+{
+    if ((g_kv_nvregion_map.entries == NULL) || (g_kv_nvregion_map.num_entries == 0)) {
+        return ERRCODE_NV_NOT_INITIALISED;
+    }
+
+    for (uint32_t i = 0; i < g_kv_nvregion_map.num_entries; i++) {
+        kv_page_header_t *map_entry = &g_kv_nvregion_map.entries[i];
+
+        if ((map_entry->details.store_id == 0) && (map_entry->details.page_index == 0) &&
+            (map_entry->inverted_details_word == 0) &&
+            (map_entry->sequence_number == 0) && (map_entry->inverted_sequence_number == 0)) {
+            if (location != NULL) {
+                uint32_t nv_page = g_kv_nvregion_area.nv_data_addr;
+                nv_page += KV_PAGE_SIZE * i;
+                *location = (kv_page_location)(uintptr_t)nv_page;
+            }
+            return ERRCODE_SUCC;
+        }
+    }
+    return ERRCODE_NV_PAGE_NOT_FOUND;
+}
+
+errcode_t kv_nvregion_erase_page(kv_page_location page_location)
+{
+    uint32_t nv_page_addr = (uint32_t)(uintptr_t)page_location;
+    errcode_t ret;
+
+    if ((nv_page_addr < g_kv_nvregion_area.nv_data_addr) ||
+        (nv_page_addr >= (g_kv_nvregion_area.nv_data_addr + g_kv_nvregion_area.nv_data_size))) {
+        return ERRCODE_INVALID_PARAM;
+    }
+
+    ret = kv_key_erase_flash(nv_page_addr, KV_PAGE_SIZE);
+    return ret;
+}
+
+errcode_t kv_nvregion_write_page(kv_page_location page_location, uint16_t store_id, uint8_t page_index)
+{
+    uint32_t written;
+    kv_page_header_t page_header;
+    unused(written);
+
+    /* Build header for KV page */
+    page_header.details.store_id = store_id;
+    page_header.details.page_index = page_index;
+    page_header.details.ver = (g_nv_header_magic == KV_KEY_MAGIC) ? 1 : 0;
+    page_header.inverted_details_word = ~*(uint32_t *)(uintptr_t)&page_header.details;
+    page_header.sequence_number = 0;
+    page_header.inverted_sequence_number = ~page_header.sequence_number;
+
+    return kv_key_write_flash((uint32_t)(uintptr_t)page_location, sizeof(kv_page_header_t),
+                              (uint8_t *)&page_header);
+}
+
+uint32_t kv_nvregion_get_page_number(kv_page_location page_location)
+{
+    uint32_t page_number = ((uint32_t)(uintptr_t)page_location - g_kv_nvregion_area.nv_data_addr) / KV_PAGE_SIZE;
+    if (page_number >= g_kv_nvregion_map.num_entries) {
+        return (uint32_t)-1;
+    }
+    return page_number;
 }
\ No newline at end of file
index 212c742..65768a0 100755 (executable)
@@ -1,65 +1,65 @@
-/*\r
- * Copyright (c) @CompanyNameMagicTag 2019-2022. All rights reserved.\r
- * Description: KV Storage Library non-volatile region access interface\r
- */\r
-\r
-#ifndef NV_NVREGION_H\r
-#define NV_NVREGION_H\r
-\r
-#include "nv_page.h"\r
-#include "errcode.h"\r
-\r
-#ifdef __cplusplus\r
-#if __cplusplus\r
-extern "C" {\r
-#endif /* __cplusplus */\r
-#endif /* __cplusplus */\r
-\r
-typedef struct {\r
-    uint16_t key_id;                /* Key ID */\r
-    uint16_t key_len    : 13;       /* Key length */\r
-    uint16_t permanent  : 1;        /* 是否是永久Key */\r
-    uint16_t encrypted  : 1;        /* 是否是加密Key */\r
-    uint16_t upgrade    : 1;        /* 是否可以升级 */\r
-    uint16_t key_offset   : 13;     /* Key的位置(相对页首地址的偏移) */\r
-    uint16_t valid        : 1;      /* Key是否有效 */\r
-    uint16_t corrupted    : 1;      /* Key是否被破坏 */\r
-    uint16_t reserved     : 1;      /* Key预留字段 */\r
-} nv_key_index_map_t;\r
-\r
-typedef struct {\r
-    kv_page_header_t        *entries;\r
-    nv_page_status_map_t    *page_status_map;\r
-    uint32_t                num_entries;\r
-} kv_nvregion_map_t;\r
-\r
-typedef struct {\r
-    uint32_t nv_data_addr;\r
-    uint32_t nv_data_size;\r
-    uint32_t nv_backup_addr;\r
-    uint32_t nv_backup_size;\r
-} kv_nvregion_area_t;\r
-\r
-void kv_nvregion_init(uint32_t nv_data_addr, uint32_t nv_data_size, uint32_t nv_backup_addr, uint32_t nv_backup_size);\r
-\r
-errcode_t kv_nvregion_scan(void);\r
-errcode_t kv_nvregion_find_page(uint16_t store_id, uint8_t page_index,\r
-                                kv_page_location *location, kv_page_header_t *header);\r
-errcode_t kv_nvregion_find_unused_page(kv_page_location *location);\r
-errcode_t kv_nvregion_erase_page(kv_page_location page_location);\r
-errcode_t kv_nvregion_create_page(uint16_t store_id, uint8_t page_index);\r
-errcode_t kv_nvregion_write_page(kv_page_location page_location, uint16_t store_id, uint8_t page_index);\r
-\r
-kv_nvregion_map_t* kv_nvregion_get_map(void);\r
-kv_nvregion_area_t* nv_get_region_area(void);\r
-\r
-uint32_t kv_nvregion_get_page_number(kv_page_location page_location);\r
-uint32_t kv_nvregion_get_use_times(kv_page_location page_location);\r
-\r
-#ifdef __cplusplus\r
-#if __cplusplus\r
-}\r
-#endif /* __cplusplus */\r
-#endif /* __cplusplus */\r
-\r
-#endif /* NV_NVREGION_H */\r
+/*
+ * Copyright (c) @CompanyNameMagicTag 2019-2022. All rights reserved.
+ * Description: KV Storage Library non-volatile region access interface
+ */
+
+#ifndef NV_NVREGION_H
+#define NV_NVREGION_H
+
+#include "nv_page.h"
+#include "errcode.h"
+
+#ifdef __cplusplus
+#if __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+typedef struct {
+    uint16_t key_id;                /* Key ID */
+    uint16_t key_len    : 13;       /* Key length */
+    uint16_t permanent  : 1;        /* 是否是永久Key */
+    uint16_t encrypted  : 1;        /* 是否是加密Key */
+    uint16_t upgrade    : 1;        /* 是否可以升级 */
+    uint16_t key_offset   : 13;     /* Key的位置(相对页首地址的偏移) */
+    uint16_t valid        : 1;      /* Key是否有效 */
+    uint16_t corrupted    : 1;      /* Key是否被破坏 */
+    uint16_t reserved     : 1;      /* Key预留字段 */
+} nv_key_index_map_t;
+
+typedef struct {
+    kv_page_header_t        *entries;
+    nv_page_status_map_t    *page_status_map;
+    uint32_t                num_entries;
+} kv_nvregion_map_t;
+
+typedef struct {
+    uint32_t nv_data_addr;
+    uint32_t nv_data_size;
+    uint32_t nv_backup_addr;
+    uint32_t nv_backup_size;
+} kv_nvregion_area_t;
+
+void kv_nvregion_init(uint32_t nv_data_addr, uint32_t nv_data_size, uint32_t nv_backup_addr, uint32_t nv_backup_size);
+
+errcode_t kv_nvregion_scan(void);
+errcode_t kv_nvregion_find_page(uint16_t store_id, uint8_t page_index,
+                                kv_page_location *location, kv_page_header_t *header);
+errcode_t kv_nvregion_find_unused_page(kv_page_location *location);
+errcode_t kv_nvregion_erase_page(kv_page_location page_location);
+errcode_t kv_nvregion_create_page(uint16_t store_id, uint8_t page_index);
+errcode_t kv_nvregion_write_page(kv_page_location page_location, uint16_t store_id, uint8_t page_index);
+
+kv_nvregion_map_t* kv_nvregion_get_map(void);
+kv_nvregion_area_t* nv_get_region_area(void);
+
+uint32_t kv_nvregion_get_page_number(kv_page_location page_location);
+uint32_t kv_nvregion_get_use_times(kv_page_location page_location);
+
+#ifdef __cplusplus
+#if __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+#endif /* NV_NVREGION_H */
index 917cab0..caad15f 100755 (executable)
-/*\r
- * Copyright (c) @CompanyNameMagicTag 2019-2022. All rights reserved.\r
- * Description: KV Storage Library page access module implementation\r
- */\r
-\r
-#include "nv_page.h"\r
-#include "nv_key.h"\r
-#include "nv_nvregion.h"\r
-#include "nv_porting.h"\r
-#include "common_def.h"\r
-\r
-#define assert_p(x)        ((void)0)\r
-\r
-errcode_t kv_page_get_index(kv_page_handle_t *page, uint32_t *page_index)\r
-{\r
-    if ((page->page_location != (kv_page_location)NULL) &&\r
-        (~page->page_header.inverted_details_word == *(uint32_t *)(uintptr_t)&page->page_header.details) &&\r
-        (~page->page_header.inverted_sequence_number == page->page_header.sequence_number)) {\r
-        *page_index = page->page_header.details.page_index;\r
-        return ERRCODE_SUCC;\r
-    }\r
-    return ERRCODE_NV_INVALID_PAGE;\r
-}\r
-\r
-errcode_t kv_page_find_first_key(const kv_page_handle_t *page, kv_key_filter_t *search_filter,\r
-                                 kv_key_handle_t *key)\r
-{\r
-    kv_key_location key_location = (kv_key_location)((uintptr_t)page->page_location + sizeof(kv_page_header_t));\r
-    errcode_t res = kv_key_get_handle_from_location(key_location, key);\r
-#if (CONFIG_NV_SUPPORT_SKIP_CORRUPT_KEY == NV_YES)\r
-    if (res == ERRCODE_NV_INVALID_KEY_HEADER) {\r
-        nv_log_debug("[NV] kv_page_find_first_key: key magic err (location = 0x%x)!\r\n", key_location);\r
-        res = kv_key_get_next_magic_position(key_location, key);\r
-    }\r
-#endif\r
-    while (res == ERRCODE_SUCC) {\r
-        res = kv_key_does_filter_match(key, search_filter);\r
-        if (res == ERRCODE_SUCC) {\r
-            return ERRCODE_SUCC;\r
-        }\r
-        res = kv_key_get_next_handle(key, KV_KEY_NOT_VALIDATE);\r
-    }\r
-    return res;\r
-}\r
-\r
-errcode_t kv_page_find_next_key(const kv_page_handle_t *page, kv_key_filter_t *search_filter,\r
-                                kv_key_handle_t *key)\r
-{\r
-    errcode_t res = kv_key_get_next_handle(key, KV_KEY_NOT_VALIDATE);\r
-    unused(page);\r
-    while (res == ERRCODE_SUCC) {\r
-        res = kv_key_does_filter_match(key, search_filter);\r
-        if (res == ERRCODE_SUCC) {\r
-            return ERRCODE_SUCC;\r
-        }\r
-        res = kv_key_get_next_handle(key, KV_KEY_NOT_VALIDATE);\r
-    }\r
-    return res;\r
-}\r
-\r
-STATIC void kv_page_copy_status_map(kv_page_status_t *page_status, nv_page_status_map_t *page_status_map)\r
-{\r
-    page_status->total_space = KV_PAGE_SIZE - (uint32_t)sizeof(kv_page_header_t);\r
-    page_status->used_space = page_status_map->used_space;\r
-    page_status->reclaimable_space = page_status_map->reclaimable_space;\r
-    page_status->corrupted_space = page_status_map->corrupted_space;\r
-    page_status->max_key_space = page_status->total_space - page_status->used_space + page_status->reclaimable_space;\r
-    page_status->first_writable_location = page_status_map->page_location + page_status_map->first_writable_offset;\r
-}\r
-\r
-void kv_page_read_status_to_map(kv_page_handle_t *page, nv_page_status_map_t *status_map)\r
-{\r
-    kv_key_handle_t key;\r
-    uint32_t page_data_loc = (uint32_t)(uintptr_t)page->page_location + (uint32_t)sizeof(kv_page_header_t);\r
-\r
-    (void)memset_s(status_map, sizeof(nv_page_status_map_t), 0, sizeof(nv_page_status_map_t));\r
-\r
-    status_map->page_location = (uint32_t)page->page_location;\r
-\r
-    errcode_t key_found = kv_page_find_first_key(page, NULL, &key);\r
-    uint32_t first_key_loc = (uint32_t)(uintptr_t)key.key_location;\r
-\r
-    /* 如果第一个KEY不在page起始位置,说明page起始位置处的KEY被破坏 */\r
-    if (first_key_loc > page_data_loc) {\r
-        status_map->corrupted_space += (uint16_t)(first_key_loc - page_data_loc);\r
-        status_map->reclaimable_space += (uint16_t)(first_key_loc - page_data_loc);\r
-        status_map->used_space += (uint16_t)(first_key_loc - page_data_loc);\r
-    }\r
-\r
-    while (key_found == ERRCODE_SUCC) {\r
-        uint32_t key_size;\r
-        uint32_t last_key_location;\r
-\r
-        key_size = kv_key_flash_size(&key);\r
-\r
-        errcode_t ret = kv_key_validate_integrity(&key, true);\r
-        if (ret != ERRCODE_SUCC) {\r
-            /* Key校验失败,则key length不可信,通过获取下一个Key的位置,与当前key的位置差重新计算key_size */\r
-            nv_log_err("[NV] key validate integrity. key id = 0x%x location = 0x%x. ret = 0x%x\r\n",\r
-                key.header.key_id, key.key_location, ret);\r
-            last_key_location = (uint32_t)(uintptr_t)key.key_location;\r
-            key_found = kv_key_get_next_handle(&key, KV_KEY_VALIDATE_WRONG);\r
-            if ((key_found == ERRCODE_SUCC) || (key_found == ERRCODE_NV_KEY_NOT_FOUND)) {\r
-                key_size = (uint32_t)(uintptr_t)key.key_location - last_key_location;\r
-            } else {\r
-                break;\r
-            }\r
-\r
-            status_map->corrupted_space += (uint16_t)key_size;\r
-            status_map->reclaimable_space += (uint16_t)key_size;\r
-        } else {\r
-            if (kv_key_is_erased(&key)) {\r
-                status_map->reclaimable_space += (uint16_t)key_size;\r
-            }\r
-            key_found = kv_key_get_next_handle(&key, KV_KEY_VALIDATE_CORRECT);\r
-        }\r
-        status_map->used_space += (uint16_t)key_size;\r
-        assert_p(status_map->used_space <= (KV_PAGE_SIZE - sizeof(kv_page_header_t)));\r
-    }\r
-\r
-    status_map->first_writable_offset = (uint16_t)sizeof(kv_page_header_t) + status_map->used_space;\r
-}\r
-\r
-void kv_page_get_status(kv_page_handle_t *page, kv_page_status_t *page_status)\r
-{\r
-    nv_page_status_map_t page_status_map;\r
-    kv_page_read_status_to_map(page, &page_status_map);\r
-    kv_page_copy_status_map(page_status, &page_status_map);\r
-}\r
-\r
-void kv_page_get_status_from_map(kv_page_handle_t *page, kv_page_status_t *page_status)\r
-{\r
-    kv_nvregion_map_t *nv_map = kv_nvregion_get_map();\r
-\r
-    uint32_t page_number = kv_nvregion_get_page_number(page->page_location);\r
-    if (page_number >= nv_map->num_entries) {\r
-        return;\r
-    }\r
-\r
-    kv_page_copy_status_map(page_status, &(nv_map->page_status_map[page_number]));\r
-    return;\r
-}\r
+/*
+ * Copyright (c) @CompanyNameMagicTag 2019-2022. All rights reserved.
+ * Description: KV Storage Library page access module implementation
+ */
+
+#include "nv_page.h"
+#include "nv_key.h"
+#include "nv_nvregion.h"
+#include "nv_porting.h"
+#include "common_def.h"
+
+#define assert_p(x)        ((void)0)
+
+errcode_t kv_page_get_index(kv_page_handle_t *page, uint32_t *page_index)
+{
+    if ((page->page_location != (kv_page_location)NULL) &&
+        (~page->page_header.inverted_details_word == *(uint32_t *)(uintptr_t)&page->page_header.details) &&
+        (~page->page_header.inverted_sequence_number == page->page_header.sequence_number)) {
+        *page_index = page->page_header.details.page_index;
+        return ERRCODE_SUCC;
+    }
+    return ERRCODE_NV_INVALID_PAGE;
+}
+
+errcode_t kv_page_find_first_key(const kv_page_handle_t *page, kv_key_filter_t *search_filter,
+                                 kv_key_handle_t *key)
+{
+    kv_key_location key_location = (kv_key_location)((uintptr_t)page->page_location + sizeof(kv_page_header_t));
+    errcode_t res = kv_key_get_handle_from_location(key_location, key);
+#if (CONFIG_NV_SUPPORT_SKIP_CORRUPT_KEY == NV_YES)
+    if (res == ERRCODE_NV_INVALID_KEY_HEADER) {
+        nv_log_debug("[NV] kv_page_find_first_key: key magic err (location = 0x%x)!\r\n", key_location);
+        res = kv_key_get_next_magic_position(key_location, key);
+    }
+#endif
+    while (res == ERRCODE_SUCC) {
+        res = kv_key_does_filter_match(key, search_filter);
+        if (res == ERRCODE_SUCC) {
+            return ERRCODE_SUCC;
+        }
+        res = kv_key_get_next_handle(key, KV_KEY_NOT_VALIDATE);
+    }
+    return res;
+}
+
+errcode_t kv_page_find_next_key(const kv_page_handle_t *page, kv_key_filter_t *search_filter,
+                                kv_key_handle_t *key)
+{
+    errcode_t res = kv_key_get_next_handle(key, KV_KEY_NOT_VALIDATE);
+    unused(page);
+    while (res == ERRCODE_SUCC) {
+        res = kv_key_does_filter_match(key, search_filter);
+        if (res == ERRCODE_SUCC) {
+            return ERRCODE_SUCC;
+        }
+        res = kv_key_get_next_handle(key, KV_KEY_NOT_VALIDATE);
+    }
+    return res;
+}
+
+STATIC void kv_page_copy_status_map(kv_page_status_t *page_status, nv_page_status_map_t *page_status_map)
+{
+    page_status->total_space = KV_PAGE_SIZE - (uint32_t)sizeof(kv_page_header_t);
+    page_status->used_space = page_status_map->used_space;
+    page_status->reclaimable_space = page_status_map->reclaimable_space;
+    page_status->corrupted_space = page_status_map->corrupted_space;
+    page_status->max_key_space = page_status->total_space - page_status->used_space + page_status->reclaimable_space;
+    page_status->first_writable_location = page_status_map->page_location + page_status_map->first_writable_offset;
+}
+
+void kv_page_read_status_to_map(kv_page_handle_t *page, nv_page_status_map_t *status_map)
+{
+    kv_key_handle_t key;
+    uint32_t page_data_loc = (uint32_t)(uintptr_t)page->page_location + (uint32_t)sizeof(kv_page_header_t);
+
+    (void)memset_s(status_map, sizeof(nv_page_status_map_t), 0, sizeof(nv_page_status_map_t));
+
+    status_map->page_location = (uint32_t)page->page_location;
+
+    errcode_t key_found = kv_page_find_first_key(page, NULL, &key);
+    uint32_t first_key_loc = (uint32_t)(uintptr_t)key.key_location;
+
+    /* 如果第一个KEY不在page起始位置,说明page起始位置处的KEY被破坏 */
+    if (first_key_loc > page_data_loc) {
+        status_map->corrupted_space += (uint16_t)(first_key_loc - page_data_loc);
+        status_map->reclaimable_space += (uint16_t)(first_key_loc - page_data_loc);
+        status_map->used_space += (uint16_t)(first_key_loc - page_data_loc);
+    }
+
+    while (key_found == ERRCODE_SUCC) {
+        uint32_t key_size;
+        uint32_t last_key_location;
+
+        key_size = kv_key_flash_size(&key);
+
+        errcode_t ret = kv_key_validate_integrity(&key, true);
+        if (ret != ERRCODE_SUCC) {
+            /* Key校验失败,则key length不可信,通过获取下一个Key的位置,与当前key的位置差重新计算key_size */
+            nv_log_err("[NV] key validate integrity. key id = 0x%x location = 0x%x. ret = 0x%x\r\n",
+                key.header.key_id, key.key_location, ret);
+            last_key_location = (uint32_t)(uintptr_t)key.key_location;
+            key_found = kv_key_get_next_handle(&key, KV_KEY_VALIDATE_WRONG);
+            if ((key_found == ERRCODE_SUCC) || (key_found == ERRCODE_NV_KEY_NOT_FOUND)) {
+                key_size = (uint32_t)(uintptr_t)key.key_location - last_key_location;
+            } else {
+                break;
+            }
+
+            status_map->corrupted_space += (uint16_t)key_size;
+            status_map->reclaimable_space += (uint16_t)key_size;
+        } else {
+            if (kv_key_is_erased(&key)) {
+                status_map->reclaimable_space += (uint16_t)key_size;
+            }
+            key_found = kv_key_get_next_handle(&key, KV_KEY_VALIDATE_CORRECT);
+        }
+        status_map->used_space += (uint16_t)key_size;
+        assert_p(status_map->used_space <= (KV_PAGE_SIZE - sizeof(kv_page_header_t)));
+    }
+
+    status_map->first_writable_offset = (uint16_t)sizeof(kv_page_header_t) + status_map->used_space;
+}
+
+void kv_page_get_status(kv_page_handle_t *page, kv_page_status_t *page_status)
+{
+    nv_page_status_map_t page_status_map;
+    kv_page_read_status_to_map(page, &page_status_map);
+    kv_page_copy_status_map(page_status, &page_status_map);
+}
+
+void kv_page_get_status_from_map(kv_page_handle_t *page, kv_page_status_t *page_status)
+{
+    kv_nvregion_map_t *nv_map = kv_nvregion_get_map();
+
+    uint32_t page_number = kv_nvregion_get_page_number(page->page_location);
+    if (page_number >= nv_map->num_entries) {
+        return;
+    }
+
+    kv_page_copy_status_map(page_status, &(nv_map->page_status_map[page_number]));
+    return;
+}
index f2dfc09..f611223 100755 (executable)
@@ -1,73 +1,73 @@
-/*\r
- * Copyright (c) @CompanyNameMagicTag 2019-2022. All rights reserved.\r
- * Description: KV Storage Library page access interface\r
- */\r
-\r
-#ifndef NV_PAGE_H\r
-#define NV_PAGE_H\r
-\r
-#include "nv_key.h"\r
-#include "errcode.h"\r
-\r
-#ifdef __cplusplus\r
-#if __cplusplus\r
-extern "C" {\r
-#endif /* __cplusplus */\r
-#endif /* __cplusplus */\r
-\r
-/** Represents the location in flash of a KV page. Provided in such a way that it can't be dereferenced,\r
- * as flash is not directly addressable */\r
-typedef const void *kv_page_location;\r
-\r
-typedef struct {\r
-    uint16_t store_id;     /* Identifies the page as belonging to a certain store */\r
-    uint8_t  ver;\r
-    uint8_t  page_index;   /* Uniquely identifies a page within a store */\r
-} kv_page_details_t;\r
-\r
-typedef struct {\r
-    kv_page_details_t  details;\r
-    uint32_t           inverted_details_word;\r
-    uint32_t           sequence_number;\r
-    uint32_t           inverted_sequence_number;\r
-} kv_page_header_t;\r
-\r
-/* A KV page handle, which provides both the page header information and the location in flash */\r
-typedef struct {\r
-    kv_page_header_t    page_header;\r
-    kv_page_location    page_location;   /* Location in flash of the KV page */\r
-} kv_page_handle_t;\r
-\r
-typedef struct {\r
-    uint32_t total_space;               /* 本页最大空间(不含页头) */\r
-    uint32_t used_space;                /* 本页已使用空间 */\r
-    uint32_t reclaimable_space;         /* 本页可回收空间(包含已损坏空间) */\r
-    uint32_t corrupted_space;           /* 本页已损坏空间 */\r
-    uint32_t max_key_space;             /* 本页可写的最大空间(未使用+可回收) */\r
-    uint32_t first_writable_location;   /* 本页第一个可写入位置 */\r
-} kv_page_status_t;\r
-\r
-typedef struct {\r
-    uint32_t page_location;             /* 本页首地址(包含页头) */\r
-    uint16_t used_space;                /* 本页已使用空间 */\r
-    uint16_t reclaimable_space;         /* 本页可回收空间(包含已损坏空间) */\r
-    uint16_t corrupted_space;           /* 本页已损坏空间 */\r
-    uint16_t first_writable_offset;     /* 本页第一个可写入位置(相对页首地址的偏移) */\r
-} nv_page_status_map_t;\r
-\r
-errcode_t kv_page_get_index(kv_page_handle_t *page, uint32_t *page_index);\r
-errcode_t kv_page_find_first_key(const kv_page_handle_t *page, kv_key_filter_t *search_filter,\r
-    kv_key_handle_t *key);\r
-errcode_t kv_page_find_next_key(const kv_page_handle_t *page, kv_key_filter_t *search_filter,\r
-    kv_key_handle_t *key);\r
-void kv_page_get_status(kv_page_handle_t *page, kv_page_status_t *page_status);\r
-void kv_page_get_status_from_map(kv_page_handle_t *page, kv_page_status_t *page_status);\r
-void kv_page_read_status_to_map(kv_page_handle_t *page, nv_page_status_map_t *status_map);\r
-\r
-#ifdef __cplusplus\r
-#if __cplusplus\r
-}\r
-#endif /* __cplusplus */\r
-#endif /* __cplusplus */\r
-\r
-#endif /* NV_PAGE_H_ */\r
+/*
+ * Copyright (c) @CompanyNameMagicTag 2019-2022. All rights reserved.
+ * Description: KV Storage Library page access interface
+ */
+
+#ifndef NV_PAGE_H
+#define NV_PAGE_H
+
+#include "nv_key.h"
+#include "errcode.h"
+
+#ifdef __cplusplus
+#if __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+/** Represents the location in flash of a KV page. Provided in such a way that it can't be dereferenced,
+ * as flash is not directly addressable */
+typedef const void *kv_page_location;
+
+typedef struct {
+    uint16_t store_id;     /* Identifies the page as belonging to a certain store */
+    uint8_t  ver;
+    uint8_t  page_index;   /* Uniquely identifies a page within a store */
+} kv_page_details_t;
+
+typedef struct {
+    kv_page_details_t  details;
+    uint32_t           inverted_details_word;
+    uint32_t           sequence_number;
+    uint32_t           inverted_sequence_number;
+} kv_page_header_t;
+
+/* A KV page handle, which provides both the page header information and the location in flash */
+typedef struct {
+    kv_page_header_t    page_header;
+    kv_page_location    page_location;   /* Location in flash of the KV page */
+} kv_page_handle_t;
+
+typedef struct {
+    uint32_t total_space;               /* 本页最大空间(不含页头) */
+    uint32_t used_space;                /* 本页已使用空间 */
+    uint32_t reclaimable_space;         /* 本页可回收空间(包含已损坏空间) */
+    uint32_t corrupted_space;           /* 本页已损坏空间 */
+    uint32_t max_key_space;             /* 本页可写的最大空间(未使用+可回收) */
+    uint32_t first_writable_location;   /* 本页第一个可写入位置 */
+} kv_page_status_t;
+
+typedef struct {
+    uint32_t page_location;             /* 本页首地址(包含页头) */
+    uint16_t used_space;                /* 本页已使用空间 */
+    uint16_t reclaimable_space;         /* 本页可回收空间(包含已损坏空间) */
+    uint16_t corrupted_space;           /* 本页已损坏空间 */
+    uint16_t first_writable_offset;     /* 本页第一个可写入位置(相对页首地址的偏移) */
+} nv_page_status_map_t;
+
+errcode_t kv_page_get_index(kv_page_handle_t *page, uint32_t *page_index);
+errcode_t kv_page_find_first_key(const kv_page_handle_t *page, kv_key_filter_t *search_filter,
+    kv_key_handle_t *key);
+errcode_t kv_page_find_next_key(const kv_page_handle_t *page, kv_key_filter_t *search_filter,
+    kv_key_handle_t *key);
+void kv_page_get_status(kv_page_handle_t *page, kv_page_status_t *page_status);
+void kv_page_get_status_from_map(kv_page_handle_t *page, kv_page_status_t *page_status);
+void kv_page_read_status_to_map(kv_page_handle_t *page, nv_page_status_map_t *status_map);
+
+#ifdef __cplusplus
+#if __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+#endif /* NV_PAGE_H_ */
index 90c1ba6..f6e2b44 100755 (executable)
-/*\r
- * Copyright (c) @CompanyNameMagicTag 2023-2023. All rights reserved.\r
- * Description: NV Storage Library Restore factory settings interface\r
- */\r
-#include "nv.h"\r
-#include "nv_store.h"\r
-#include "nv_page.h"\r
-#include "nv_storage.h"\r
-#include "nv_nvregion.h"\r
-#include "nv_porting.h"\r
-#include "nv_notify.h"\r
-#include "nv_task_adapt.h"\r
-#include "nv_update.h"\r
-#include "common_def.h"\r
-#include "nv_storage_handle.h"\r
-#include "nv_reset.h"\r
-\r
-#if (CONFIG_NV_SUPPORT_BACKUP_RESTORE == NV_YES)\r
-\r
-bool g_reset_region_flag[KEY_ID_REGION_MAX_NUM] = {0};\r
-STATIC retain_key_list_handle_t* g_retain_key_list = NULL;\r
-\r
-#define RESET_MAX_BINARY_VAL 1\r
-#define assert_r(x)        ((void)0)\r
-#define NV_RESTORE_MAX_KEY 4060\r
-\r
-STATIC errcode_t kv_region_is_enable(uint16_t key_id)\r
-{\r
-    uint16_t region_id = key_id / REGION_KEY_NUMS;\r
-    if (region_id < KEY_ID_REGION_MAX_NUM && g_reset_region_flag[region_id]) {\r
-        return ERRCODE_SUCC;\r
-    }\r
-    return ERRCODE_FAIL;\r
-}\r
-\r
-STATIC void retain_key_list_free(void)\r
-{\r
-    retain_key_t *current_key = g_retain_key_list->next;\r
-    retain_key_t *temp_key = NULL;\r
-    while (current_key != NULL) {\r
-        temp_key = current_key;\r
-        current_key = current_key->next;\r
-        if (temp_key->kvalue != NULL) {\r
-            kv_free(temp_key->kvalue);\r
-        }\r
-        kv_free(temp_key);\r
-        g_retain_key_list->list_length--;\r
-    }\r
-    kv_free(g_retain_key_list);\r
-    g_retain_key_list = NULL;\r
-}\r
-\r
-STATIC errcode_t retain_key_list_init(void)\r
-{\r
-    if (g_retain_key_list != NULL) {\r
-        return ERRCODE_SUCC;\r
-    }\r
-    g_retain_key_list = (retain_key_list_handle_t *)(uintptr_t)kv_malloc(sizeof(retain_key_list_handle_t));\r
-    if (g_retain_key_list == NULL) {\r
-        return ERRCODE_MALLOC;\r
-    }\r
-\r
-    g_retain_key_list->list_length = 0;\r
-    g_retain_key_list->tail = NULL;\r
-    g_retain_key_list->next = NULL;\r
-    return ERRCODE_SUCC;\r
-}\r
-\r
-STATIC void retain_key_list_add(retain_key_t* cur_key)\r
-{\r
-    if (g_retain_key_list->list_length == 0) {\r
-        g_retain_key_list->next = cur_key;\r
-        g_retain_key_list->tail = cur_key;\r
-    } else {\r
-        g_retain_key_list->tail->next = cur_key;\r
-        g_retain_key_list->tail = cur_key;\r
-    }\r
-    g_retain_key_list->list_length++;\r
-}\r
-\r
-STATIC errcode_t kv_reset_backup_retain_keys_helper(kv_page_handle_t *page)\r
-{\r
-    errcode_t res;\r
-    kv_key_handle_t key;\r
-    retain_key_t *cur_key = NULL;\r
-    res = retain_key_list_init();\r
-    if (res != ERRCODE_SUCC) {\r
-        return res;\r
-    }\r
-\r
-    errcode_t key_found = kv_page_find_first_key(page, NULL, &key);\r
-    while (key_found == ERRCODE_SUCC) {\r
-        if ((kv_key_is_valid(&key)) && (kv_region_is_enable(key.header.key_id) == ERRCODE_FAIL)) {\r
-            cur_key = (retain_key_t *)kv_malloc(sizeof(retain_key_t));\r
-            if (cur_key == NULL) {\r
-                return ERRCODE_MALLOC;\r
-            }\r
-            (void)memset_s(cur_key, sizeof(retain_key_t), 0, sizeof(retain_key_t));\r
-            cur_key->key = key.header.key_id;\r
-            cur_key->kvalue_length = key.header.length;\r
-            cur_key->kvalue = (uint8_t *)kv_malloc(cur_key->kvalue_length);\r
-            if (cur_key->kvalue == NULL) {\r
-                return ERRCODE_MALLOC;\r
-            }\r
-            cur_key->next = NULL;\r
-            res = kv_key_read_data(&key, cur_key->kvalue);\r
-            if (res != ERRCODE_SUCC) {\r
-                return ERRCODE_FAIL;\r
-            }\r
-            nv_log_debug("[NV] backup_retain_keys_helper key_id: %d\r\n", cur_key->key);\r
-            (void)retain_key_list_add(cur_key);\r
-        }\r
-        key_found = kv_page_find_next_key(page, NULL, &key);\r
-    }\r
-    return ERRCODE_SUCC;\r
-}\r
-\r
-STATIC errcode_t kv_reset_backup_retain_keys(kv_store_t store, uint8_t num_pages)\r
-{\r
-    errcode_t ret;\r
-    kv_page_handle_t kv_page;\r
-    for (uint8_t page_index = 0; page_index < num_pages; page_index++) {\r
-        ret = kv_store_get_page_handle(store, page_index, &kv_page);\r
-        if (ret != ERRCODE_SUCC) {\r
-            return ret;\r
-        }\r
-        ret = kv_reset_backup_retain_keys_helper(&kv_page);\r
-        if (ret != ERRCODE_SUCC) {\r
-            retain_key_list_free();\r
-            return ret;\r
-        }\r
-    }\r
-    return ERRCODE_SUCC;\r
-}\r
-\r
-STATIC errcode_t restore_retain_keys(void)\r
-{\r
-    if (g_retain_key_list == NULL) {\r
-        return ERRCODE_FAIL;\r
-    }\r
-    retain_key_t *cur_key = g_retain_key_list->next;\r
-    while (cur_key != NULL && cur_key->kvalue != NULL) {\r
-        nv_log_debug("[NV] restore_retain_keys_b key_id: 0x%x\r\n", cur_key->key);\r
-        (void)nv_direct_write_with_attr(cur_key->key, cur_key->kvalue, cur_key->kvalue_length, NULL, NULL);\r
-        cur_key = cur_key->next;\r
-    }\r
-    retain_key_list_free();\r
-    return ERRCODE_SUCC;\r
-}\r
-\r
-STATIC errcode_t kv_backup_invalid_key(const kv_key_handle_t *key)\r
-{\r
-    /* 计算valid相对于key起始的位置,即要写入数据在flash中相对于key_location的偏移量 */\r
-    uint32_t offset = ((uint32_t)(uintptr_t)&key->header.valid) - ((uint32_t)(uintptr_t)key);\r
-    uint32_t write_position = (uint32_t)(uintptr_t)key->key_location + offset - FLASH_PHYSICAL_ADDR_START;\r
-    uint32_t write_length = sizeof(key->header.valid);\r
-    uint8_t *write_data = (uint8_t *)kv_malloc(write_length);\r
-    if (write_data == NULL) {\r
-        return ERRCODE_MALLOC;\r
-    }\r
-    (void)memset_s(write_data, write_length, 0, write_length);\r
-    errcode_t ret = kv_flash_write(write_position, write_length, write_data, false);\r
-    kv_free(write_data);\r
-    return ret;\r
-}\r
-\r
-STATIC errcode_t kv_backup_delete_one_page_repeat_key(kv_page_handle_t *page)\r
-{\r
-    errcode_t ret;\r
-    kv_key_handle_t key;\r
-    errcode_t key_found = kv_page_find_first_key(page, NULL, &key);\r
-    while (key_found == ERRCODE_SUCC) {\r
-        if ((kv_key_is_valid(&key)) && (kv_region_is_enable(key.header.key_id) == ERRCODE_SUCC)) {\r
-            ret = kv_backup_invalid_key(&key);\r
-            if (ret != ERRCODE_SUCC) {\r
-                return ret;\r
-            }\r
-        }\r
-        key_found = kv_page_find_next_key(page, NULL, &key);\r
-    }\r
-    return ERRCODE_SUCC;\r
-}\r
-\r
-errcode_t kv_backup_delete_repeat_key(void)\r
-{\r
-    errcode_t ret;\r
-    kv_page_handle_t page;\r
-    kv_nvregion_area_t* nvregion_area =  nv_get_region_area();\r
-    if (nvregion_area == NULL) {\r
-        return ERRCODE_FAIL;\r
-    }\r
-    uint32_t page_start = nvregion_area->nv_backup_addr;\r
-    /* 遍历备份区,将每个要被重复备份的key标志位置为无效 */\r
-    for (uint32_t page_index = 0; page_index < KV_BACKUP_PAGE_NUM; page_index++) {\r
-        page.page_location = (kv_page_location)(uintptr_t)(page_start + page_index * KV_PAGE_SIZE);\r
-        ret = kv_backup_delete_one_page_repeat_key(&page);\r
-        if (ret != ERRCODE_SUCC) {\r
-            return ret;\r
-        }\r
-    }\r
-\r
-    return ERRCODE_SUCC;\r
-}\r
-\r
-STATIC errcode_t kv_backup_dragpage_switch_unused_page(kv_page_handle_t dragpage, kv_page_handle_t unused_page)\r
-{\r
-    /* 将换页页内容转移到unused page */\r
-    errcode_t ret;\r
-    uint32_t page_head_size = (uint32_t)sizeof(kv_page_header_t);\r
-\r
-    /* 将换页页的页头转移到unused page */\r
-    kv_page_header_t head_buffer;\r
-    ret = kv_key_helper_copy_flash((uint32_t)(uintptr_t)&head_buffer,\r
-        (uint32_t)dragpage.page_location, page_head_size);\r
-    if (ret != ERRCODE_SUCC) {\r
-        return ret;\r
-    }\r
-    ret = kv_key_write_flash((uint32_t)unused_page.page_location, page_head_size, (uint8_t *)&head_buffer);\r
-    if (ret != ERRCODE_SUCC) {\r
-        return ret;\r
-    }\r
-\r
-    kv_key_handle_t key;\r
-    uint16_t key_size;\r
-    uint32_t write_position = (uint32_t)((uintptr_t)unused_page.page_location + page_head_size);\r
-    /* 将换页页的有效的key转移到unused page */\r
-    errcode_t key_found = kv_page_find_first_key(&dragpage, NULL, &key);\r
-    while (key_found == ERRCODE_SUCC) {\r
-        if (kv_key_is_valid(&key)) {\r
-            key_size = kv_key_flash_size(&key);\r
-            uint8_t *kv_buffer = (uint8_t *)kv_malloc(key_size);\r
-            if (kv_buffer == NULL) {\r
-                return ERRCODE_MALLOC;\r
-            }\r
-            (void)memset_s(kv_buffer, key_size, 0, key_size);\r
-            ret = kv_key_helper_copy_flash((uint32_t)(uintptr_t)kv_buffer, (uint32_t)(uintptr_t)key.key_location,\r
-                key_size);\r
-            if (ret != ERRCODE_SUCC) {\r
-                kv_free(kv_buffer);\r
-                return ret;\r
-            }\r
-            ret = kv_key_write_flash(write_position, key_size, kv_buffer);\r
-            if (ret != ERRCODE_SUCC) {\r
-                kv_free(kv_buffer);\r
-                return ret;\r
-            }\r
-            kv_free(kv_buffer);\r
-            write_position += key_size;\r
-        }\r
-        key_found = kv_page_find_next_key(&dragpage, NULL, &key);\r
-    }\r
-\r
-    return ERRCODE_SUCC;\r
-}\r
-\r
-errcode_t kv_backup_copy_unused_page_to_dragpage(uint32_t dragpage_location, uint32_t unused_page_location)\r
-{\r
-    errcode_t ret;\r
-\r
-    /* 首先将工作区用来换页的页的key内容全部转移到备份区原来的页上 */\r
-    uint8_t *page_buffer = (uint8_t *)kv_malloc(KV_PAGE_SIZE - sizeof(kv_page_header_t));\r
-    if (page_buffer == NULL) {\r
-        return ERRCODE_MALLOC;\r
-    }\r
-    ret = kv_key_helper_copy_flash((uint32_t)(uintptr_t)page_buffer,\r
-        unused_page_location + sizeof(kv_page_header_t), KV_PAGE_SIZE - sizeof(kv_page_header_t));\r
-    if (ret != ERRCODE_SUCC) {\r
-        kv_free(page_buffer);\r
-        return ret;\r
-    }\r
-    ret = kv_key_write_flash(dragpage_location + sizeof(kv_page_header_t),\r
-        KV_PAGE_SIZE - sizeof(kv_page_header_t), page_buffer);\r
-    if (ret != ERRCODE_SUCC) {\r
-        kv_free(page_buffer);\r
-        return ret;\r
-    }\r
-    kv_free(page_buffer);\r
-\r
-    /* 其次拷贝工作区换页页的页头内容:先拷贝页内容,后拷贝页头是为了更好的处理换页时掉电异常场景 */\r
-    kv_page_header_t head_buffer;\r
-    ret = kv_key_helper_copy_flash((uint32_t)(uintptr_t)&head_buffer,\r
-        unused_page_location, sizeof(kv_page_header_t));\r
-    if (ret != ERRCODE_SUCC) {\r
-        return ret;\r
-    }\r
-    ret = kv_key_write_flash(dragpage_location, sizeof(kv_page_header_t), (uint8_t *)&head_buffer);\r
-    if (ret != ERRCODE_SUCC) {\r
-        return ret;\r
-    }\r
-\r
-    return ERRCODE_SUCC;\r
-}\r
-\r
-/* 备份区换页处理机制 */\r
-STATIC errcode_t kv_backup_dragpage_process(kv_page_handle_t dragpage)\r
-{\r
-    errcode_t ret;\r
-    kv_page_handle_t unused_page;\r
-    kv_page_location unused_page_location = NULL;\r
-    /* 1、去找工作区可以换页的页,然后将可以换页的页地址给传出 */\r
-    ret = kv_nvregion_find_unused_page(&unused_page_location);\r
-    if (ret != ERRCODE_SUCC) {\r
-        return ret;\r
-    }\r
-    /* 2、将工作区内可以换页的页的内容擦除 */\r
-    ret = kv_nvregion_erase_page(unused_page_location);\r
-    if (ret != ERRCODE_SUCC) {\r
-        return ret;\r
-    }\r
-    unused_page.page_location = unused_page_location;\r
-    /* 3、将备份区要换页的内容拷贝到工作区可以换页的页上 */\r
-    ret = kv_backup_dragpage_switch_unused_page(dragpage, unused_page);\r
-    if (ret != ERRCODE_SUCC) {\r
-        return ret;\r
-    }\r
-    /* 4、将备份区要换页的页擦除内容 */\r
-    ret = kv_key_erase_flash((uint32_t)(uintptr_t)dragpage.page_location, KV_PAGE_SIZE);\r
-    if (ret != ERRCODE_SUCC) {\r
-        return ret;\r
-    }\r
-    /* 5、将换页页的内容拷贝到备份区被擦除的页上 */\r
-    ret =  kv_backup_copy_unused_page_to_dragpage((uint32_t)dragpage.page_location,\r
-        (uint32_t)unused_page.page_location);\r
-    if (ret != ERRCODE_SUCC) {\r
-        return ret;\r
-    }\r
-    /* 6、擦除工作区换页页 */\r
-    ret = kv_nvregion_erase_page(unused_page_location);\r
-    if (ret != ERRCODE_SUCC) {\r
-        return ret;\r
-    }\r
-\r
-    return ERRCODE_SUCC;\r
-}\r
-\r
-STATIC errcode_t kv_backup_find_write_position(uint16_t required_space, uint32_t *write_position)\r
-{\r
-    errcode_t ret;\r
-    kv_page_handle_t page;\r
-    kv_page_status_t page_status;\r
-    kv_page_handle_t dragpage;\r
-    kv_nvregion_area_t* nvregion_area =  nv_get_region_area();\r
-    uint32_t page_start = nvregion_area->nv_backup_addr;\r
-    for (uint32_t page_index = 0; page_index < KV_BACKUP_PAGE_NUM; page_index++) {\r
-        page.page_location = (kv_page_location)(uintptr_t)(page_start + page_index * KV_PAGE_SIZE);\r
-        kv_page_get_status(&page, &page_status);\r
-        if ((page_status.total_space - page_status.used_space) >= required_space) {\r
-            *write_position = page_status.first_writable_location;\r
-            return ERRCODE_SUCC;\r
-        }\r
-\r
-        /* 找可换页页 */\r
-        if (page_status.max_key_space >= required_space) {\r
-            dragpage = page;\r
-        }\r
-    }\r
-\r
-    /* 进行备份区换页 */\r
-    ret = kv_backup_dragpage_process(dragpage);\r
-    if (ret != ERRCODE_SUCC) {\r
-        return ret;\r
-    }\r
-\r
-    /* 将备份区整理好的页可以写的位置传出 */\r
-    kv_page_get_status(&dragpage, &page_status);\r
-    if ((page_status.total_space - page_status.used_space) >= required_space) {\r
-        *write_position = page_status.first_writable_location;\r
-        return ERRCODE_SUCC;\r
-    }\r
-    return ERRCODE_NV_NO_ENOUGH_SPACE;\r
-}\r
-\r
-STATIC errcode_t kv_backup_write_one_page_key(kv_page_handle_t *page)\r
-{\r
-    errcode_t ret;\r
-    kv_key_handle_t key;\r
-    uint16_t key_size;\r
-    uint32_t write_position = 0;\r
-    errcode_t key_found = kv_page_find_first_key(page, NULL, &key);\r
-    while (key_found == ERRCODE_SUCC) {\r
-        if ((kv_key_is_valid(&key)) &&\r
-            (kv_region_is_enable(key.header.key_id) == ERRCODE_SUCC)) {\r
-            key_size = kv_key_flash_size(&key);\r
-            uint8_t *kv_buffer = (uint8_t *)kv_malloc(key_size);\r
-            if (kv_buffer == NULL) {\r
-                return ERRCODE_MALLOC;\r
-            }\r
-            ret = kv_key_helper_copy_flash((uint32_t)(uintptr_t)kv_buffer, (uint32_t)(uintptr_t)key.key_location,\r
-                key_size);\r
-            if (ret != ERRCODE_SUCC) {\r
-                kv_free(kv_buffer);\r
-                return ret;\r
-            }\r
-            ret = kv_backup_find_write_position(key_size, &write_position);\r
-            if (ret != ERRCODE_SUCC) {\r
-                kv_free(kv_buffer);\r
-                return ret;\r
-            }\r
-            ret = kv_key_write_flash(write_position, key_size, kv_buffer);\r
-            if (ret != ERRCODE_SUCC) {\r
-                kv_free(kv_buffer);\r
-                return ret;\r
-            }\r
-            kv_free(kv_buffer);\r
-        }\r
-        key_found = kv_page_find_next_key(page, NULL, &key);\r
-    }\r
-    return ERRCODE_SUCC;\r
-}\r
-\r
-errcode_t kv_backup_write_key(void)\r
-{\r
-    errcode_t ret;\r
-    kv_page_handle_t page;\r
-\r
-    for (uint32_t page_index = 0; page_index < KV_STORE_PAGES_ACPU; page_index++) {\r
-        ret = kv_store_get_page_handle(KV_STORE_APPLICATION, page_index, &page);\r
-        if (ret != ERRCODE_SUCC) {\r
-            return ret;\r
-        }\r
-        ret = kv_backup_write_one_page_key(&page);\r
-        if (ret != ERRCODE_SUCC) {\r
-            return ret;\r
-        }\r
-    }\r
-\r
-    return ERRCODE_SUCC;\r
-}\r
-\r
-STATIC errcode_t kv_read_backup_key(uint16_t key_id, uint16_t *kvalue_length, uint8_t *kvalue, nv_key_attr_t *attr,\r
-    kv_page_location page_location)\r
-{\r
-    kv_attributes_t backup_attribute = 0;\r
-    if (kvalue_length == NULL || kvalue == NULL || attr == NULL) {\r
-        return ERRCODE_NV_INVALID_PARAMS;\r
-    }\r
-\r
-    kv_store_key_data_t key_data = {*kvalue_length, 0, kvalue};\r
-    errcode_t ret_val = kv_store_get_backup_key(key_id, &key_data, &backup_attribute, page_location);\r
-    if (ret_val == ERRCODE_SUCC) {\r
-        memset_s(attr, sizeof(nv_key_attr_t), 0, sizeof(nv_key_attr_t));\r
-        if (((uint32_t)backup_attribute & NV_ATTRIBUTE_PERMANENT) != 0) {\r
-            attr->permanent = true;\r
-            attr->non_upgrade = true;\r
-        }\r
-        if (((uint32_t)backup_attribute & NV_ATTRIBUTE_ENCRYPTED) != 0) {\r
-            attr->encrypted = true;\r
-            attr->non_upgrade = true;\r
-        }\r
-        if (((uint32_t)backup_attribute & NV_ATTRIBUTE_NON_UPGRADE) != 0) {\r
-            attr->non_upgrade = true;\r
-        }\r
-    }\r
-    *kvalue_length = key_data.kvalue_actual_length;\r
-    return ret_val;\r
-}\r
-\r
-STATIC errcode_t kv_start_restore_all_keys(void)\r
-{\r
-    errcode_t ret = ERRCODE_SUCC;\r
-    uint16_t klength = 0;\r
-    uint8_t *kvalue;\r
-    nv_key_attr_t attr;\r
-    kv_key_handle_t key;\r
-    kv_page_handle_t page;\r
-    errcode_t key_found;\r
-    kv_nvregion_area_t* nvregion_area =  nv_get_region_area();\r
-    if (nvregion_area == NULL) {\r
-        return ERRCODE_FAIL;\r
-    }\r
-    for (uint32_t page_num = 0; page_num < KV_BACKUP_PAGE_NUM; page_num++) {\r
-        page.page_location = (kv_page_location)(uintptr_t)(nvregion_area->nv_backup_addr + page_num * KV_PAGE_SIZE);\r
-        key_found = kv_page_find_first_key(&page, NULL, &key);\r
-        while (key_found == ERRCODE_SUCC) {\r
-            if (kv_region_is_enable(key.header.key_id) == ERRCODE_SUCC) {\r
-                kvalue = (uint8_t *)kv_malloc(key.header.length);\r
-                klength = key.header.length;\r
-                (void)kv_read_backup_key(key.header.key_id, &klength, kvalue, &attr, page.page_location);\r
-                ret = nv_direct_write_with_attr(key.header.key_id, kvalue, klength, &attr, NULL);\r
-                kv_free(kvalue);\r
-            }\r
-            key_found = kv_page_find_next_key(&page, NULL, &key);\r
-        }\r
-    }\r
-    return ret;\r
-}\r
-\r
-errcode_t kv_enable_restore_flag(const nv_reset_mode_t *nv_reset_mode)\r
-{\r
-    nv_key_attr_t attr = {0};\r
-    attr.non_upgrade = true;\r
-    errcode_t ret = nv_direct_write_with_attr(NV_ID_RESTORE_ENABLE,\r
-        (uint8_t *)(uintptr_t)nv_reset_mode, sizeof(nv_reset_mode_t), &attr, NULL);\r
-    return ret;\r
-}\r
-\r
-static errcode_t kv_disable_restore_flag(void)\r
-{\r
-    nv_reset_mode_t nv_reset_mode = {0};\r
-    nv_key_attr_t attr = {0};\r
-    attr.non_upgrade = true;\r
-    errcode_t ret = nv_direct_write_with_attr(NV_ID_RESTORE_ENABLE,\r
-        (uint8_t *)(uintptr_t)nv_reset_mode, sizeof(nv_reset_mode_t), &attr, NULL);\r
-    return ret;\r
-}\r
-\r
-errcode_t kv_restore_set_region_flag(const bool *flag)\r
-{\r
-    if (flag == NULL) {\r
-        if (memset_s(g_reset_region_flag, sizeof(g_reset_region_flag), true, sizeof(g_reset_region_flag)) != EOK) {\r
-            return ERRCODE_MEMSET;\r
-        }\r
-    } else {\r
-        if (memcpy_s(g_reset_region_flag, sizeof(g_reset_region_flag), flag, sizeof(g_reset_region_flag)) != EOK) {\r
-            return ERRCODE_MEMCPY;\r
-        }\r
-    }\r
-    return ERRCODE_SUCC;\r
-}\r
-\r
-STATIC errcode_t kv_restore_clear_work_area(void)\r
-{\r
-    errcode_t ret;\r
-    kv_nvregion_area_t* nvregion_area =  nv_get_region_area();\r
-    if (nvregion_area == NULL) {\r
-        return ERRCODE_FAIL;\r
-    }\r
-    ret = kv_key_erase_flash(nvregion_area->nv_data_addr, KV_STORE_DATA_SIZE);\r
-    if (ret != ERRCODE_SUCC) {\r
-        return ret;\r
-    }\r
-    return kv_update_init((cores_t)KV_STORE_APPLICATION);\r
-}\r
-\r
-STATIC errcode_t kv_restore_mode_a(void)\r
-{\r
-    errcode_t ret;\r
-    ret = kv_restore_clear_work_area();\r
-    if (ret != ERRCODE_SUCC) {\r
-        return ret;\r
-    }\r
-\r
-    ret = kv_restore_set_region_flag(NULL);\r
-    if (ret != ERRCODE_SUCC) {\r
-        return ret;\r
-    }\r
-\r
-    return kv_start_restore_all_keys();\r
-}\r
-\r
-STATIC errcode_t kv_restore_mode_b(const bool *flag)\r
-{\r
-    if (flag == NULL) {\r
-        return ERRCODE_NV_ILLEGAL_OPERATION;\r
-    }\r
-\r
-    errcode_t ret;\r
-    ret = kv_restore_set_region_flag(flag);\r
-    if (ret != ERRCODE_SUCC) {\r
-        return ret;\r
-    }\r
-\r
-    ret = kv_reset_backup_retain_keys(KV_STORE_APPLICATION, kv_store_get_page_count(KV_STORE_APPLICATION));\r
-    if (ret != ERRCODE_SUCC) {\r
-        return ret;\r
-    }\r
-\r
-    ret = kv_restore_clear_work_area();\r
-    if (ret != ERRCODE_SUCC) {\r
-        return ret;\r
-    }\r
-\r
-    ret = kv_restore_set_region_flag(NULL);\r
-    if (ret != ERRCODE_SUCC) {\r
-        return ret;\r
-    }\r
-\r
-    ret = kv_start_restore_all_keys();\r
-    if (ret != ERRCODE_SUCC) {\r
-        return ret;\r
-    }\r
-\r
-    return restore_retain_keys();\r
-}\r
-\r
-errcode_t kv_backup_keys(const nv_backup_mode_t *backup_flag)\r
-{\r
-    errcode_t ret;\r
-    ret = kv_restore_set_region_flag(backup_flag->region_mode);\r
-    if (ret != ERRCODE_SUCC) {\r
-        return ret;\r
-    }\r
-    ret = kv_backup_delete_repeat_key();\r
-    if (ret != ERRCODE_SUCC) {\r
-        return ret;\r
-    }\r
-    return kv_backup_write_key();\r
-}\r
-\r
-errcode_t kv_restore_all_keys(void)\r
-{\r
-    errcode_t ret;\r
-    nv_reset_mode_t nv_reset_mode;\r
-    uint16_t flag_length;\r
-    nv_key_attr_t attr;\r
-    ret = nv_direct_get_key_data(NV_ID_RESTORE_ENABLE, sizeof(nv_reset_mode_t), &flag_length,\r
-        (uint8_t *)(uintptr_t)&nv_reset_mode, &attr);\r
-    if (ret != ERRCODE_SUCC) {\r
-        return ret;\r
-    }\r
-    (void)kv_disable_restore_flag();\r
-\r
-    if (nv_reset_mode.mode == RESET_MODE_A) {\r
-        return kv_restore_mode_a();\r
-    } else if (nv_reset_mode.mode == RESET_MODE_B) {\r
-        return kv_restore_mode_b(nv_reset_mode.region_flag);\r
-    } else {\r
-        return ERRCODE_NV_ILLEGAL_OPERATION;\r
-    }\r
-}\r
-\r
+/*
+ * Copyright (c) @CompanyNameMagicTag 2023-2023. All rights reserved.
+ * Description: NV Storage Library Restore factory settings interface
+ */
+#include "nv.h"
+#include "nv_store.h"
+#include "nv_page.h"
+#include "nv_storage.h"
+#include "nv_nvregion.h"
+#include "nv_porting.h"
+#include "nv_notify.h"
+#include "nv_task_adapt.h"
+#include "nv_update.h"
+#include "common_def.h"
+#include "nv_storage_handle.h"
+#include "nv_reset.h"
+
+#if (CONFIG_NV_SUPPORT_BACKUP_RESTORE == NV_YES)
+
+bool g_reset_region_flag[KEY_ID_REGION_MAX_NUM] = {0};
+STATIC retain_key_list_handle_t* g_retain_key_list = NULL;
+
+#define RESET_MAX_BINARY_VAL 1
+#define assert_r(x)        ((void)0)
+#define NV_RESTORE_MAX_KEY 4060
+
+STATIC errcode_t kv_region_is_enable(uint16_t key_id)
+{
+    uint16_t region_id = key_id / REGION_KEY_NUMS;
+    if (region_id < KEY_ID_REGION_MAX_NUM && g_reset_region_flag[region_id]) {
+        return ERRCODE_SUCC;
+    }
+    return ERRCODE_FAIL;
+}
+
+STATIC void retain_key_list_free(void)
+{
+    retain_key_t *current_key = g_retain_key_list->next;
+    retain_key_t *temp_key = NULL;
+    while (current_key != NULL) {
+        temp_key = current_key;
+        current_key = current_key->next;
+        if (temp_key->kvalue != NULL) {
+            kv_free(temp_key->kvalue);
+        }
+        kv_free(temp_key);
+        g_retain_key_list->list_length--;
+    }
+    kv_free(g_retain_key_list);
+    g_retain_key_list = NULL;
+}
+
+STATIC errcode_t retain_key_list_init(void)
+{
+    if (g_retain_key_list != NULL) {
+        return ERRCODE_SUCC;
+    }
+    g_retain_key_list = (retain_key_list_handle_t *)(uintptr_t)kv_malloc(sizeof(retain_key_list_handle_t));
+    if (g_retain_key_list == NULL) {
+        return ERRCODE_MALLOC;
+    }
+
+    g_retain_key_list->list_length = 0;
+    g_retain_key_list->tail = NULL;
+    g_retain_key_list->next = NULL;
+    return ERRCODE_SUCC;
+}
+
+STATIC void retain_key_list_add(retain_key_t* cur_key)
+{
+    if (g_retain_key_list->list_length == 0) {
+        g_retain_key_list->next = cur_key;
+        g_retain_key_list->tail = cur_key;
+    } else {
+        g_retain_key_list->tail->next = cur_key;
+        g_retain_key_list->tail = cur_key;
+    }
+    g_retain_key_list->list_length++;
+}
+
+STATIC errcode_t kv_reset_backup_retain_keys_helper(kv_page_handle_t *page)
+{
+    errcode_t res;
+    kv_key_handle_t key;
+    retain_key_t *cur_key = NULL;
+    res = retain_key_list_init();
+    if (res != ERRCODE_SUCC) {
+        return res;
+    }
+
+    errcode_t key_found = kv_page_find_first_key(page, NULL, &key);
+    while (key_found == ERRCODE_SUCC) {
+        if ((kv_key_is_valid(&key)) && (kv_region_is_enable(key.header.key_id) == ERRCODE_FAIL)) {
+            cur_key = (retain_key_t *)kv_malloc(sizeof(retain_key_t));
+            if (cur_key == NULL) {
+                return ERRCODE_MALLOC;
+            }
+            (void)memset_s(cur_key, sizeof(retain_key_t), 0, sizeof(retain_key_t));
+            cur_key->key = key.header.key_id;
+            cur_key->kvalue_length = key.header.length;
+            cur_key->kvalue = (uint8_t *)kv_malloc(cur_key->kvalue_length);
+            if (cur_key->kvalue == NULL) {
+                return ERRCODE_MALLOC;
+            }
+            cur_key->next = NULL;
+            res = kv_key_read_data(&key, cur_key->kvalue);
+            if (res != ERRCODE_SUCC) {
+                return ERRCODE_FAIL;
+            }
+            nv_log_debug("[NV] backup_retain_keys_helper key_id: %d\r\n", cur_key->key);
+            (void)retain_key_list_add(cur_key);
+        }
+        key_found = kv_page_find_next_key(page, NULL, &key);
+    }
+    return ERRCODE_SUCC;
+}
+
+STATIC errcode_t kv_reset_backup_retain_keys(kv_store_t store, uint8_t num_pages)
+{
+    errcode_t ret;
+    kv_page_handle_t kv_page;
+    for (uint8_t page_index = 0; page_index < num_pages; page_index++) {
+        ret = kv_store_get_page_handle(store, page_index, &kv_page);
+        if (ret != ERRCODE_SUCC) {
+            return ret;
+        }
+        ret = kv_reset_backup_retain_keys_helper(&kv_page);
+        if (ret != ERRCODE_SUCC) {
+            retain_key_list_free();
+            return ret;
+        }
+    }
+    return ERRCODE_SUCC;
+}
+
+STATIC errcode_t restore_retain_keys(void)
+{
+    if (g_retain_key_list == NULL) {
+        return ERRCODE_FAIL;
+    }
+    retain_key_t *cur_key = g_retain_key_list->next;
+    while (cur_key != NULL && cur_key->kvalue != NULL) {
+        nv_log_debug("[NV] restore_retain_keys_b key_id: 0x%x\r\n", cur_key->key);
+        (void)nv_direct_write_with_attr(cur_key->key, cur_key->kvalue, cur_key->kvalue_length, NULL, NULL);
+        cur_key = cur_key->next;
+    }
+    retain_key_list_free();
+    return ERRCODE_SUCC;
+}
+
+STATIC errcode_t kv_backup_invalid_key(const kv_key_handle_t *key)
+{
+    /* 计算valid相对于key起始的位置,即要写入数据在flash中相对于key_location的偏移量 */
+    uint32_t offset = ((uint32_t)(uintptr_t)&key->header.valid) - ((uint32_t)(uintptr_t)key);
+    uint32_t write_position = (uint32_t)(uintptr_t)key->key_location + offset - FLASH_PHYSICAL_ADDR_START;
+    uint32_t write_length = sizeof(key->header.valid);
+    uint8_t *write_data = (uint8_t *)kv_malloc(write_length);
+    if (write_data == NULL) {
+        return ERRCODE_MALLOC;
+    }
+    (void)memset_s(write_data, write_length, 0, write_length);
+    errcode_t ret = kv_flash_write(write_position, write_length, write_data, false);
+    kv_free(write_data);
+    return ret;
+}
+
+STATIC errcode_t kv_backup_delete_one_page_repeat_key(kv_page_handle_t *page)
+{
+    errcode_t ret;
+    kv_key_handle_t key;
+    errcode_t key_found = kv_page_find_first_key(page, NULL, &key);
+    while (key_found == ERRCODE_SUCC) {
+        if ((kv_key_is_valid(&key)) && (kv_region_is_enable(key.header.key_id) == ERRCODE_SUCC)) {
+            ret = kv_backup_invalid_key(&key);
+            if (ret != ERRCODE_SUCC) {
+                return ret;
+            }
+        }
+        key_found = kv_page_find_next_key(page, NULL, &key);
+    }
+    return ERRCODE_SUCC;
+}
+
+errcode_t kv_backup_delete_repeat_key(void)
+{
+    errcode_t ret;
+    kv_page_handle_t page;
+    kv_nvregion_area_t* nvregion_area =  nv_get_region_area();
+    if (nvregion_area == NULL) {
+        return ERRCODE_FAIL;
+    }
+    uint32_t page_start = nvregion_area->nv_backup_addr;
+    /* 遍历备份区,将每个要被重复备份的key标志位置为无效 */
+    for (uint32_t page_index = 0; page_index < KV_BACKUP_PAGE_NUM; page_index++) {
+        page.page_location = (kv_page_location)(uintptr_t)(page_start + page_index * KV_PAGE_SIZE);
+        ret = kv_backup_delete_one_page_repeat_key(&page);
+        if (ret != ERRCODE_SUCC) {
+            return ret;
+        }
+    }
+
+    return ERRCODE_SUCC;
+}
+
+STATIC errcode_t kv_backup_dragpage_switch_unused_page(kv_page_handle_t dragpage, kv_page_handle_t unused_page)
+{
+    /* 将换页页内容转移到unused page */
+    errcode_t ret;
+    uint32_t page_head_size = (uint32_t)sizeof(kv_page_header_t);
+
+    /* 将换页页的页头转移到unused page */
+    kv_page_header_t head_buffer;
+    ret = kv_key_helper_copy_flash((uint32_t)(uintptr_t)&head_buffer,
+        (uint32_t)dragpage.page_location, page_head_size);
+    if (ret != ERRCODE_SUCC) {
+        return ret;
+    }
+    ret = kv_key_write_flash((uint32_t)unused_page.page_location, page_head_size, (uint8_t *)&head_buffer);
+    if (ret != ERRCODE_SUCC) {
+        return ret;
+    }
+
+    kv_key_handle_t key;
+    uint16_t key_size;
+    uint32_t write_position = (uint32_t)((uintptr_t)unused_page.page_location + page_head_size);
+    /* 将换页页的有效的key转移到unused page */
+    errcode_t key_found = kv_page_find_first_key(&dragpage, NULL, &key);
+    while (key_found == ERRCODE_SUCC) {
+        if (kv_key_is_valid(&key)) {
+            key_size = kv_key_flash_size(&key);
+            uint8_t *kv_buffer = (uint8_t *)kv_malloc(key_size);
+            if (kv_buffer == NULL) {
+                return ERRCODE_MALLOC;
+            }
+            (void)memset_s(kv_buffer, key_size, 0, key_size);
+            ret = kv_key_helper_copy_flash((uint32_t)(uintptr_t)kv_buffer, (uint32_t)(uintptr_t)key.key_location,
+                key_size);
+            if (ret != ERRCODE_SUCC) {
+                kv_free(kv_buffer);
+                return ret;
+            }
+            ret = kv_key_write_flash(write_position, key_size, kv_buffer);
+            if (ret != ERRCODE_SUCC) {
+                kv_free(kv_buffer);
+                return ret;
+            }
+            kv_free(kv_buffer);
+            write_position += key_size;
+        }
+        key_found = kv_page_find_next_key(&dragpage, NULL, &key);
+    }
+
+    return ERRCODE_SUCC;
+}
+
+errcode_t kv_backup_copy_unused_page_to_dragpage(uint32_t dragpage_location, uint32_t unused_page_location)
+{
+    errcode_t ret;
+
+    /* 首先将工作区用来换页的页的key内容全部转移到备份区原来的页上 */
+    uint8_t *page_buffer = (uint8_t *)kv_malloc(KV_PAGE_SIZE - sizeof(kv_page_header_t));
+    if (page_buffer == NULL) {
+        return ERRCODE_MALLOC;
+    }
+    ret = kv_key_helper_copy_flash((uint32_t)(uintptr_t)page_buffer,
+        unused_page_location + sizeof(kv_page_header_t), KV_PAGE_SIZE - sizeof(kv_page_header_t));
+    if (ret != ERRCODE_SUCC) {
+        kv_free(page_buffer);
+        return ret;
+    }
+    ret = kv_key_write_flash(dragpage_location + sizeof(kv_page_header_t),
+        KV_PAGE_SIZE - sizeof(kv_page_header_t), page_buffer);
+    if (ret != ERRCODE_SUCC) {
+        kv_free(page_buffer);
+        return ret;
+    }
+    kv_free(page_buffer);
+
+    /* 其次拷贝工作区换页页的页头内容:先拷贝页内容,后拷贝页头是为了更好的处理换页时掉电异常场景 */
+    kv_page_header_t head_buffer;
+    ret = kv_key_helper_copy_flash((uint32_t)(uintptr_t)&head_buffer,
+        unused_page_location, sizeof(kv_page_header_t));
+    if (ret != ERRCODE_SUCC) {
+        return ret;
+    }
+    ret = kv_key_write_flash(dragpage_location, sizeof(kv_page_header_t), (uint8_t *)&head_buffer);
+    if (ret != ERRCODE_SUCC) {
+        return ret;
+    }
+
+    return ERRCODE_SUCC;
+}
+
+/* 备份区换页处理机制 */
+STATIC errcode_t kv_backup_dragpage_process(kv_page_handle_t dragpage)
+{
+    errcode_t ret;
+    kv_page_handle_t unused_page;
+    kv_page_location unused_page_location = NULL;
+    /* 1、去找工作区可以换页的页,然后将可以换页的页地址给传出 */
+    ret = kv_nvregion_find_unused_page(&unused_page_location);
+    if (ret != ERRCODE_SUCC) {
+        return ret;
+    }
+    /* 2、将工作区内可以换页的页的内容擦除 */
+    ret = kv_nvregion_erase_page(unused_page_location);
+    if (ret != ERRCODE_SUCC) {
+        return ret;
+    }
+    unused_page.page_location = unused_page_location;
+    /* 3、将备份区要换页的内容拷贝到工作区可以换页的页上 */
+    ret = kv_backup_dragpage_switch_unused_page(dragpage, unused_page);
+    if (ret != ERRCODE_SUCC) {
+        return ret;
+    }
+    /* 4、将备份区要换页的页擦除内容 */
+    ret = kv_key_erase_flash((uint32_t)(uintptr_t)dragpage.page_location, KV_PAGE_SIZE);
+    if (ret != ERRCODE_SUCC) {
+        return ret;
+    }
+    /* 5、将换页页的内容拷贝到备份区被擦除的页上 */
+    ret =  kv_backup_copy_unused_page_to_dragpage((uint32_t)dragpage.page_location,
+        (uint32_t)unused_page.page_location);
+    if (ret != ERRCODE_SUCC) {
+        return ret;
+    }
+    /* 6、擦除工作区换页页 */
+    ret = kv_nvregion_erase_page(unused_page_location);
+    if (ret != ERRCODE_SUCC) {
+        return ret;
+    }
+
+    return ERRCODE_SUCC;
+}
+
+STATIC errcode_t kv_backup_find_write_position(uint16_t required_space, uint32_t *write_position)
+{
+    errcode_t ret;
+    kv_page_handle_t page;
+    kv_page_status_t page_status;
+    kv_page_handle_t dragpage;
+    kv_nvregion_area_t* nvregion_area =  nv_get_region_area();
+    uint32_t page_start = nvregion_area->nv_backup_addr;
+    for (uint32_t page_index = 0; page_index < KV_BACKUP_PAGE_NUM; page_index++) {
+        page.page_location = (kv_page_location)(uintptr_t)(page_start + page_index * KV_PAGE_SIZE);
+        kv_page_get_status(&page, &page_status);
+        if ((page_status.total_space - page_status.used_space) >= required_space) {
+            *write_position = page_status.first_writable_location;
+            return ERRCODE_SUCC;
+        }
+
+        /* 找可换页页 */
+        if (page_status.max_key_space >= required_space) {
+            dragpage = page;
+        }
+    }
+
+    /* 进行备份区换页 */
+    ret = kv_backup_dragpage_process(dragpage);
+    if (ret != ERRCODE_SUCC) {
+        return ret;
+    }
+
+    /* 将备份区整理好的页可以写的位置传出 */
+    kv_page_get_status(&dragpage, &page_status);
+    if ((page_status.total_space - page_status.used_space) >= required_space) {
+        *write_position = page_status.first_writable_location;
+        return ERRCODE_SUCC;
+    }
+    return ERRCODE_NV_NO_ENOUGH_SPACE;
+}
+
+STATIC errcode_t kv_backup_write_one_page_key(kv_page_handle_t *page)
+{
+    errcode_t ret;
+    kv_key_handle_t key;
+    uint16_t key_size;
+    uint32_t write_position = 0;
+    errcode_t key_found = kv_page_find_first_key(page, NULL, &key);
+    while (key_found == ERRCODE_SUCC) {
+        if ((kv_key_is_valid(&key)) &&
+            (kv_region_is_enable(key.header.key_id) == ERRCODE_SUCC)) {
+            key_size = kv_key_flash_size(&key);
+            uint8_t *kv_buffer = (uint8_t *)kv_malloc(key_size);
+            if (kv_buffer == NULL) {
+                return ERRCODE_MALLOC;
+            }
+            ret = kv_key_helper_copy_flash((uint32_t)(uintptr_t)kv_buffer, (uint32_t)(uintptr_t)key.key_location,
+                key_size);
+            if (ret != ERRCODE_SUCC) {
+                kv_free(kv_buffer);
+                return ret;
+            }
+            ret = kv_backup_find_write_position(key_size, &write_position);
+            if (ret != ERRCODE_SUCC) {
+                kv_free(kv_buffer);
+                return ret;
+            }
+            ret = kv_key_write_flash(write_position, key_size, kv_buffer);
+            if (ret != ERRCODE_SUCC) {
+                kv_free(kv_buffer);
+                return ret;
+            }
+            kv_free(kv_buffer);
+        }
+        key_found = kv_page_find_next_key(page, NULL, &key);
+    }
+    return ERRCODE_SUCC;
+}
+
+errcode_t kv_backup_write_key(void)
+{
+    errcode_t ret;
+    kv_page_handle_t page;
+
+    for (uint32_t page_index = 0; page_index < KV_STORE_PAGES_ACPU; page_index++) {
+        ret = kv_store_get_page_handle(KV_STORE_APPLICATION, page_index, &page);
+        if (ret != ERRCODE_SUCC) {
+            return ret;
+        }
+        ret = kv_backup_write_one_page_key(&page);
+        if (ret != ERRCODE_SUCC) {
+            return ret;
+        }
+    }
+
+    return ERRCODE_SUCC;
+}
+
+STATIC errcode_t kv_read_backup_key(uint16_t key_id, uint16_t *kvalue_length, uint8_t *kvalue, nv_key_attr_t *attr,
+    kv_page_location page_location)
+{
+    kv_attributes_t backup_attribute = 0;
+    if (kvalue_length == NULL || kvalue == NULL || attr == NULL) {
+        return ERRCODE_NV_INVALID_PARAMS;
+    }
+
+    kv_store_key_data_t key_data = {*kvalue_length, 0, kvalue};
+    errcode_t ret_val = kv_store_get_backup_key(key_id, &key_data, &backup_attribute, page_location);
+    if (ret_val == ERRCODE_SUCC) {
+        memset_s(attr, sizeof(nv_key_attr_t), 0, sizeof(nv_key_attr_t));
+        if (((uint32_t)backup_attribute & NV_ATTRIBUTE_PERMANENT) != 0) {
+            attr->permanent = true;
+            attr->non_upgrade = true;
+        }
+        if (((uint32_t)backup_attribute & NV_ATTRIBUTE_ENCRYPTED) != 0) {
+            attr->encrypted = true;
+            attr->non_upgrade = true;
+        }
+        if (((uint32_t)backup_attribute & NV_ATTRIBUTE_NON_UPGRADE) != 0) {
+            attr->non_upgrade = true;
+        }
+    }
+    *kvalue_length = key_data.kvalue_actual_length;
+    return ret_val;
+}
+
+STATIC errcode_t kv_start_restore_all_keys(void)
+{
+    errcode_t ret = ERRCODE_SUCC;
+    uint16_t klength = 0;
+    uint8_t *kvalue;
+    nv_key_attr_t attr;
+    kv_key_handle_t key;
+    kv_page_handle_t page;
+    errcode_t key_found;
+    kv_nvregion_area_t* nvregion_area =  nv_get_region_area();
+    if (nvregion_area == NULL) {
+        return ERRCODE_FAIL;
+    }
+    for (uint32_t page_num = 0; page_num < KV_BACKUP_PAGE_NUM; page_num++) {
+        page.page_location = (kv_page_location)(uintptr_t)(nvregion_area->nv_backup_addr + page_num * KV_PAGE_SIZE);
+        key_found = kv_page_find_first_key(&page, NULL, &key);
+        while (key_found == ERRCODE_SUCC) {
+            if (kv_region_is_enable(key.header.key_id) == ERRCODE_SUCC) {
+                kvalue = (uint8_t *)kv_malloc(key.header.length);
+                klength = key.header.length;
+                (void)kv_read_backup_key(key.header.key_id, &klength, kvalue, &attr, page.page_location);
+                ret = nv_direct_write_with_attr(key.header.key_id, kvalue, klength, &attr, NULL);
+                kv_free(kvalue);
+            }
+            key_found = kv_page_find_next_key(&page, NULL, &key);
+        }
+    }
+    return ret;
+}
+
+errcode_t kv_enable_restore_flag(const nv_reset_mode_t *nv_reset_mode)
+{
+    nv_key_attr_t attr = {0};
+    attr.non_upgrade = true;
+    errcode_t ret = nv_direct_write_with_attr(NV_ID_RESTORE_ENABLE,
+        (uint8_t *)(uintptr_t)nv_reset_mode, sizeof(nv_reset_mode_t), &attr, NULL);
+    return ret;
+}
+
+static errcode_t kv_disable_restore_flag(void)
+{
+    nv_reset_mode_t nv_reset_mode = {0};
+    nv_key_attr_t attr = {0};
+    attr.non_upgrade = true;
+    errcode_t ret = nv_direct_write_with_attr(NV_ID_RESTORE_ENABLE,
+        (uint8_t *)(uintptr_t)nv_reset_mode, sizeof(nv_reset_mode_t), &attr, NULL);
+    return ret;
+}
+
+errcode_t kv_restore_set_region_flag(const bool *flag)
+{
+    if (flag == NULL) {
+        if (memset_s(g_reset_region_flag, sizeof(g_reset_region_flag), true, sizeof(g_reset_region_flag)) != EOK) {
+            return ERRCODE_MEMSET;
+        }
+    } else {
+        if (memcpy_s(g_reset_region_flag, sizeof(g_reset_region_flag), flag, sizeof(g_reset_region_flag)) != EOK) {
+            return ERRCODE_MEMCPY;
+        }
+    }
+    return ERRCODE_SUCC;
+}
+
+STATIC errcode_t kv_restore_clear_work_area(void)
+{
+    errcode_t ret;
+    kv_nvregion_area_t* nvregion_area =  nv_get_region_area();
+    if (nvregion_area == NULL) {
+        return ERRCODE_FAIL;
+    }
+    ret = kv_key_erase_flash(nvregion_area->nv_data_addr, KV_STORE_DATA_SIZE);
+    if (ret != ERRCODE_SUCC) {
+        return ret;
+    }
+    return kv_update_init((cores_t)KV_STORE_APPLICATION);
+}
+
+STATIC errcode_t kv_restore_mode_a(void)
+{
+    errcode_t ret;
+    ret = kv_restore_clear_work_area();
+    if (ret != ERRCODE_SUCC) {
+        return ret;
+    }
+
+    ret = kv_restore_set_region_flag(NULL);
+    if (ret != ERRCODE_SUCC) {
+        return ret;
+    }
+
+    return kv_start_restore_all_keys();
+}
+
+STATIC errcode_t kv_restore_mode_b(const bool *flag)
+{
+    if (flag == NULL) {
+        return ERRCODE_NV_ILLEGAL_OPERATION;
+    }
+
+    errcode_t ret;
+    ret = kv_restore_set_region_flag(flag);
+    if (ret != ERRCODE_SUCC) {
+        return ret;
+    }
+
+    ret = kv_reset_backup_retain_keys(KV_STORE_APPLICATION, kv_store_get_page_count(KV_STORE_APPLICATION));
+    if (ret != ERRCODE_SUCC) {
+        return ret;
+    }
+
+    ret = kv_restore_clear_work_area();
+    if (ret != ERRCODE_SUCC) {
+        return ret;
+    }
+
+    ret = kv_restore_set_region_flag(NULL);
+    if (ret != ERRCODE_SUCC) {
+        return ret;
+    }
+
+    ret = kv_start_restore_all_keys();
+    if (ret != ERRCODE_SUCC) {
+        return ret;
+    }
+
+    return restore_retain_keys();
+}
+
+errcode_t kv_backup_keys(const nv_backup_mode_t *backup_flag)
+{
+    errcode_t ret;
+    ret = kv_restore_set_region_flag(backup_flag->region_mode);
+    if (ret != ERRCODE_SUCC) {
+        return ret;
+    }
+    ret = kv_backup_delete_repeat_key();
+    if (ret != ERRCODE_SUCC) {
+        return ret;
+    }
+    return kv_backup_write_key();
+}
+
+errcode_t kv_restore_all_keys(void)
+{
+    errcode_t ret;
+    nv_reset_mode_t nv_reset_mode;
+    uint16_t flag_length;
+    nv_key_attr_t attr;
+    ret = nv_direct_get_key_data(NV_ID_RESTORE_ENABLE, sizeof(nv_reset_mode_t), &flag_length,
+        (uint8_t *)(uintptr_t)&nv_reset_mode, &attr);
+    if (ret != ERRCODE_SUCC) {
+        return ret;
+    }
+    (void)kv_disable_restore_flag();
+
+    if (nv_reset_mode.mode == RESET_MODE_A) {
+        return kv_restore_mode_a();
+    } else if (nv_reset_mode.mode == RESET_MODE_B) {
+        return kv_restore_mode_b(nv_reset_mode.region_flag);
+    } else {
+        return ERRCODE_NV_ILLEGAL_OPERATION;
+    }
+}
+
 #endif /* #if (CONFIG_NV_SUPPORT_BACKUP_RESTORE == NV_YES) */
\ No newline at end of file
index e1ed42e..ca884f0 100755 (executable)
@@ -1,55 +1,55 @@
-/*\r
- * Copyright (c) @CompanyNameMagicTag 2023-2023. All rights reserved.\r
- * Description: NV Storage Library Restore factory settings interface\r
- */\r
-\r
-#ifndef NV_RESET_H_\r
-#define NV_RESET_H_\r
-\r
-#include "nv.h"\r
-#include "errcode.h"\r
-\r
-#ifdef __cplusplus\r
-#if __cplusplus\r
-extern "C" {\r
-#endif /* __cplusplus */\r
-#endif /* __cplusplus */\r
-\r
-#define RESET_MODE_A        1\r
-#define RESET_MODE_B        2\r
-\r
-typedef struct {\r
-    uint8_t mode;\r
-    bool region_flag[KEY_ID_REGION_MAX_NUM];\r
-} nv_reset_mode_t;\r
-\r
-typedef struct retain_key {\r
-    uint16_t key;\r
-    uint16_t kvalue_length;\r
-    uint8_t  *kvalue;\r
-    struct retain_key* next;\r
-} retain_key_t;\r
-\r
-typedef struct {\r
-    uint8_t list_length;\r
-    retain_key_t* tail;\r
-    retain_key_t* next;\r
-} retain_key_list_handle_t;\r
-\r
-errcode_t kv_backup_keys(const nv_backup_mode_t *backup_flag);\r
-errcode_t kv_restore_all_keys(void);\r
-errcode_t kv_enable_restore_flag(const nv_reset_mode_t *nv_reset_mode);\r
-errcode_t kv_backup_copy_unused_page_to_dragpage(uint32_t dragpage_location, uint32_t unused_page_location);\r
-\r
-errcode_t kv_restore_set_region_flag(const bool *flag);\r
-errcode_t kv_backup_delete_repeat_key(void);\r
-errcode_t kv_backup_write_key(void);\r
-\r
-#ifdef __cplusplus\r
-#if __cplusplus\r
-}\r
-#endif /* __cplusplus */\r
-#endif /* __cplusplus */\r
-\r
-#endif /* NV_RESET_H_ */\r
-\r
+/*
+ * Copyright (c) @CompanyNameMagicTag 2023-2023. All rights reserved.
+ * Description: NV Storage Library Restore factory settings interface
+ */
+
+#ifndef NV_RESET_H_
+#define NV_RESET_H_
+
+#include "nv.h"
+#include "errcode.h"
+
+#ifdef __cplusplus
+#if __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+#define RESET_MODE_A        1
+#define RESET_MODE_B        2
+
+typedef struct {
+    uint8_t mode;
+    bool region_flag[KEY_ID_REGION_MAX_NUM];
+} nv_reset_mode_t;
+
+typedef struct retain_key {
+    uint16_t key;
+    uint16_t kvalue_length;
+    uint8_t  *kvalue;
+    struct retain_key* next;
+} retain_key_t;
+
+typedef struct {
+    uint8_t list_length;
+    retain_key_t* tail;
+    retain_key_t* next;
+} retain_key_list_handle_t;
+
+errcode_t kv_backup_keys(const nv_backup_mode_t *backup_flag);
+errcode_t kv_restore_all_keys(void);
+errcode_t kv_enable_restore_flag(const nv_reset_mode_t *nv_reset_mode);
+errcode_t kv_backup_copy_unused_page_to_dragpage(uint32_t dragpage_location, uint32_t unused_page_location);
+
+errcode_t kv_restore_set_region_flag(const bool *flag);
+errcode_t kv_backup_delete_repeat_key(void);
+errcode_t kv_backup_write_key(void);
+
+#ifdef __cplusplus
+#if __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+#endif /* NV_RESET_H_ */
+
index 5fd5e0f..c951ab2 100755 (executable)
@@ -1,96 +1,96 @@
-/*\r
- * Copyright (c) @CompanyNameMagicTag 2019-2022. All rights reserved.\r
- * Description: KV Storage Library remote RPC handler implementations\r
- */\r
-#ifndef CONFIG_NV_SUPPORT_SINGLE_CORE_SYSTEM\r
-#include "nv_rpc.h"\r
-#include "rpc_auto_generated.h"\r
-#include "rpc_interface.h"\r
-#include "nv_store.h"\r
-#include "nv_porting.h"\r
-\r
-errcode_t uapi_rpc_remote_cmd_kv_store_get_status(cores core, uint16_t *store_status_length,\r
-                                                  rpc_auto_generated_release_func *store_status_free_mem_callback,\r
-                                                  uint8_t **store_status)\r
-{\r
-    errcode_t call_err;\r
-    kv_store_t store;\r
-    unused(call_err);\r
-    /* Initialise pass-back values in case we fail early */\r
-    *store_status = NULL;\r
-    *store_status_length = 0;\r
-\r
-    uint32_t status_size = sizeof(nv_store_status_t);\r
-    *store_status = osal_kmalloc(sizeof(nv_store_status_t), OSAL_GFP_KERNEL);\r
-    if (*store_status == NULL) {\r
-        return ERRCODE_MALLOC;\r
-    }\r
-    *store_status_length = status_size;\r
-    *store_status_free_mem_callback = osal_kfree;\r
-    store = kv_store_from_core(core);\r
-    return kv_store_get_status(store, *store_status);\r
-}\r
-\r
-errcode_t uapi_rpc_remote_cmd_kv_store_get_key(cores core, uint16_t key_id, uint16_t *kvalue_length,\r
-                                               rpc_auto_generated_release_func *kvalue_free_mem_callback,\r
-                                               uint8_t **kvalue)\r
-{\r
-    errcode_t call_err;\r
-    kv_store_t store;\r
-    kv_key_handle_t key;\r
-\r
-    /* Initialise pass-back values in case we fail early */\r
-    *kvalue = NULL;\r
-    *kvalue_length = 0;\r
-\r
-    store = kv_store_from_core(core);\r
-    call_err = kv_store_find_valid_key(store, key_id, &key);\r
-    if (call_err != ERRCODE_SUCC) {\r
-        return call_err;\r
-    }\r
-\r
-    /* Attempt to obtain key data from store */\r
-    *kvalue = osal_kmalloc(key.header.length, OSAL_GFP_KERNEL);\r
-    if (*kvalue == NULL) {\r
-        return ERRCODE_MALLOC;\r
-    }\r
-    *kvalue_length = key.header.length;\r
-    *kvalue_free_mem_callback = osal_kfree;\r
-\r
-    return kv_key_read_data(&key, *kvalue);\r
-}\r
-\r
-errcode_t uapi_rpc_remote_cmd_kv_store_get_key_by_addr(cores core,\r
-                                                       uint16_t key_id,\r
-                                                       uint32_t kvalue_addr,\r
-                                                       uint16_t length)\r
-{\r
-    errcode_t call_err;\r
-    kv_store_t store;\r
-    kv_key_handle_t key;\r
-\r
-    store = kv_store_from_core(core);\r
-    call_err = kv_store_find_valid_key(store, key_id, &key);\r
-    if (call_err != ERRCODE_SUCC) {\r
-        return call_err;\r
-    }\r
-\r
-    /* Attempt to obtain key data from store */\r
-    if (length < key.header.length) {\r
-        return ERRCODE_NV_GET_BUFFER_TOO_SMALL;\r
-    }\r
-    return kv_key_read_data(&key, (uint8_t *)(uintptr_t)kvalue_addr);\r
-}\r
-\r
-errcode_t uapi_rpc_remote_cmd_kv_store_get_key_attr(cores core, uint16_t key_id, uint16_t *len, uint8_t *attributes)\r
-{\r
-    kv_store_t store;\r
-\r
-    /* Initialise pass-back value in case we fail early */\r
-    *attributes = 0;\r
-    *len = 0;\r
-\r
-    store = kv_store_from_core(core);\r
-    return kv_store_get_key_attr(store, (kv_key_id)key_id, len, (kv_attributes_t *)attributes);\r
-}\r
-#endif\r
+/*
+ * Copyright (c) @CompanyNameMagicTag 2019-2022. All rights reserved.
+ * Description: KV Storage Library remote RPC handler implementations
+ */
+#ifndef CONFIG_NV_SUPPORT_SINGLE_CORE_SYSTEM
+#include "nv_rpc.h"
+#include "rpc_auto_generated.h"
+#include "rpc_interface.h"
+#include "nv_store.h"
+#include "nv_porting.h"
+
+errcode_t uapi_rpc_remote_cmd_kv_store_get_status(cores core, uint16_t *store_status_length,
+                                                  rpc_auto_generated_release_func *store_status_free_mem_callback,
+                                                  uint8_t **store_status)
+{
+    errcode_t call_err;
+    kv_store_t store;
+    unused(call_err);
+    /* Initialise pass-back values in case we fail early */
+    *store_status = NULL;
+    *store_status_length = 0;
+
+    uint32_t status_size = sizeof(nv_store_status_t);
+    *store_status = osal_kmalloc(sizeof(nv_store_status_t), OSAL_GFP_KERNEL);
+    if (*store_status == NULL) {
+        return ERRCODE_MALLOC;
+    }
+    *store_status_length = status_size;
+    *store_status_free_mem_callback = osal_kfree;
+    store = kv_store_from_core(core);
+    return kv_store_get_status(store, *store_status);
+}
+
+errcode_t uapi_rpc_remote_cmd_kv_store_get_key(cores core, uint16_t key_id, uint16_t *kvalue_length,
+                                               rpc_auto_generated_release_func *kvalue_free_mem_callback,
+                                               uint8_t **kvalue)
+{
+    errcode_t call_err;
+    kv_store_t store;
+    kv_key_handle_t key;
+
+    /* Initialise pass-back values in case we fail early */
+    *kvalue = NULL;
+    *kvalue_length = 0;
+
+    store = kv_store_from_core(core);
+    call_err = kv_store_find_valid_key(store, key_id, &key);
+    if (call_err != ERRCODE_SUCC) {
+        return call_err;
+    }
+
+    /* Attempt to obtain key data from store */
+    *kvalue = osal_kmalloc(key.header.length, OSAL_GFP_KERNEL);
+    if (*kvalue == NULL) {
+        return ERRCODE_MALLOC;
+    }
+    *kvalue_length = key.header.length;
+    *kvalue_free_mem_callback = osal_kfree;
+
+    return kv_key_read_data(&key, *kvalue);
+}
+
+errcode_t uapi_rpc_remote_cmd_kv_store_get_key_by_addr(cores core,
+                                                       uint16_t key_id,
+                                                       uint32_t kvalue_addr,
+                                                       uint16_t length)
+{
+    errcode_t call_err;
+    kv_store_t store;
+    kv_key_handle_t key;
+
+    store = kv_store_from_core(core);
+    call_err = kv_store_find_valid_key(store, key_id, &key);
+    if (call_err != ERRCODE_SUCC) {
+        return call_err;
+    }
+
+    /* Attempt to obtain key data from store */
+    if (length < key.header.length) {
+        return ERRCODE_NV_GET_BUFFER_TOO_SMALL;
+    }
+    return kv_key_read_data(&key, (uint8_t *)(uintptr_t)kvalue_addr);
+}
+
+errcode_t uapi_rpc_remote_cmd_kv_store_get_key_attr(cores core, uint16_t key_id, uint16_t *len, uint8_t *attributes)
+{
+    kv_store_t store;
+
+    /* Initialise pass-back value in case we fail early */
+    *attributes = 0;
+    *len = 0;
+
+    store = kv_store_from_core(core);
+    return kv_store_get_key_attr(store, (kv_key_id)key_id, len, (kv_attributes_t *)attributes);
+}
+#endif
index af8e6a4..04ef820 100755 (executable)
@@ -1,11 +1,11 @@
-/*\r
- * Copyright (c) @CompanyNameMagicTag 2019-2022. All rights reserved.\r
- * Description: KV Storage Library remote RPC handler implementations\r
- */\r
-\r
-#include "errcode.h"\r
-\r
-#ifndef SRC_LIB_KV_STORAGE_PUBLIC_NV_RPC_H_\r
-#define SRC_LIB_KV_STORAGE_PUBLIC_NV_RPC_H_\r
-\r
-#endif /* SRC_LIB_KV_STORAGE_PUBLIC_NV_RPC_H_ */\r
+/*
+ * Copyright (c) @CompanyNameMagicTag 2019-2022. All rights reserved.
+ * Description: KV Storage Library remote RPC handler implementations
+ */
+
+#include "errcode.h"
+
+#ifndef SRC_LIB_KV_STORAGE_PUBLIC_NV_RPC_H_
+#define SRC_LIB_KV_STORAGE_PUBLIC_NV_RPC_H_
+
+#endif /* SRC_LIB_KV_STORAGE_PUBLIC_NV_RPC_H_ */
index 888937a..32d4e42 100755 (executable)
@@ -1,58 +1,58 @@
-/*\r
- * Copyright (c) @CompanyNameMagicTag 2019-2022. All rights reserved.\r
- * Description: KV Storage Library store access interface\r
- */\r
-\r
-#ifndef NV_STORE_H\r
-#define NV_STORE_H\r
-\r
-#include "nv_page.h"\r
-#include "platform_types.h"\r
-#include "nv.h"\r
-#include "errcode.h"\r
-\r
-#ifdef __cplusplus\r
-#if __cplusplus\r
-extern "C" {\r
-#endif /* __cplusplus */\r
-#endif /* __cplusplus */\r
-\r
-/** Store ids for each core, with a minimum hamming distance of 10 between each value */\r
-#define KV_STORE_ID_SCPU    0xCB7E\r
-#define KV_STORE_ID_ACPU    0x254D\r
-#define KV_STORE_ID_BACKUP  0x34B2\r
-\r
-typedef enum {\r
-    KV_STORE_APPLICATION,\r
-    KV_STORE_MAX_NUM,\r
-} kv_store_t;\r
-\r
-typedef struct {\r
-    uint16_t kvalue_max_length;\r
-    uint16_t kvalue_actual_length;\r
-    uint8_t *kvalue;\r
-} kv_store_key_data_t;\r
-\r
-cores_t kv_store_to_core(kv_store_t store);\r
-kv_store_t kv_store_from_core(cores_t core);\r
-uint16_t kv_store_get_id(kv_store_t store);\r
-uint8_t kv_store_get_page_count(kv_store_t store);\r
-errcode_t kv_store_get_page_handle(kv_store_t store, uint32_t page_index, kv_page_handle_t *page);\r
-errcode_t kv_store_find_valid_key(kv_store_t store, kv_key_id key_id, kv_key_handle_t *key);\r
-errcode_t kv_store_get_backup_key(kv_key_id key_id, kv_store_key_data_t *key_data, kv_attributes_t *attributes,\r
-    kv_page_location page_location);\r
-errcode_t kv_store_get_key_attr(kv_store_t store, kv_key_id key_id, uint16_t *len, kv_attributes_t *attributes);\r
-errcode_t kv_store_get_key(kv_store_t store, kv_key_id key_id, kv_store_key_data_t *key_data,\r
-                           kv_attributes_t *attributes);\r
-errcode_t kv_store_get_status(kv_store_t store, nv_store_status_t *store_status);\r
-errcode_t kv_store_find_write_page(kv_store_t store, uint32_t required_space, kv_page_handle_t *page,\r
-                                   kv_page_status_t *page_status);\r
-errcode_t kv_store_read_backup_key(kv_key_id key_id, kv_store_key_data_t *key_data, kv_attributes_t *attributes);\r
-\r
-#ifdef __cplusplus\r
-#if __cplusplus\r
-}\r
-#endif /* __cplusplus */\r
-#endif /* __cplusplus */\r
-\r
-#endif /* NV_STORE_H_ */\r
+/*
+ * Copyright (c) @CompanyNameMagicTag 2019-2022. All rights reserved.
+ * Description: KV Storage Library store access interface
+ */
+
+#ifndef NV_STORE_H
+#define NV_STORE_H
+
+#include "nv_page.h"
+#include "platform_types.h"
+#include "nv.h"
+#include "errcode.h"
+
+#ifdef __cplusplus
+#if __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+/** Store ids for each core, with a minimum hamming distance of 10 between each value */
+#define KV_STORE_ID_SCPU    0xCB7E
+#define KV_STORE_ID_ACPU    0x254D
+#define KV_STORE_ID_BACKUP  0x34B2
+
+typedef enum {
+    KV_STORE_APPLICATION,
+    KV_STORE_MAX_NUM,
+} kv_store_t;
+
+typedef struct {
+    uint16_t kvalue_max_length;
+    uint16_t kvalue_actual_length;
+    uint8_t *kvalue;
+} kv_store_key_data_t;
+
+cores_t kv_store_to_core(kv_store_t store);
+kv_store_t kv_store_from_core(cores_t core);
+uint16_t kv_store_get_id(kv_store_t store);
+uint8_t kv_store_get_page_count(kv_store_t store);
+errcode_t kv_store_get_page_handle(kv_store_t store, uint32_t page_index, kv_page_handle_t *page);
+errcode_t kv_store_find_valid_key(kv_store_t store, kv_key_id key_id, kv_key_handle_t *key);
+errcode_t kv_store_get_backup_key(kv_key_id key_id, kv_store_key_data_t *key_data, kv_attributes_t *attributes,
+    kv_page_location page_location);
+errcode_t kv_store_get_key_attr(kv_store_t store, kv_key_id key_id, uint16_t *len, kv_attributes_t *attributes);
+errcode_t kv_store_get_key(kv_store_t store, kv_key_id key_id, kv_store_key_data_t *key_data,
+                           kv_attributes_t *attributes);
+errcode_t kv_store_get_status(kv_store_t store, nv_store_status_t *store_status);
+errcode_t kv_store_find_write_page(kv_store_t store, uint32_t required_space, kv_page_handle_t *page,
+                                   kv_page_status_t *page_status);
+errcode_t kv_store_read_backup_key(kv_key_id key_id, kv_store_key_data_t *key_data, kv_attributes_t *attributes);
+
+#ifdef __cplusplus
+#if __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+#endif /* NV_STORE_H_ */
index dd860bc..3b7365a 100755 (executable)
-/*\r
- * Copyright (c) @CompanyNameMagicTag 2021-2022. All rights reserved.\r
- * Description: FLASH task shared definitions between the SCPU and A/PCPU.\r
- */\r
-\r
-#ifndef FLASH_TASK_ETYPES_H\r
-#define FLASH_TASK_ETYPES_H\r
-\r
-#include "stdbool.h"\r
-#include "errcode.h"\r
-\r
-#ifdef __cplusplus\r
-#if __cplusplus\r
-extern "C" {\r
-#endif /* __cplusplus */\r
-#endif /* __cplusplus */\r
-\r
-/** Identifier to check that a section of memory is indeed a flash_task_node */\r
-#define FLASH_TASK_NODE_IDENTIFIER        0xd3a71f85\r
-\r
-/* Normal values of the flash_task_node.result field; anything else is an error being reported - must remain in sync\r
- * with the SCPU soc_errno.  The A/PCPU can use these defines in case they have a different set of error codes */\r
-#define FLASH_TASK_DISCARD                0x80002040\r
-#define FLASH_TASK_DISCARDED              0x80002041\r
-#define FLASH_TASK_READY                  0x80002042\r
-#define FLASH_TASK_BEING_PROCESSED        0x80002043\r
-#define FLASH_TASK_COMPLETED              0x80003130\r
-\r
-#define FLASH_TASK_ERASE_ALL_MAGIC_VALUE_LEN    10\r
-\r
-typedef enum {\r
-    /* Create KV storage in flash memory */\r
-    FLASH_TASK_KV_PAGE_INIT = 0,\r
-    /* A new or modification to an existing key-value */\r
-    FLASH_TASK_KV_DATA,\r
-    /* Modify the attribute on an existing key-value */\r
-    FLASH_TASK_KV_ATTRIBUTE,\r
-    /* Erase a key-value */\r
-    FLASH_TASK_KV_ERASE,\r
-    /* Write / overwrite some FOTA patch data in FLASH */\r
-    FLASH_TASK_FOTA_DATA,\r
-    /* Erase some FOTA patch data in FLASH and re-write the FOTA header */\r
-    FLASH_TASK_FOTA_ERASE,\r
-    /* Write some data to ACPU storage in FLASH */\r
-    FLASH_TASK_ACPU_DATA,\r
-    /* Erase some ACPU storage in FLASH */\r
-    FLASH_TASK_ACPU_ERASE,\r
-    /* Number of task types */\r
-    FLASH_TASK_NUM_TYPES,\r
-} flash_task_type_t;\r
-\r
-\r
-/** @brief  Key type */\r
-typedef uint16_t kv_storage_key;\r
-\r
-typedef struct {\r
-    uint32_t        kv_addr;\r
-    uint32_t        kv_size;\r
-} flash_task_kv_init_t;\r
-\r
-typedef struct {\r
-    const uint8_t   *kvalue;\r
-    kv_storage_key   key;\r
-    uint16_t           kvalue_length;\r
-    uint8_t            attribute;\r
-    bool          force_write;\r
-} flash_task_kv_data_t;\r
-\r
-typedef struct {\r
-    kv_storage_key  key;\r
-    uint8_t         attribute;\r
-} flash_task_kv_attribute_t;\r
-\r
-typedef struct {\r
-    kv_storage_key  key;\r
-} flash_task_kv_erase_t;\r
-\r
-typedef struct {\r
-    kv_storage_key  key;\r
-} flash_task_kv_backup_t;\r
-\r
-typedef struct {\r
-    /* Used to ensure erase all is not called by mistake. */\r
-    uint8_t   magic_value[FLASH_TASK_ERASE_ALL_MAGIC_VALUE_LEN];\r
-} kv_erase_all_t;\r
-\r
-typedef struct {\r
-    uint8_t   *src; /* Mapped address in calling core memory map, can in RAM or FLASH. */\r
-    uint8_t   *dst; /* Mapped address in calling core memory map FOTA FLASH region\r
-                     * - must not include the FOTA header. */\r
-    uint16_t  length;\r
-} flash_task_flash_data_t;\r
-\r
-typedef struct {\r
-    uint32_t  start_address; /* Core mapped address in FOTA FLASH region; must be at the start of a flash page. */\r
-    uint32_t  length;        /* Must be a multiple of the page size. */\r
-} flash_task_flash_erase_t;\r
-\r
-typedef union {\r
-    flash_task_kv_init_t      kv_region;\r
-    flash_task_kv_data_t      kv;\r
-    flash_task_kv_attribute_t kv_attribute;\r
-    flash_task_kv_erase_t     kv_erase;\r
-    flash_task_flash_data_t   flash;\r
-    flash_task_flash_erase_t  flash_erase;\r
-} task_node_data_t;\r
-\r
-typedef struct owner_callback_data_t owner_callback;\r
-\r
-/**\r
- * @brief  Flash task local callback from the flash_task_process_completed_task(...) function.\r
- *\r
- * @param result    is the result of the flash task execution on the SCPU.\r
- * @param callback  is the callback struct containing any information that was prepared for use during the callback.\r
- * @return          soc_errno value SOC_ERR_SUCCESS or another error code indicating that the callback has failed; this\r
- *                  will be returned by the flash_task_process_completed_task(...) function. */\r
-typedef errcode_t (*flash_task_completed_callback)(errcode_t result, owner_callback *callback);\r
-\r
-struct owner_callback_data_t {\r
-    /** Callback function to call if not EXT_NULL. */\r
-    flash_task_completed_callback  func;\r
-    /* Include any owner data to be available to the callback function upon execution. */\r
-};\r
-\r
-typedef struct flash_task_description_t flash_task_node;\r
-struct flash_task_description_t {\r
-    /** A flash_task identifier to maximise the chance that a bug is detected quickly. */\r
-    uint32_t                               identifier;\r
-    /** Next task in the queue or EXT_NULL if nothing. */\r
-    volatile flash_task_node              *next;\r
-    /** FOR THE TASK PRODUCER: This is private to the core that owns the cache and will not be examined by the SCPU task\r
-     * handlers.  It will nominally be used by the owning core as the call-back it should call when it discovers that\r
-     * this task has been completed combined with a pointer to a struct with any state information.\r
-     *\r
-     * NB: IN THE SCPU FLASH TASK HANDLER DURING EXECUTION ONLY: this will be nulled out in the copy initially provided\r
-     * to the SCPU task handler and can be used to store task state while the task is in progress, even if the task\r
-     * must be temporarily suspended due to an A/PCPU wake-up. */\r
-    owner_callback                         *owner_callback;\r
-    /** The state_code is a soc_errno and is used as a lock so is volatile so that it can be read/written from each core\r
-     * properly.\r
-     *   FLASH_TASK_DISCARD         - Set by the owning core so that the SCPU will stop checking this memory\r
-     *                                      (and will acknowledge this by setting this to DISCARDED).\r
-     *   FLASH_TASK_DISCARDED       - Set by the SCPU to acknowledge that this task has not been processed and\r
-     *                                      was discarded by request of the owning core.\r
-     *                                      (the SCPU is no longer examining this memory which can be modified/freed).\r
-     *   FLASH_TASK_READY           - Set by the owning core so that the SCPU will process this task\r
-     *                                      (and will update it when finished) so the owning core cannot change\r
-     *                                      anything other than the owner_callback once this has been set.\r
-     *   FLASH_TASK_BEING_PROCESSED - Set by the SCPU to indicate that this task is being processed;\r
-     *                                      this may take some time if the SCPU has to wait for other cores to sleep.\r
-     *                                      The owning core must not change anything other than the owner_callback.\r
-     *   FLASH_TASK_COMPLETED       - Set by the SCPU to indicate that this task completed successfully\r
-     *                                      (the SCPU is no longer examining this memory which can be modified/freed).\r
-     *   any other value            - Provides an error code; contact customer support to obtain it's meaning\r
-     *                                      (the SCPU is no longer examining this memory which can be modified/freed).\r
-     */\r
-    volatile uint32_t                      state_code;\r
-    /** The flash task to be performed. */\r
-    flash_task_type_t                        task;\r
-    /** The unique per task data contents. */\r
-    task_node_data_t                         data;\r
-    /** A checksum formed by xoring the flash write task information (task and data) and is used to spot errors. */\r
-    uint32_t                               checksum;\r
-};\r
-\r
-#ifdef __cplusplus\r
-#if __cplusplus\r
-}\r
-#endif /* __cplusplus */\r
-#endif /* __cplusplus */\r
-\r
-#endif /* _EXTERNAL_ETYPES_5GNBRBIV100_SHARED_FLASH_TASK_ETYPES_H */\r
-\r
+/*
+ * Copyright (c) @CompanyNameMagicTag 2021-2022. All rights reserved.
+ * Description: FLASH task shared definitions between the SCPU and A/PCPU.
+ */
+
+#ifndef FLASH_TASK_ETYPES_H
+#define FLASH_TASK_ETYPES_H
+
+#include "stdbool.h"
+#include "errcode.h"
+
+#ifdef __cplusplus
+#if __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+/** Identifier to check that a section of memory is indeed a flash_task_node */
+#define FLASH_TASK_NODE_IDENTIFIER        0xd3a71f85
+
+/* Normal values of the flash_task_node.result field; anything else is an error being reported - must remain in sync
+ * with the SCPU soc_errno.  The A/PCPU can use these defines in case they have a different set of error codes */
+#define FLASH_TASK_DISCARD                0x80002040
+#define FLASH_TASK_DISCARDED              0x80002041
+#define FLASH_TASK_READY                  0x80002042
+#define FLASH_TASK_BEING_PROCESSED        0x80002043
+#define FLASH_TASK_COMPLETED              0x80003130
+
+#define FLASH_TASK_ERASE_ALL_MAGIC_VALUE_LEN    10
+
+typedef enum {
+    /* Create KV storage in flash memory */
+    FLASH_TASK_KV_PAGE_INIT = 0,
+    /* A new or modification to an existing key-value */
+    FLASH_TASK_KV_DATA,
+    /* Modify the attribute on an existing key-value */
+    FLASH_TASK_KV_ATTRIBUTE,
+    /* Erase a key-value */
+    FLASH_TASK_KV_ERASE,
+    /* Write / overwrite some FOTA patch data in FLASH */
+    FLASH_TASK_FOTA_DATA,
+    /* Erase some FOTA patch data in FLASH and re-write the FOTA header */
+    FLASH_TASK_FOTA_ERASE,
+    /* Write some data to ACPU storage in FLASH */
+    FLASH_TASK_ACPU_DATA,
+    /* Erase some ACPU storage in FLASH */
+    FLASH_TASK_ACPU_ERASE,
+    /* Number of task types */
+    FLASH_TASK_NUM_TYPES,
+} flash_task_type_t;
+
+
+/** @brief  Key type */
+typedef uint16_t kv_storage_key;
+
+typedef struct {
+    uint32_t        kv_addr;
+    uint32_t        kv_size;
+} flash_task_kv_init_t;
+
+typedef struct {
+    const uint8_t   *kvalue;
+    kv_storage_key   key;
+    uint16_t           kvalue_length;
+    uint8_t            attribute;
+    bool          force_write;
+} flash_task_kv_data_t;
+
+typedef struct {
+    kv_storage_key  key;
+    uint8_t         attribute;
+} flash_task_kv_attribute_t;
+
+typedef struct {
+    kv_storage_key  key;
+} flash_task_kv_erase_t;
+
+typedef struct {
+    kv_storage_key  key;
+} flash_task_kv_backup_t;
+
+typedef struct {
+    /* Used to ensure erase all is not called by mistake. */
+    uint8_t   magic_value[FLASH_TASK_ERASE_ALL_MAGIC_VALUE_LEN];
+} kv_erase_all_t;
+
+typedef struct {
+    uint8_t   *src; /* Mapped address in calling core memory map, can in RAM or FLASH. */
+    uint8_t   *dst; /* Mapped address in calling core memory map FOTA FLASH region
+                     * - must not include the FOTA header. */
+    uint16_t  length;
+} flash_task_flash_data_t;
+
+typedef struct {
+    uint32_t  start_address; /* Core mapped address in FOTA FLASH region; must be at the start of a flash page. */
+    uint32_t  length;        /* Must be a multiple of the page size. */
+} flash_task_flash_erase_t;
+
+typedef union {
+    flash_task_kv_init_t      kv_region;
+    flash_task_kv_data_t      kv;
+    flash_task_kv_attribute_t kv_attribute;
+    flash_task_kv_erase_t     kv_erase;
+    flash_task_flash_data_t   flash;
+    flash_task_flash_erase_t  flash_erase;
+} task_node_data_t;
+
+typedef struct owner_callback_data_t owner_callback;
+
+/**
+ * @brief  Flash task local callback from the flash_task_process_completed_task(...) function.
+ *
+ * @param result    is the result of the flash task execution on the SCPU.
+ * @param callback  is the callback struct containing any information that was prepared for use during the callback.
+ * @return          soc_errno value SOC_ERR_SUCCESS or another error code indicating that the callback has failed; this
+ *                  will be returned by the flash_task_process_completed_task(...) function. */
+typedef errcode_t (*flash_task_completed_callback)(errcode_t result, owner_callback *callback);
+
+struct owner_callback_data_t {
+    /** Callback function to call if not EXT_NULL. */
+    flash_task_completed_callback  func;
+    /* Include any owner data to be available to the callback function upon execution. */
+};
+
+typedef struct flash_task_description_t flash_task_node;
+struct flash_task_description_t {
+    /** A flash_task identifier to maximise the chance that a bug is detected quickly. */
+    uint32_t                               identifier;
+    /** Next task in the queue or EXT_NULL if nothing. */
+    volatile flash_task_node              *next;
+    /** FOR THE TASK PRODUCER: This is private to the core that owns the cache and will not be examined by the SCPU task
+     * handlers.  It will nominally be used by the owning core as the call-back it should call when it discovers that
+     * this task has been completed combined with a pointer to a struct with any state information.
+     *
+     * NB: IN THE SCPU FLASH TASK HANDLER DURING EXECUTION ONLY: this will be nulled out in the copy initially provided
+     * to the SCPU task handler and can be used to store task state while the task is in progress, even if the task
+     * must be temporarily suspended due to an A/PCPU wake-up. */
+    owner_callback                         *owner_callback;
+    /** The state_code is a soc_errno and is used as a lock so is volatile so that it can be read/written from each core
+     * properly.
+     *   FLASH_TASK_DISCARD         - Set by the owning core so that the SCPU will stop checking this memory
+     *                                      (and will acknowledge this by setting this to DISCARDED).
+     *   FLASH_TASK_DISCARDED       - Set by the SCPU to acknowledge that this task has not been processed and
+     *                                      was discarded by request of the owning core.
+     *                                      (the SCPU is no longer examining this memory which can be modified/freed).
+     *   FLASH_TASK_READY           - Set by the owning core so that the SCPU will process this task
+     *                                      (and will update it when finished) so the owning core cannot change
+     *                                      anything other than the owner_callback once this has been set.
+     *   FLASH_TASK_BEING_PROCESSED - Set by the SCPU to indicate that this task is being processed;
+     *                                      this may take some time if the SCPU has to wait for other cores to sleep.
+     *                                      The owning core must not change anything other than the owner_callback.
+     *   FLASH_TASK_COMPLETED       - Set by the SCPU to indicate that this task completed successfully
+     *                                      (the SCPU is no longer examining this memory which can be modified/freed).
+     *   any other value            - Provides an error code; contact customer support to obtain it's meaning
+     *                                      (the SCPU is no longer examining this memory which can be modified/freed).
+     */
+    volatile uint32_t                      state_code;
+    /** The flash task to be performed. */
+    flash_task_type_t                        task;
+    /** The unique per task data contents. */
+    task_node_data_t                         data;
+    /** A checksum formed by xoring the flash write task information (task and data) and is used to spot errors. */
+    uint32_t                               checksum;
+};
+
+#ifdef __cplusplus
+#if __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+#endif /* _EXTERNAL_ETYPES_5GNBRBIV100_SHARED_FLASH_TASK_ETYPES_H */
+
index d7d92fe..f38bae2 100755 (executable)
-/*\r
- * Copyright (c) @CompanyNameMagicTag 2019-2022. All rights reserved.\r
- * Description: KV Storage Library flash updating module implementation\r
- */\r
-\r
-#include "nv_update.h"\r
-#include "nv_store.h"\r
-#include "nv_page.h"\r
-#include "nv_key.h"\r
-#include "nv_porting.h"\r
-#include "nv_config.h"\r
-#include "nv_reset.h"\r
-#include "nv_nvregion.h"\r
-#if defined(CONFIG_PARTITION_FEATURE_SUPPORT)\r
-#include "partition.h"\r
-#endif\r
-#include "assert.h"\r
-#include "common_def.h"\r
-#include "uapi_crc.h"\r
-#ifndef CONFIG_NV_SUPPORT_SINGLE_CORE_SYSTEM\r
-#include "flash_task_mutex.h"\r
-#include "flash_task_adapt.h"\r
-#endif\r
-\r
-#define KV_WRITE_KEY_BUFFER_SIZE    NV_KEY_DATA_CHUNK_LEN\r
-#define KV_WRITE_CHUNK_SIZE         32\r
-\r
-#define assert__(x)        ((void)0)\r
-\r
-/* Pointer to current state machine being processed.\r
- * Will point to the last instance in a list of kv_active_state_machine_t, or NULL if\r
- * no state machine is being processed */\r
-STATIC kv_active_state_machine_t *g_current_state_machine = NULL;\r
-\r
-/* Holds a search filter being used by searching operations performed by state machines */\r
-STATIC kv_key_filter_t g_search_filter;\r
-\r
-/* Holds details of key data to be written to a store */\r
-STATIC kv_key_details_t g_new_key_details;\r
-\r
-/* The key within a KV store begin accessed by a state machine */\r
-STATIC kv_key_handle_t g_current_key;\r
-\r
-/* The flash page within a KV store begin accessed by a state machine */\r
-STATIC kv_page_handle_t g_current_page;\r
-\r
-/* The KV store begin accessed by a state machine */\r
-STATIC kv_store_t g_current_store;\r
-\r
-/* The position in a flash page where a new key will be written */\r
-STATIC kv_key_location g_current_store_write_location;\r
-\r
-/* Memory address of flash page being used to defrag an existing page into */\r
-STATIC kv_page_location g_defrag_page_location = NULL;\r
-\r
-\r
-STATIC errcode_t kv_create_write_buffer(uint32_t write_location, uint32_t size);\r
-STATIC void kv_remove_write_buffer(void);\r
-STATIC kv_managed_source_buffer_t* kv_update_source_buffer(uint8_t *data, uint32_t data_length);\r
-STATIC void kv_remove_source_buffer(void);\r
-STATIC void kv_release_crypto(void);\r
-STATIC errcode_t begin_state_machine(const kv_state_machine_t *machine);\r
-STATIC void end_state_machine(void);\r
-\r
-/* State machine action functions */\r
-STATIC kv_update_event_t kv_update_action_store_write_buffer(void);\r
-STATIC kv_update_event_t kv_update_action_prime_write_buffer(void);\r
-\r
-STATIC kv_update_event_t kv_update_action_select_first_page(void);\r
-STATIC kv_update_event_t kv_update_action_select_next_page(void);\r
-STATIC kv_update_event_t kv_update_action_find_first_key(void);\r
-STATIC kv_update_event_t kv_update_action_find_next_key(void);\r
-STATIC kv_update_event_t kv_update_action_prepare_delete_key(void);\r
-\r
-STATIC kv_update_event_t kv_update_action_find_defrag_page(void);\r
-STATIC kv_update_event_t kv_update_action_erase_defrag_page(void);\r
-STATIC kv_update_event_t kv_update_action_prepare_copy_key(void);\r
-\r
-STATIC kv_update_event_t kv_update_action_prepare_defrag_page(void);\r
-STATIC kv_update_event_t kv_update_action_copy_all_keys(void);\r
-STATIC kv_update_event_t kv_update_action_prepare_page_header(void);\r
-STATIC kv_update_event_t kv_update_action_find_write_position(void);\r
-STATIC kv_update_event_t kv_update_action_defrag_current_page(void);\r
-STATIC kv_update_event_t kv_update_action_update_nvregion_map(void);\r
-\r
-STATIC kv_update_event_t kv_update_action_prepare_store(void);\r
-STATIC kv_update_event_t kv_update_action_prepare_write_key(void);\r
-STATIC kv_update_event_t kv_update_action_claim_crypto(void);\r
-STATIC kv_update_event_t kv_update_action_erase_old_keys(void);\r
-\r
-STATIC kv_update_event_t kv_update_action_update_nvmap_for_erase_key(void);\r
-STATIC kv_update_event_t kv_update_action_update_nvmap_for_new_key(void);\r
-\r
-\r
-/* State machine to iterate through keys in a store marking all keys as erased\r
- * - Uses a pre-configured filter to determine which keys to select for erasing\r
- */\r
-static const kv_update_transition_t g_erase_keys_transitions[] = {\r
-    {.state = STATE_SELECT_FIRST_PAGE,  .event = EVENT_PAGE_SELECTED,       .next_state = STATE_FIND_FIRST_KEY  },\r
-    {.state = STATE_SELECT_FIRST_PAGE,  .event = EVENT_PAGE_NOT_SELECTED,   .next_state = STATE_EXIT            },\r
-    {.state = STATE_SELECT_NEXT_PAGE,   .event = EVENT_PAGE_SELECTED,       .next_state = STATE_FIND_FIRST_KEY  },\r
-    {.state = STATE_SELECT_NEXT_PAGE,   .event = EVENT_PAGE_NOT_SELECTED,   .next_state = STATE_EXIT            },\r
-    {.state = STATE_FIND_FIRST_KEY,     .event = EVENT_KEY_FOUND,           .next_state = STATE_PREP_DELETE_KEY },\r
-    {.state = STATE_FIND_FIRST_KEY,     .event = EVENT_KEY_NOT_FOUND,       .next_state = STATE_SELECT_NEXT_PAGE},\r
-    {.state = STATE_FIND_NEXT_KEY,      .event = EVENT_KEY_FOUND,           .next_state = STATE_PREP_DELETE_KEY },\r
-    {.state = STATE_FIND_NEXT_KEY,      .event = EVENT_KEY_NOT_FOUND,       .next_state = STATE_SELECT_NEXT_PAGE},\r
-    {.state = STATE_PREP_DELETE_KEY,    .event = EVENT_WRITE_BUFFER_PRIMED, .next_state = STATE_PERFORM_WRITE   },\r
-    {.state = STATE_PERFORM_WRITE,      .event = EVENT_WRITE_BUFFER_STORED, .next_state = STATE_UPDATE_MAP_FOR_OLD },\r
-    {.state = STATE_UPDATE_MAP_FOR_OLD, .event = EVENT_PAGE_MAP_UPDATED,    .next_state = STATE_FIND_NEXT_KEY   },\r
-    {.state = STATE_PERFORM_WRITE,      .event = EVENT_SUSPEND,             .next_state = STATE_SUSPENDED       },\r
-    {.state = STATE_EXIT,               .event = EVENT_NONE,                .next_state = STATE_EXIT            }\r
-};\r
-static const kv_update_action_t g_erase_keys_actions[] = {\r
-    {.state = STATE_SELECT_FIRST_PAGE,  .action = kv_update_action_select_first_page },\r
-    {.state = STATE_SELECT_NEXT_PAGE,   .action = kv_update_action_select_next_page  },\r
-    {.state = STATE_FIND_FIRST_KEY,     .action = kv_update_action_find_first_key    },\r
-    {.state = STATE_FIND_NEXT_KEY,      .action = kv_update_action_find_next_key     },\r
-    {.state = STATE_PREP_DELETE_KEY,    .action = kv_update_action_prepare_delete_key},\r
-    {.state = STATE_PERFORM_WRITE,      .action = kv_update_action_store_write_buffer},\r
-    {.state = STATE_UPDATE_MAP_FOR_OLD, .action = kv_update_action_update_nvmap_for_erase_key},\r
-    {.state = STATE_EXIT,               .action = NULL                            }\r
-};\r
-static const kv_state_machine_t g_erase_keys_machine = {\r
-    .initial_state     = STATE_SELECT_FIRST_PAGE,\r
-    .resume_state      = STATE_PERFORM_WRITE,\r
-    .exit_event        = EVENT_KEYS_ERASED,\r
-    .transition_table  = g_erase_keys_transitions,\r
-    .action_table      = g_erase_keys_actions,\r
-    .write_buffer_size = sizeof(uint32_t)\r
-};\r
-\r
-/*\r
- * State machine to locate a defrag page\r
- * - Scans NV Region for an unused page of flash\r
- * - Sets g_defrag_page_location to point the unused flash page, thus declaring it to be the current defrag page\r
- * - Ensures defrag page is erased\r
- */\r
-static const kv_update_transition_t g_prep_defrag_page_transitions[] = {\r
-    {.state = STATE_FIND_DEFRAG,  .event = EVENT_DEFRAG_FOUND,  .next_state = STATE_ERASE_DEFRAG},\r
-    {.state = STATE_ERASE_DEFRAG, .event = EVENT_DEFRAG_ERASED, .next_state = STATE_EXIT        },\r
-    {.state = STATE_ERASE_DEFRAG, .event = EVENT_SUSPEND,       .next_state = STATE_SUSPENDED   },\r
-    {.state = STATE_EXIT,         .event = EVENT_NONE,          .next_state = STATE_EXIT        }\r
-};\r
-static const kv_update_action_t g_prep_defrag_page_actions[] = {\r
-    {.state = STATE_FIND_DEFRAG,  .action = kv_update_action_find_defrag_page },\r
-    {.state = STATE_ERASE_DEFRAG, .action = kv_update_action_erase_defrag_page},\r
-    {.state = STATE_EXIT,         .action = NULL                           }\r
-};\r
-static const kv_state_machine_t g_prep_defrag_page_machine = {\r
-    .initial_state     = STATE_FIND_DEFRAG,\r
-    .resume_state      = STATE_ERASE_DEFRAG,\r
-    .exit_event        = EVENT_DEFRAG_PREPARED,\r
-    .transition_table  = g_prep_defrag_page_transitions,\r
-    .action_table      = g_prep_defrag_page_actions,\r
-    .write_buffer_size = 0\r
-};\r
-\r
-/*\r
- * State machine to copy keys from the current page to the defrag page.\r
- * Keys to copy are selected by a pre-configured filter, contained in g_search_filter\r
- * Current page identified by g_current_page\r
- * Defrag page identified by g_defrag_page_location\r
- */\r
-static const kv_update_transition_t g_copy_all_keys_transitions[] = {\r
-    {.state = STATE_FIND_FIRST_KEY, .event = EVENT_KEY_FOUND,            .next_state = STATE_PREP_COPY_KEY  },\r
-    {.state = STATE_FIND_FIRST_KEY, .event = EVENT_KEY_NOT_FOUND,        .next_state = STATE_EXIT           },\r
-    {.state = STATE_FIND_NEXT_KEY,  .event = EVENT_KEY_FOUND,            .next_state = STATE_PREP_COPY_KEY  },\r
-    {.state = STATE_FIND_NEXT_KEY,  .event = EVENT_KEY_NOT_FOUND,        .next_state = STATE_EXIT           },\r
-    {.state = STATE_PREP_COPY_KEY,  .event = EVENT_COPY_KEY_READY,       .next_state = STATE_PRIME_WRITE    },\r
-    {.state = STATE_PRIME_WRITE,    .event = EVENT_WRITE_BUFFER_PRIMED,  .next_state = STATE_PERFORM_WRITE  },\r
-    {.state = STATE_PRIME_WRITE,    .event = EVENT_WRITE_DATA_EXHAUSTED, .next_state = STATE_FIND_NEXT_KEY  },\r
-    {.state = STATE_PERFORM_WRITE,  .event = EVENT_WRITE_BUFFER_STORED,  .next_state = STATE_PRIME_WRITE    },\r
-    {.state = STATE_PERFORM_WRITE,  .event = EVENT_SUSPEND,              .next_state = STATE_SUSPENDED      },\r
-    {.state = STATE_EXIT,           .event = EVENT_NONE,                 .next_state = STATE_EXIT           }\r
-};\r
-static const kv_update_action_t g_copy_all_keys_actions[] = {\r
-    {.state = STATE_FIND_FIRST_KEY, .action = kv_update_action_find_first_key    },\r
-    {.state = STATE_FIND_NEXT_KEY,  .action = kv_update_action_find_next_key     },\r
-    {.state = STATE_PREP_COPY_KEY,  .action = kv_update_action_prepare_copy_key  },\r
-    {.state = STATE_PRIME_WRITE,    .action = kv_update_action_prime_write_buffer},\r
-    {.state = STATE_PERFORM_WRITE,  .action = kv_update_action_store_write_buffer},\r
-    {.state = STATE_EXIT,           .action = NULL                            }\r
-};\r
-static const kv_state_machine_t g_copy_all_keys_machine = {\r
-    .initial_state     = STATE_FIND_FIRST_KEY,\r
-    .resume_state      = STATE_PERFORM_WRITE,\r
-    .exit_event        = EVENT_ALL_KEYS_COPIED,\r
-    .transition_table  = g_copy_all_keys_transitions,\r
-    .action_table      = g_copy_all_keys_actions,\r
-    .write_buffer_size = KV_WRITE_KEY_BUFFER_SIZE\r
-};\r
-\r
-/*\r
- * State machine to defrag a store page\r
- * Makes use of the g_prep_defrag_page_machine state machine\r
- * Makes use of the g_copy_all_keys_machine state machine\r
- * - Locates an unused flash page in the NV Region and erased it\r
- * - Copies valid keys from page being defragged to the new page\r
- * - Writes an updated page header to top of the new page, so that it supercedes the recently defragged page\r
- */\r
-static const kv_update_transition_t g_defrag_page_transitions[] = {\r
-    {.state = STATE_PREP_DEFRAG,         .event = EVENT_DEFRAG_PREPARED,      .next_state = STATE_COPY_ALL_KEYS      },\r
-    {.state = STATE_COPY_ALL_KEYS,       .event = EVENT_ALL_KEYS_COPIED,      .next_state = STATE_PREP_PAGE_HEADER   },\r
-    {.state = STATE_PREP_PAGE_HEADER,    .event = EVENT_WRITE_BUFFER_PRIMED,  .next_state = STATE_WRITE_PAGE_HEADER  },\r
-    {.state = STATE_WRITE_PAGE_HEADER,   .event = EVENT_WRITE_BUFFER_STORED,  .next_state = STATE_UPDATE_NVREGION_MAP},\r
-    {.state = STATE_WRITE_PAGE_HEADER,   .event = EVENT_SUSPEND,              .next_state = STATE_SUSPENDED          },\r
-    {.state = STATE_UPDATE_NVREGION_MAP, .event = EVENT_NVREGION_MAP_UPDATED, .next_state = STATE_EXIT               },\r
-    {.state = STATE_EXIT,                .event = EVENT_NONE,                 .next_state = STATE_EXIT               }\r
-};\r
-static const kv_update_action_t g_defrag_page_actions[] = {\r
-    {.state = STATE_PREP_DEFRAG,         .action = kv_update_action_prepare_defrag_page},\r
-    {.state = STATE_COPY_ALL_KEYS,       .action = kv_update_action_copy_all_keys      },\r
-    {.state = STATE_PREP_PAGE_HEADER,    .action = kv_update_action_prepare_page_header},\r
-    {.state = STATE_WRITE_PAGE_HEADER,   .action = kv_update_action_store_write_buffer },\r
-    {.state = STATE_UPDATE_NVREGION_MAP, .action = kv_update_action_update_nvregion_map},\r
-    {.state = STATE_EXIT,                .action = NULL                             }\r
-};\r
-static const kv_state_machine_t g_defrag_page_machine = {\r
-    .initial_state     = STATE_PREP_DEFRAG,\r
-    .resume_state      = STATE_WRITE_PAGE_HEADER,\r
-    .exit_event        = EVENT_DEFRAG_COMPLETE,\r
-    .transition_table  = g_defrag_page_transitions,\r
-    .action_table      = g_defrag_page_actions,\r
-    .write_buffer_size = sizeof(kv_page_header_t)\r
-};\r
-\r
-/*\r
- * State machine to prepare a store for writing a key\r
- * May make use of the g_defrag_page_machine state machine\r
- * - Selects a suitable page in a store for receiving a key\r
- * - Kicks off a defrag of the selected page if necessary\r
- */\r
-static const kv_update_transition_t g_prepare_store_transitions[] = {\r
-    {.state = STATE_FIND_WRITE_POS, .event = EVENT_DEFRAG_REQUIRED, .next_state = STATE_DEFRAG_PAGE   },\r
-    {.state = STATE_FIND_WRITE_POS, .event = EVENT_WRITE_POS_FOUND, .next_state = STATE_EXIT          },\r
-    {.state = STATE_DEFRAG_PAGE,    .event = EVENT_DEFRAG_COMPLETE, .next_state = STATE_FIND_WRITE_POS},\r
-    {.state = STATE_EXIT,           .event = EVENT_NONE,            .next_state = STATE_EXIT          }\r
-};\r
-static const kv_update_action_t g_prepare_store_actions[] = {\r
-    {.state = STATE_FIND_WRITE_POS, .action = kv_update_action_find_write_position},\r
-    {.state = STATE_DEFRAG_PAGE,    .action = kv_update_action_defrag_current_page},\r
-    {.state = STATE_EXIT,           .action = NULL                             }\r
-};\r
-STATIC const kv_state_machine_t g_prepare_store_machine = {\r
-    .initial_state     = STATE_FIND_WRITE_POS,\r
-    .resume_state      = STATE_INVALID,\r
-    .exit_event        = EVENT_STORE_READY,\r
-    .transition_table  = g_prepare_store_transitions,\r
-    .action_table      = g_prepare_store_actions,\r
-    .write_buffer_size = 0\r
-};\r
-\r
-/*\r
- * State machine to write a key to a store\r
- * Makes use of the g_prepare_store_machine state machine\r
- */\r
-static const kv_update_transition_t g_write_key_transitions[] = {\r
-    {.state = STATE_PREP_STORE,         .event = EVENT_STORE_READY,           .next_state = STATE_PREP_KEY_DATA     },\r
-    {.state = STATE_PREP_KEY_DATA,      .event = EVENT_KEY_UPDATE_NOT_NEEDED, .next_state = STATE_EXIT              },\r
-    {.state = STATE_PREP_KEY_DATA,      .event = EVENT_KEY_DATA_READY,        .next_state = STATE_CLAIM_CRYPTO      },\r
-    {.state = STATE_CLAIM_CRYPTO,       .event = EVENT_CRYPTO_CLAIMED,        .next_state = STATE_PRIME_WRITE       },\r
-    {.state = STATE_PRIME_WRITE,        .event = EVENT_WRITE_BUFFER_PRIMED,   .next_state = STATE_PERFORM_WRITE     },\r
-    {.state = STATE_PRIME_WRITE,        .event = EVENT_WRITE_DATA_EXHAUSTED,  .next_state = STATE_UPDATE_MAP_FOR_NEW},\r
-    {.state = STATE_UPDATE_MAP_FOR_NEW, .event = EVENT_PAGE_MAP_UPDATED,      .next_state = STATE_ERASE_OLD_KEYS    },\r
-    {.state = STATE_PERFORM_WRITE,      .event = EVENT_WRITE_BUFFER_STORED,   .next_state = STATE_PRIME_WRITE       },\r
-    {.state = STATE_PERFORM_WRITE,      .event = EVENT_SUSPEND,               .next_state = STATE_SUSPENDED         },\r
-    {.state = STATE_ERASE_OLD_KEYS,     .event = EVENT_KEYS_ERASED,           .next_state = STATE_EXIT              },\r
-    {.state = STATE_EXIT,               .event = EVENT_NONE,                  .next_state = STATE_EXIT              }\r
-};\r
-static const kv_update_action_t g_write_key_actions[] = {\r
-    {.state = STATE_PREP_STORE,         .action = kv_update_action_prepare_store     },\r
-    {.state = STATE_PREP_KEY_DATA,      .action = kv_update_action_prepare_write_key },\r
-    {.state = STATE_CLAIM_CRYPTO,       .action = kv_update_action_claim_crypto      },\r
-    {.state = STATE_PRIME_WRITE,        .action = kv_update_action_prime_write_buffer},\r
-    {.state = STATE_PERFORM_WRITE,      .action = kv_update_action_store_write_buffer},\r
-    {.state = STATE_UPDATE_MAP_FOR_NEW, .action = kv_update_action_update_nvmap_for_new_key},\r
-    {.state = STATE_ERASE_OLD_KEYS,     .action = kv_update_action_erase_old_keys    },\r
-    {.state = STATE_EXIT,               .action = NULL                            }\r
-};\r
-static const kv_state_machine_t g_write_key_machine = {\r
-    .initial_state     = STATE_PREP_STORE,\r
-    .resume_state      = STATE_CLAIM_CRYPTO,\r
-    .exit_event        = EVENT_WRITE_COMPLETE,\r
-    .transition_table  = g_write_key_transitions,\r
-    .action_table      = g_write_key_actions,\r
-    .write_buffer_size = KV_WRITE_KEY_BUFFER_SIZE\r
-};\r
-\r
-/* Attempts to write all data in a write buffer to flash */\r
-STATIC kv_update_event_t kv_update_action_store_write_buffer(void)\r
-{\r
-    errcode_t ret;\r
-    uint32_t read_location;\r
-    uint32_t write_length;\r
-    uint32_t written;\r
-\r
-    kv_managed_write_buffer_t *write_buffer = g_current_state_machine->write_buffer;\r
-\r
-    /* Skip over section of write buffer that has already been written, due to being suspended */\r
-    if (write_buffer->write_location < write_buffer->resume_location) {\r
-        uint32_t data_already_written = write_buffer->resume_location - write_buffer->write_location;\r
-        if (data_already_written > write_buffer->data_length) {\r
-            data_already_written = write_buffer->data_length;\r
-        }\r
-        write_buffer->data_consumed += (uint16_t)data_already_written;\r
-        write_buffer->write_location += data_already_written;\r
-    }\r
-\r
-    /* Attempt to write chunks of data from the write_buffer to flash */\r
-    while (write_buffer->data_consumed < write_buffer->data_length) {\r
-        /* Determine size and position of chunk to write */\r
-        read_location = (uint32_t)(uintptr_t)write_buffer->data + write_buffer->data_consumed;\r
-        write_length = uapi_min(KV_WRITE_CHUNK_SIZE, write_buffer->data_length - write_buffer->data_consumed);\r
-\r
-        /* Attempt to write chunk */\r
-        ret = kv_key_write_flash(write_buffer->write_location, write_length, (uint8_t *)(uintptr_t)read_location);\r
-        if (ret == ERRCODE_SUCC) {\r
-            written = write_length;\r
-        } else {\r
-            written = 0;\r
-        }\r
-        write_buffer->data_consumed += (uint16_t)written;\r
-        /* Update write position, automatically allowing for subsequent writes to occur sequentially in flash */\r
-        write_buffer->write_location += written;\r
-        if (written < write_length) {\r
-            /* Write was aborted early */\r
-            write_buffer->resume_location = write_buffer->write_location;\r
-            return EVENT_SUSPEND;\r
-        }\r
-    }\r
-    /* Write completed */\r
-    return EVENT_WRITE_BUFFER_STORED;\r
-}\r
-STATIC errcode_t kv_update_hash_encrypt_chunk(kv_managed_write_buffer_t *write_buffer,\r
-    const kv_managed_source_buffer_t *source_buffer, uint32_t chunk_dest, uint32_t chunk_len)\r
-{\r
-    /* Need to cal CRC? */\r
-    errcode_t ret = ERRCODE_SUCC;\r
-    if (source_buffer->crc_data) {\r
-        if (!write_buffer->crc_claimed) {\r
-            return ERRCODE_NV_HASH_UNAVAILABLE;\r
-        }\r
-        write_buffer->crc_ret = uapi_crc32(write_buffer->crc_ret, (const uint8_t *)(uintptr_t)chunk_dest,\r
-                                           chunk_len);\r
-    }\r
-\r
-#if (CONFIG_NV_SUPPORT_ENCRYPT == NV_YES)\r
-    /* Need to hash data? */\r
-    if (source_buffer->hash_data) {\r
-        if (!write_buffer->hash_claimed) {\r
-            return ERRCODE_NV_HASH_UNAVAILABLE;\r
-        }\r
-        nv_crypto_update_hash((const uint8_t *)(uintptr_t)chunk_dest, chunk_len);\r
-    }\r
-\r
-    /* Need to encrypt data? */\r
-    if (source_buffer->encrypt_data) {\r
-        if (!write_buffer->encrypt_claimed) {\r
-            return ERRCODE_NV_AES_UNAVAILABLE;\r
-        }\r
-\r
-        ret = nv_crypto_encode(write_buffer->crypto_handle, (uintptr_t)chunk_dest, (uintptr_t)chunk_dest, chunk_len);\r
-    }\r
-\r
-    if (source_buffer->gcm_tag_data || source_buffer->hash_data) {\r
-        if ((source_buffer->gcm_tag_data && !write_buffer->gcm_tag_claimed) ||\r
-            (source_buffer->hash_data && !write_buffer->hash_claimed)) {\r
-            return ERRCODE_NV_HASH_UNAVAILABLE;\r
-        }\r
-        write_buffer->crc_ret = uapi_crc32(write_buffer->crc_ret, (const uint8_t *)(uintptr_t)chunk_dest,\r
-                                           chunk_len);\r
-    }\r
-#endif\r
-    return ret;\r
-}\r
-\r
-/* Copy data from the selected source buffer to the write_buffer, hashing and encrypting the data as necessary */\r
-STATIC errcode_t prime_next_chunk(void)\r
-{\r
-    kv_managed_source_buffer_t *source_buffer = g_current_state_machine->current_source;\r
-    kv_managed_write_buffer_t *write_buffer = g_current_state_machine->write_buffer;\r
-\r
-    uint32_t remaining_dest_space = write_buffer->size - write_buffer->data_length;\r
-    uint32_t remaining_src_data = source_buffer->data_length - source_buffer->data_consumed;\r
-    uint16_t chunk_len = (uint16_t)uapi_min(remaining_dest_space, remaining_src_data);\r
-\r
-    uint32_t chunk_dest = (uint32_t)(uintptr_t)write_buffer->data + write_buffer->data_length;\r
-    uint32_t chunk_src = (uint32_t)(uintptr_t)source_buffer->data + source_buffer->data_consumed;\r
-\r
-    if (source_buffer->encrypt_data) {\r
-        /* For encrypted data, the length of each operation is the same as that of NV reading.\r
-         * CNCommont: 对于加密数据,每次操作的数据长度与读NV时保持一致(KEY_DATA_CHUNK_LEN),因此当write_buffer剩余空间\r
-         * 小于KEY_DATA_CHUNK_LEN时,暂不处理.\r
-         */\r
-        chunk_len = (uint16_t)uapi_min(chunk_len, NV_KEY_DATA_CHUNK_LEN);\r
-        if (remaining_dest_space < NV_KEY_DATA_CHUNK_LEN) {\r
-            return ERRCODE_NV_BUFFER_PRIMED_PREMATURELY;\r
-        }\r
-    }\r
-\r
-    kv_attributes_t attributes = (source_buffer->encrypt_data) ? KV_ATTRIBUTE_ENCRYPTED : 0;\r
-    if (remaining_dest_space < kv_key_padded_data_length(attributes, chunk_len)) {\r
-        /* Not enough space for padded data, exit early and write what we have */\r
-        return ERRCODE_NV_BUFFER_PRIMED_PREMATURELY;\r
-    }\r
-\r
-    /* Copy a chunk of source_buffer data to write buffer */\r
-    if ((chunk_src >= FLASH_PHYSICAL_ADDR_START) &&\r
-        (chunk_src + chunk_len) <= FLASH_PHYSICAL_ADDR_END) {\r
-        /* Source buffer is referencing data in Flash */\r
-        errcode_t res = kv_key_helper_copy_flash(chunk_dest, chunk_src, chunk_len);\r
-        if (res != ERRCODE_SUCC) {\r
-            return res;\r
-        }\r
-    } else {\r
-        int32_t result;\r
-        /* Source buffer is referencing data in RAM */\r
-        result = memcpy_s((void *)(uintptr_t)chunk_dest, remaining_dest_space,\r
-                          (const void *)(uintptr_t)chunk_src, chunk_len);\r
-        if (result != (int32_t)EOK) {\r
-            assert__(false);\r
-        }\r
-    }\r
-\r
-    /* Round chunk_len up to a multiple of 4 or 16 bytes, depending upon the encryption requirement */\r
-    /* We have already checked there is enough space in the write buffer                            */\r
-    chunk_len = kv_key_padded_data_length(attributes, chunk_len);\r
-\r
-    errcode_t hash_crypt_ret;\r
-    hash_crypt_ret = kv_update_hash_encrypt_chunk(write_buffer, source_buffer, chunk_dest, chunk_len);\r
-    if (hash_crypt_ret != ERRCODE_SUCC) {\r
-        return hash_crypt_ret;\r
-    }\r
-\r
-    write_buffer->data_length += chunk_len;\r
-    source_buffer->data_consumed += chunk_len;\r
-    return ERRCODE_SUCC;\r
-}\r
-\r
-/* Select next source buffer, filling it with a hash if required */\r
-STATIC errcode_t select_next_source_buffer(void)\r
-{\r
-    kv_managed_source_buffer_t *source_buffer = g_current_state_machine->current_source->next;\r
-    kv_managed_write_buffer_t *write_buffer = g_current_state_machine->write_buffer;\r
-\r
-    g_current_state_machine->current_source = source_buffer;\r
-\r
-    /* Has the next source_buffer buffer been designated to receive the hash calculation */\r
-    if ((source_buffer != NULL) && (source_buffer->receive_hash)) {\r
-        if (write_buffer->crc_claimed) {\r
-            if (source_buffer->data_length < KV_CRYPTO_CRC_SIZE) {\r
-                return ERRCODE_NV_KEY_HASH_BUFFER_TOO_SMALL;\r
-            }\r
-\r
-            write_buffer->crc_ret = kv_crc32_swap(write_buffer->crc_ret);\r
-            (void)memcpy_s((void *)source_buffer->data, KV_CRYPTO_CRC_SIZE, (const void *)&write_buffer->crc_ret,\r
-                KV_CRYPTO_CRC_SIZE);\r
-            write_buffer->crc_claimed = false;\r
-            source_buffer->data_length = KV_CRYPTO_CRC_SIZE;\r
-        }\r
-#if (CONFIG_NV_SUPPORT_ENCRYPT == NV_YES)\r
-        else if (write_buffer->hash_claimed) {\r
-            if (source_buffer->data_length < KV_CRYPTO_HASH_SIZE) {\r
-                return ERRCODE_NV_KEY_HASH_BUFFER_TOO_SMALL;\r
-            }\r
-            (void)memset_s(source_buffer->data,  source_buffer->data_length, 0, source_buffer->data_length);\r
-            nv_crypto_complete_hash(source_buffer->data);\r
-\r
-            write_buffer->crc_ret = kv_crc32_swap(write_buffer->crc_ret);\r
-            (void)memcpy_s((void *)(source_buffer->data + KV_CRYPTO_HASH_SIZE - KV_CRYPTO_CRC_SIZE),\r
-                KV_CRYPTO_CRC_SIZE, (const void *)&write_buffer->crc_ret, KV_CRYPTO_CRC_SIZE);\r
-\r
-            write_buffer->hash_claimed = false;\r
-            source_buffer->data_length = KV_CRYPTO_HASH_SIZE;\r
-        } else if (write_buffer->gcm_tag_claimed) {\r
-            uint32_t tag_len = NV_AES_GCM_TAG_LENGTH;\r
-            if (source_buffer->data_length < KV_CRYPTO_HASH_SIZE) {\r
-                return ERRCODE_NV_KEY_HASH_BUFFER_TOO_SMALL;\r
-            }\r
-\r
-            write_buffer->crc_ret = kv_crc32_swap(write_buffer->crc_ret);\r
-            memset_s(source_buffer->data, source_buffer->data_length, 0, source_buffer->data_length);\r
-\r
-            nv_crypto_get_tag(write_buffer->crypto_handle, source_buffer->data, &tag_len);\r
-\r
-            (void)memcpy_s((void *)(source_buffer->data + KV_CRYPTO_HASH_SIZE - KV_CRYPTO_CRC_SIZE),\r
-                KV_CRYPTO_CRC_SIZE, (const void *)&write_buffer->crc_ret, KV_CRYPTO_CRC_SIZE);\r
-\r
-            write_buffer->gcm_tag_claimed = false;\r
-            source_buffer->data_length = KV_CRYPTO_HASH_SIZE;\r
-        }\r
-#endif\r
-        else {\r
-            return ERRCODE_NV_HASH_UNAVAILABLE;\r
-        }\r
-    }\r
-\r
-    return ERRCODE_SUCC;\r
-}\r
-\r
-/* Gather data from one or more source buffers to fill write_buffer with more data ready for writing to flash */\r
-STATIC kv_update_event_t kv_update_action_prime_write_buffer(void)\r
-{\r
-    errcode_t res;\r
-\r
-    kv_managed_source_buffer_t *source_buffer = g_current_state_machine->current_source;\r
-    kv_managed_write_buffer_t *write_buffer = g_current_state_machine->write_buffer;\r
-\r
-    (void)memset_s(write_buffer->data, write_buffer->size, 0, write_buffer->size);\r
-\r
-    write_buffer->data_length = 0;\r
-    write_buffer->data_consumed = 0;\r
-\r
-    while ((source_buffer != NULL) && (write_buffer->data_length < write_buffer->size)) {\r
-        if (source_buffer->data_consumed < source_buffer->data_length) {\r
-            res = prime_next_chunk();\r
-            if (res == ERRCODE_NV_BUFFER_PRIMED_PREMATURELY) {\r
-                /* Not enough space for padded data so just write what we have for now */\r
-                break;\r
-            }\r
-            if (res != ERRCODE_SUCC) {\r
-                g_current_state_machine->error_code = res;\r
-                return EVENT_ERROR;\r
-            }\r
-        } else {\r
-            /* Select next source buffer */\r
-            res = select_next_source_buffer();\r
-            if (res != ERRCODE_SUCC) {\r
-                g_current_state_machine->error_code = res;\r
-                return EVENT_ERROR;\r
-            }\r
-            source_buffer = g_current_state_machine->current_source;\r
-        }\r
-    }\r
-\r
-    /* Did we manage to place any data in the write buffer? */\r
-    if (write_buffer->data_length == 0) {\r
-        kv_release_crypto();\r
-        return EVENT_WRITE_DATA_EXHAUSTED;\r
-    } else {\r
-        return EVENT_WRITE_BUFFER_PRIMED;\r
-    }\r
-}\r
-\r
-/*\r
- * Attempts to obtain a handle to the first page of the g_current_store\r
- * - g_current_page will be populated if a page is obtained\r
- */\r
-STATIC kv_update_event_t kv_update_action_select_first_page(void)\r
-{\r
-    errcode_t res;\r
-\r
-    res = kv_store_get_page_handle(g_current_store, 0, &g_current_page);\r
-    if (res == ERRCODE_SUCC) {\r
-        return EVENT_PAGE_SELECTED;\r
-    }\r
-    return EVENT_PAGE_NOT_SELECTED;\r
-}\r
-\r
-/*\r
- * Attempts to obtain a handle to the next page of the g_current_store, based on g_current_page\r
- * - g_current_page will be updated if a page is obtained\r
- */\r
-STATIC kv_update_event_t kv_update_action_select_next_page(void)\r
-{\r
-    errcode_t res;\r
-    uint32_t page_index;\r
-    if (kv_page_get_index(&g_current_page, &page_index) != ERRCODE_SUCC) {\r
-        return EVENT_PAGE_NOT_SELECTED;\r
-    }\r
-    page_index++;\r
-    if (page_index < kv_store_get_page_count(g_current_store)) {\r
-        res = kv_store_get_page_handle(g_current_store, page_index, &g_current_page);\r
-        if (res == ERRCODE_SUCC) {\r
-            return EVENT_PAGE_SELECTED;\r
-        }\r
-    }\r
-\r
-    return EVENT_PAGE_NOT_SELECTED;\r
-}\r
-\r
-/*\r
- * Attempts to obtain the first key in the g_current_page, that conforms to g_search_filter\r
- * - g_current_key will be populated if a key is obtained\r
- */\r
-STATIC kv_update_event_t kv_update_action_find_first_key(void)\r
-{\r
-    errcode_t res;\r
-\r
-    res = kv_page_find_first_key(&g_current_page, &g_search_filter, &g_current_key);\r
-    while (res == ERRCODE_SUCC) {\r
-        if (g_current_key.key_location != g_search_filter.location) {\r
-            return EVENT_KEY_FOUND;\r
-        }\r
-        res = kv_page_find_next_key(&g_current_page, &g_search_filter, &g_current_key);\r
-    }\r
-    return EVENT_KEY_NOT_FOUND;\r
-}\r
-\r
-/*\r
- * Attempts to obtain the next key in the g_current_page, based on g_current_key and that conforms to g_search_filter\r
- * - g_current_key will be updated if a key is obtained\r
- */\r
-STATIC kv_update_event_t kv_update_action_find_next_key(void)\r
-{\r
-    errcode_t res;\r
-\r
-    res = kv_page_find_next_key(&g_current_page, &g_search_filter, &g_current_key);\r
-    while (res == ERRCODE_SUCC) {\r
-        if (g_current_key.key_location != g_search_filter.location) {\r
-            return EVENT_KEY_FOUND;\r
-        }\r
-        res = kv_page_find_next_key(&g_current_page, &g_search_filter, &g_current_key);\r
-    }\r
-    return EVENT_KEY_NOT_FOUND;\r
-}\r
-\r
-/*\r
- * Prepares the g_current_state_machine->write_buffer to mark g_current_key as invalid (and hence erased)\r
- * Will not mark keys with the attribute KV_ATTRIBUTE_PERMANENT as invalid\r
- */\r
-STATIC kv_update_event_t kv_update_action_prepare_delete_key(void)\r
-{\r
-    kv_managed_write_buffer_t *write_buffer = NULL;\r
-    kv_attributes_t attributes = kv_key_attributes(&g_current_key);\r
-    if (((uint32_t)attributes & (uint32_t)KV_ATTRIBUTE_PERMANENT) != 0  &&\r
-        (g_new_key_details.focre_write != true)) {\r
-        g_current_state_machine->error_code = ERRCODE_NV_TRYING_TO_MODIFY_A_PERMANENT_KEY;\r
-        return EVENT_ERROR;\r
-    }\r
-\r
-    write_buffer = g_current_state_machine->write_buffer;\r
-    if (write_buffer == NULL) {\r
-        g_current_state_machine->error_code = ERRCODE_NV_WRITE_BUFFER_NOT_ALLOCATED;\r
-        return EVENT_ERROR;\r
-    }\r
-    if (write_buffer->size < sizeof(uint32_t)) {\r
-        g_current_state_machine->error_code = ERRCODE_NV_WRITE_BUFFER_TOO_SMALL;\r
-        return EVENT_ERROR;\r
-    }\r
-\r
-    /* As only 4 bytes are being written, directly prime write buffer rather that setting up a source buffer */\r
-    *(uint32_t *)write_buffer->data = KV_KEY_INVALID;\r
-    write_buffer->data_consumed = 0;\r
-\r
-    if (g_nv_header_magic == KV_KEY_MAGIC) {\r
-        write_buffer->data_length = (uint16_t)sizeof(uint8_t);\r
-        /* Need to manually configure the write location for each key being deleted */\r
-        /* as they will not follow in an ordered sequence                           */\r
-        write_buffer->write_location = (uint32_t)(uintptr_t)((uint8_t *)g_current_key.key_location + sizeof(uint8_t));\r
-    } else {\r
-        write_buffer->data_length = (uint16_t)sizeof(uint16_t);\r
-        write_buffer->write_location = (uint32_t)(uintptr_t)g_current_key.key_location;\r
-    }\r
-\r
-    return EVENT_WRITE_BUFFER_PRIMED;\r
-}\r
-\r
-STATIC kv_update_event_t kv_update_action_prepare_copy_key(void)\r
-{\r
-    kv_managed_write_buffer_t *write_buffer = g_current_state_machine->write_buffer;\r
-    if (write_buffer == NULL) {\r
-        g_current_state_machine->error_code = ERRCODE_NV_WRITE_BUFFER_NOT_ALLOCATED;\r
-        return EVENT_ERROR;\r
-    }\r
-    if (write_buffer->write_location == 0) {\r
-        write_buffer->write_location = (uint32_t)(uintptr_t)g_defrag_page_location + (uint32_t)sizeof(kv_page_header_t);\r
-    }\r
-\r
-    /* Use a source buffer to manage copy progress of key data */\r
-    uint8_t *source = (uint8_t *)g_current_key.key_location;\r
-    uint16_t length = kv_key_flash_size(&g_current_key);\r
-    kv_managed_source_buffer_t *source_buffer = kv_update_source_buffer(source, length);\r
-    g_current_state_machine->current_source = source_buffer;  /* Point current source buffer at first buffer */\r
-    if (source_buffer == NULL) {\r
-        g_current_state_machine->error_code = ERRCODE_MALLOC;\r
-        return EVENT_ERROR;\r
-    }\r
-\r
-    return EVENT_COPY_KEY_READY;\r
-}\r
-\r
-/*\r
- * Attempts to locate an unused page of flash, in the KV NV flash region, to use as the current defrag page\r
- * g_defrag_page_location will be set to point to the unused flash page\r
- */\r
-STATIC kv_update_event_t kv_update_action_find_defrag_page(void)\r
-{\r
-    errcode_t res;\r
-    g_defrag_page_location = NULL;\r
-    res = kv_nvregion_find_unused_page(&g_defrag_page_location);\r
-    if (res == ERRCODE_SUCC) {\r
-        nv_log_debug("[NV] found defrag_page. loc = 0x%x\r\n", g_defrag_page_location);\r
-        return EVENT_DEFRAG_FOUND;\r
-    } else {\r
-        g_current_state_machine->error_code = res;\r
-        return EVENT_ERROR;\r
-    }\r
-}\r
-\r
-/*\r
- * Attempts to erase the current defrag page, as defined by g_defrag_page_location\r
- */\r
-STATIC kv_update_event_t kv_update_action_erase_defrag_page(void)\r
-{\r
-    errcode_t res;\r
-    res = kv_nvregion_erase_page(g_defrag_page_location);\r
-    if (res == ERRCODE_SUCC) {\r
-        return EVENT_DEFRAG_ERASED;\r
-    } else if (res == ERRCODE_NV_WRITE_VETOED) {\r
-        return EVENT_SUSPEND;\r
-    } else {\r
-        g_current_state_machine->error_code = res;\r
-        return EVENT_ERROR;\r
-    }\r
-}\r
-\r
-/*\r
- * Attempts to start the g_prep_defrag_page_machine state machine\r
- */\r
-STATIC kv_update_event_t kv_update_action_prepare_defrag_page(void)\r
-{\r
-    errcode_t res = begin_state_machine(&g_prep_defrag_page_machine);\r
-    if (res == ERRCODE_SUCC) {\r
-        return EVENT_NONE;\r
-    } else {\r
-        g_current_state_machine->error_code = res;\r
-        return EVENT_ERROR;\r
-    }\r
-}\r
-\r
-/*\r
- * Attempts to start the g_copy_all_keys_machine state machine\r
- * Configures g_search_filter to find all valid (un-erased) keys\r
- */\r
-STATIC kv_update_event_t kv_update_action_copy_all_keys(void)\r
-{\r
-    /* Configure search filter to copy all valid keys */\r
-    g_search_filter.pattern = 0;\r
-    g_search_filter.mask = 0;\r
-    g_search_filter.state = KV_KEY_FILTER_STATE_VALID;\r
-    g_search_filter.type = KV_KEY_FILTER_TYPE_ANY;\r
-    g_search_filter.location = 0;\r
-\r
-    errcode_t res = begin_state_machine(&g_copy_all_keys_machine);\r
-    if (res == ERRCODE_SUCC) {\r
-        return EVENT_NONE;\r
-    } else {\r
-        g_current_state_machine->error_code = res;\r
-        return EVENT_ERROR;\r
-    }\r
-}\r
-\r
-/*\r
- * Prepares g_current_state_machine->write_buffer with information to construct a page header for the\r
- * current defrag page, as defined by g_defrag_page_location\r
- * All information is obtained from g_current_page\r
- * The page sequence_number is updated to indicate that this page will supersede g_current_page\r
- */\r
-STATIC kv_update_event_t kv_update_action_prepare_page_header(void)\r
-{\r
-    kv_managed_write_buffer_t *write_buffer = g_current_state_machine->write_buffer;\r
-    if (write_buffer == NULL) {\r
-        g_current_state_machine->error_code = ERRCODE_NV_WRITE_BUFFER_NOT_ALLOCATED;\r
-        return EVENT_ERROR;\r
-    }\r
-    write_buffer->write_location = (uint32_t)(uintptr_t)g_defrag_page_location;\r
-\r
-    if (memcpy_s(write_buffer->data, sizeof(kv_page_header_t), &g_current_page, sizeof(kv_page_header_t)) != EOK) {\r
-        return EVENT_ERROR;\r
-    }\r
-    write_buffer->data_length = (uint16_t)sizeof(kv_page_header_t);\r
-    write_buffer->data_consumed = 0;\r
-\r
-    /* Too specific, move to kv_page? */\r
-    kv_page_header_t *defrag_page_header = (kv_page_header_t *)write_buffer->data;\r
-    defrag_page_header->sequence_number++;\r
-    defrag_page_header->inverted_sequence_number = ~defrag_page_header->sequence_number;\r
-\r
-    return EVENT_WRITE_BUFFER_PRIMED;\r
-}\r
-\r
-/*\r
- * Forces a re-scan of the KV NV flash region to update a map of KV pages\r
- */\r
-STATIC kv_update_event_t kv_update_action_update_nvregion_map(void)\r
-{\r
-    errcode_t res;\r
-\r
-    res = kv_nvregion_scan();\r
-    if (res != ERRCODE_SUCC) {\r
-        g_current_state_machine->error_code = res;\r
-        return EVENT_ERROR;\r
-    }\r
-    return EVENT_NVREGION_MAP_UPDATED;\r
-}\r
-\r
-/*\r
- * Attempts to find a suitable write location in g_current_store for g_new_key_details\r
- * Will set g_current_store_write_location if enough space is found in g_current_store\r
- * Will indicate that a defrag is required if there is not currently enough free space in g_current_store\r
- * Will return an error if a defrag would not free up enough space for the new key\r
- */\r
-STATIC kv_update_event_t kv_update_action_find_write_position(void)\r
-{\r
-    errcode_t res;\r
-    uint16_t required_space;\r
-    kv_key_handle_t new_key;\r
-    kv_page_status_t page_status;\r
-\r
-    /* Work out space needed for new key */\r
-    kv_key_build_from_new(&new_key, &g_new_key_details, 0);\r
-    required_space = kv_key_flash_size(&new_key);\r
-\r
-    res = kv_store_find_write_page(g_current_store, required_space, &g_current_page, &page_status);\r
-    if (res == ERRCODE_SUCC) {\r
-        g_current_store_write_location = (kv_key_location)(uintptr_t)page_status.first_writable_location;\r
-        return EVENT_WRITE_POS_FOUND;\r
-    } else if (res == ERRCODE_NV_DEFRAGMENTATION_NEEDED) {\r
-        return EVENT_DEFRAG_REQUIRED;\r
-    } else {\r
-        g_current_state_machine->error_code = res;\r
-        return EVENT_ERROR;\r
-    }\r
-}\r
-\r
-/*\r
- * Attempts to start the g_defrag_page_machine state machine\r
- */\r
-STATIC kv_update_event_t kv_update_action_defrag_current_page(void)\r
-{\r
-    errcode_t res = begin_state_machine(&g_defrag_page_machine);\r
-    if (res == ERRCODE_SUCC) {\r
-        return EVENT_NONE;\r
-    } else {\r
-        g_current_state_machine->error_code = res;\r
-        return EVENT_ERROR;\r
-    }\r
-}\r
-\r
-/*\r
- * Attempts to start the g_prepare_store_machine state machine\r
- */\r
-STATIC kv_update_event_t kv_update_action_prepare_store(void)\r
-{\r
-    errcode_t res = begin_state_machine(&g_prepare_store_machine);\r
-    if (res == ERRCODE_SUCC) {\r
-        return EVENT_NONE;\r
-    } else {\r
-        g_current_state_machine->error_code = res;\r
-        return EVENT_ERROR;\r
-    }\r
-}\r
-\r
-/*\r
- * Configure write location for g_current_state_machine->write_buffer\r
- * Attempt to allocate memory for AES Control data structure, if key data is to be encrypted\r
- */\r
-STATIC kv_update_event_t kv_update_helper_prepare_write_buffer(void)\r
-{\r
-    kv_managed_write_buffer_t *write_buffer = g_current_state_machine->write_buffer;\r
-\r
-    if (write_buffer == NULL) {\r
-        g_current_state_machine->error_code = ERRCODE_NV_WRITE_BUFFER_NOT_ALLOCATED;\r
-        return EVENT_ERROR;\r
-    }\r
-    write_buffer->write_location = (uint32_t)(uintptr_t)g_current_store_write_location;\r
-    return EVENT_KEY_DATA_READY;\r
-}\r
-\r
-/*\r
- * Attempt to allocate a kv_managed_source_buffer_t for a key header\r
- */\r
-STATIC kv_update_event_t kv_update_helper_setup_key_header_source_buffer(void)\r
-{\r
-    kv_managed_source_buffer_t *source_buffer = NULL;\r
-\r
-    /* Setup source buffers for key header */\r
-    source_buffer = kv_update_source_buffer((uint8_t *)&g_current_key.header, sizeof(kv_key_header_t));\r
-    if (source_buffer == NULL) {\r
-        g_current_state_machine->error_code = ERRCODE_NV_KEY_HEADER_BUFFER_NOT_ALLOCATED;\r
-        return EVENT_ERROR;\r
-    }\r
-\r
-    if (((uint32_t)g_new_key_details.attributes & (uint32_t)KV_ATTRIBUTE_ENCRYPTED) != 0) {\r
-#if (CONFIG_NV_SUPPORT_HASH_FOR_CRYPT == NV_YES)\r
-        source_buffer->hash_data = true;\r
-#else\r
-        source_buffer->gcm_tag_data = true;\r
-#endif\r
-    } else {\r
-        source_buffer->crc_data = true;\r
-    }\r
-    source_buffer->encrypt_data = false;\r
-    return EVENT_KEY_DATA_READY;\r
-}\r
-\r
-/*\r
- * Attempt to allocate a kv_managed_source_buffer_t for key data\r
- */\r
-STATIC kv_update_event_t kv_update_helper_setup_key_data_source_buffer(bool release_key_data)\r
-{\r
-    kv_managed_source_buffer_t *source_buffer = NULL;\r
-\r
-    /* Setup source buffer for key data */\r
-    source_buffer = kv_update_source_buffer((uint8_t *)g_new_key_details.kvalue, g_new_key_details.kvalue_length);\r
-    if (source_buffer == NULL) {\r
-        g_current_state_machine->error_code = ERRCODE_NV_KEY_DATA_BUFFER_NOT_ALLOCATED;\r
-        return EVENT_ERROR;\r
-    }\r
-    source_buffer->release_data = release_key_data;\r
-\r
-    if (((uint32_t)g_new_key_details.attributes & (uint32_t)KV_ATTRIBUTE_ENCRYPTED) != 0) {\r
-#if (CONFIG_NV_SUPPORT_HASH_FOR_CRYPT == NV_YES)\r
-        source_buffer->hash_data = true;\r
-#else\r
-        source_buffer->gcm_tag_data = true;\r
-#endif\r
-    } else {\r
-        source_buffer->crc_data = true;\r
-    }\r
-    source_buffer->encrypt_data = (((uint32_t)g_new_key_details.attributes & (uint32_t)KV_ATTRIBUTE_ENCRYPTED) != 0);\r
-    return EVENT_KEY_DATA_READY;\r
-}\r
-\r
-/*\r
- * Attempt to allocate a kv_managed_source_buffer_t for a key hash\r
- * Will also attempt to allocate a buffer to contain the calculated hash\r
- */\r
-STATIC kv_update_event_t kv_update_helper_setup_key_hash_source_buffer(void)\r
-{\r
-    uint8_t *key_hash = NULL;\r
-    kv_managed_source_buffer_t *source_buffer = NULL;\r
-    uint32_t hash_crc_len = 0;\r
-    if (((uint32_t)g_new_key_details.attributes & (uint32_t)KV_ATTRIBUTE_ENCRYPTED) != 0) {\r
-        hash_crc_len = KV_CRYPTO_HASH_SIZE;\r
-    } else {\r
-        hash_crc_len = KV_CRYPTO_CRC_SIZE;\r
-    }\r
-\r
-    /* Setup source buffer for key hash                                                               */\r
-    /* The hash is calculated while data is written to flash then placed into this buffer for writing */\r
-    key_hash = (uint8_t *)kv_malloc(hash_crc_len);\r
-    if (key_hash == NULL) {\r
-        g_current_state_machine->error_code = ERRCODE_MALLOC;\r
-        return EVENT_ERROR;\r
-    }\r
-    source_buffer = kv_update_source_buffer(key_hash, hash_crc_len);\r
-    if (source_buffer == NULL) {\r
-        kv_free(key_hash);\r
-        g_current_state_machine->error_code = ERRCODE_NV_KEY_HASH_BUFFER_NOT_ALLOCATED;\r
-        return EVENT_ERROR;\r
-    }\r
-    source_buffer->release_data = true;\r
-    source_buffer->receive_hash = true;\r
-    source_buffer->encrypt_data = false;\r
-    return EVENT_KEY_DATA_READY;\r
-}\r
-\r
-/*\r
- * Prepare kv_managed_source_buffers for the three separate parts of a key i.e. header, data and hash\r
- * Ensures state machine write buffer is ready to receive data for writing\r
- * CNcomment: 准备好NV写入需要的source buffer,NV的三个部分(header、数据、HASH/CRC)被放置在三个source buffer中\r
- */\r
-STATIC kv_update_event_t kv_update_helper_prepare_source_buffers(bool release_key_data)\r
-{\r
-    kv_update_event_t event;\r
-\r
-    event = kv_update_helper_prepare_write_buffer();\r
-    if (event == EVENT_KEY_DATA_READY) {\r
-        event = kv_update_helper_setup_key_header_source_buffer();\r
-    }\r
-    if (event == EVENT_KEY_DATA_READY) {\r
-        event = kv_update_helper_setup_key_data_source_buffer(release_key_data);\r
-    }\r
-    if ((event != EVENT_KEY_DATA_READY) && release_key_data) {\r
-        /* Ensure we release any new key data as it will not have been placed into a source buffer */\r
-        /* which get cleaned up automatically when a state machine ends                            */\r
-        kv_free((void *)g_new_key_details.kvalue);\r
-        g_new_key_details.kvalue = NULL;\r
-    }\r
-    if (event == EVENT_KEY_DATA_READY) {\r
-        event = kv_update_helper_setup_key_hash_source_buffer();\r
-    }\r
-    return event;\r
-}\r
-\r
-/*\r
- * Checks if g_current_key would end up being modified by any changes detailed in g_new_key_details\r
- * Will return an error if g_current_key is permanent\r
- */\r
-STATIC kv_update_event_t kv_update_helper_check_for_key_updates(void)\r
-{\r
-    errcode_t res;\r
-    kv_attributes_t attributes = kv_key_attributes(&g_current_key);\r
-    if ((((uint32_t)attributes & (uint32_t)KV_ATTRIBUTE_PERMANENT) != 0) &&\r
-        (g_new_key_details.focre_write != true)) {\r
-        /* We can't modify permanent keys in any way */\r
-        g_current_state_machine->error_code = ERRCODE_NV_TRYING_TO_MODIFY_A_PERMANENT_KEY;\r
-        return EVENT_ERROR;\r
-    }\r
-    if (((uint32_t)attributes & (uint32_t)KV_ATTRIBUTE_NON_UPGRADE) !=\r
-        ((uint32_t)g_new_key_details.attributes & (uint32_t)KV_ATTRIBUTE_NON_UPGRADE)) {\r
-        /* Attributes are being updated */\r
-        return EVENT_KEY_UPDATE_REQUIRED;\r
-    }\r
-    if (((uint32_t)attributes & (uint32_t)g_new_key_details.attributes) != (uint32_t)g_new_key_details.attributes) {\r
-        /* Attributes are being updated */\r
-        return EVENT_KEY_UPDATE_REQUIRED;\r
-    }\r
-\r
-    if (g_current_key.header.length != g_new_key_details.kvalue_length) {\r
-        /* New data is of a different length */\r
-        return EVENT_KEY_UPDATE_REQUIRED;\r
-    }\r
-    res = kv_helper_compare_key_data(&g_current_key, g_new_key_details.kvalue,\r
-                                     (uint16_t)g_new_key_details.kvalue_length);\r
-    if (res != ERRCODE_SUCC) {\r
-        /* New data content is different */\r
-        return EVENT_KEY_UPDATE_REQUIRED;\r
-    }\r
-\r
-    /* Key not actually being updated */\r
-    return EVENT_KEY_UPDATE_NOT_NEEDED;\r
-}\r
-\r
-/*\r
- * Constructs a new key header from g_new_key_details, copying the attributes of any existing key with the same key_id\r
- * Updates g_current_key with details of the new key header\r
- */\r
-STATIC kv_update_event_t kv_update_action_prepare_write_key(void)\r
-{\r
-    errcode_t res = kv_store_find_valid_key(g_current_store, g_new_key_details.key_id, &g_current_key);\r
-    if (res == ERRCODE_SUCC) {\r
-        kv_update_event_t event = kv_update_helper_check_for_key_updates();\r
-        if (event != EVENT_KEY_UPDATE_REQUIRED) {\r
-            nv_log_debug("[NV] The Key not need update. Key id = 0x%x\r\n", g_current_key.header.key_id);\r
-            return event;\r
-        }\r
-\r
-        /* Combine existing key attributes with those requested for the new key */\r
-        if (g_current_key.header.type != KV_KEY_TYPE_NORMAL) {\r
-            g_new_key_details.attributes = (kv_attributes_t)((uint32_t)g_new_key_details.attributes |\r
-                                                             (uint32_t)KV_ATTRIBUTE_PERMANENT);\r
-        }\r
-        if (g_current_key.header.enc_key != 0) {\r
-            g_new_key_details.attributes = (kv_attributes_t)((uint32_t)g_new_key_details.attributes |\r
-                                                             (uint32_t)KV_ATTRIBUTE_ENCRYPTED);\r
-        }\r
-    }\r
-\r
-    kv_key_build_from_new(&g_current_key, &g_new_key_details, g_current_store_write_location);\r
-    return kv_update_helper_prepare_source_buffers(false);\r
-}\r
-\r
-STATIC errcode_t kv_update_helper_get_current_key(uint8_t **old_kvalue, uint32_t *kvalue_length)\r
-{\r
-    kv_key_handle_t current_key;\r
-    errcode_t res;\r
-\r
-    res = kv_store_find_valid_key(g_current_store, g_new_key_details.key_id, &current_key);\r
-    if (res != ERRCODE_SUCC) {\r
-        return res;\r
-    }\r
-\r
-    kv_attributes_t attributes = kv_key_attributes(&current_key);\r
-    if (((uint32_t)attributes & KV_ATTRIBUTE_PERMANENT) != 0) {\r
-        return ERRCODE_SUCC;\r
-    }\r
-\r
-    if (((uint32_t)attributes & KV_ATTRIBUTE_ENCRYPTED) != 0) {\r
-        /* if old key is encrypted, the new key must be encrypted too */\r
-        g_new_key_details.attributes = (kv_attributes_t)((uint32_t)g_new_key_details.attributes |\r
-                                                         (uint32_t)KV_ATTRIBUTE_ENCRYPTED);\r
-    }\r
-\r
-    *kvalue_length = current_key.header.length;\r
-    *old_kvalue = (uint8_t *)kv_malloc(current_key.header.length);\r
-    if (*old_kvalue == NULL) {\r
-        return ERRCODE_MALLOC;\r
-    }\r
-\r
-    res = kv_key_read_data(&current_key, *old_kvalue);\r
-    if (res != ERRCODE_SUCC) {\r
-        kv_free((void *)*old_kvalue);\r
-    }\r
-    return res;\r
-}\r
-\r
-/*\r
- * Attempt to claim access to hardware AES and hash functions\r
- */\r
-STATIC kv_update_event_t kv_update_action_claim_crypto(void)\r
-{\r
-    kv_managed_write_buffer_t *write_buffer = g_current_state_machine->write_buffer;\r
-\r
-    /* Reset write location */\r
-    write_buffer->write_location = (uint32_t)(uintptr_t)g_current_key.key_location;\r
-\r
-    /* Point current source buffer at first buffer and reset data_consumed values */\r
-    g_current_state_machine->current_source = g_current_state_machine->source_buffer;\r
-    kv_managed_source_buffer_t *source_buffer = g_current_state_machine->source_buffer;\r
-    while (source_buffer != NULL) {\r
-        source_buffer->data_consumed = 0;\r
-        source_buffer = source_buffer->next;\r
-    }\r
-\r
-    write_buffer->crypto_handle = INVAILD_CRYPTO_HANDLE;\r
-\r
-    if (((uint32_t)g_new_key_details.attributes & (uint32_t)KV_ATTRIBUTE_ENCRYPTED) != 0) {\r
-#if (CONFIG_NV_SUPPORT_ENCRYPT == NV_YES)\r
-        /* Claim cryptographic engines */\r
-        if (!write_buffer->encrypt_claimed) {\r
-            errcode_t res = nv_crypto_claim_aes(&write_buffer->crypto_handle, &(g_current_key.header));\r
-            if (res != ERRCODE_SUCC) {\r
-                g_current_state_machine->error_code = res;\r
-                return EVENT_ERROR;\r
-            }\r
-            write_buffer->encrypt_claimed = true;\r
-        }\r
-\r
-#if (CONFIG_NV_SUPPORT_HASH_FOR_CRYPT == NV_YES)\r
-        if (!write_buffer->hash_claimed) {\r
-            errcode_t res = nv_crypto_start_hash();\r
-            if (res != ERRCODE_SUCC) {\r
-                nv_crypto_release_aes(write_buffer->crypto_handle);\r
-                write_buffer->crypto_handle = INVAILD_CRYPTO_HANDLE;\r
-                write_buffer->encrypt_claimed = false;\r
-                g_current_state_machine->error_code = res;\r
-                return EVENT_ERROR;\r
-            }\r
-            write_buffer->crc_ret = 0;\r
-            write_buffer->hash_claimed = true;\r
-        }\r
-#else\r
-        if (!write_buffer->gcm_tag_claimed) {\r
-            write_buffer->crc_ret = 0;\r
-            write_buffer->gcm_tag_claimed = true;\r
-        }\r
-#endif /* #if (CONFIG_NV_SUPPORT_HASH_FOR_CRYPT == NV_YES) */\r
-#endif /* #if (CONFIG_NV_SUPPORT_ENCRYPT == NV_YES) */\r
-    } else {\r
-        if (!write_buffer->crc_claimed) {\r
-            write_buffer->crc_ret = 0;\r
-            write_buffer->crc_claimed = true;\r
-        }\r
-    }\r
-\r
-    return EVENT_CRYPTO_CLAIMED;\r
-}\r
-\r
-/*\r
- * Attempts to erases all instances of g_current_key (in g_current_store), by marking them as invalid\r
- * Configures g_search_filter to find all valid keys with an id matching g_current_key.header.key_id\r
- * Starts the g_erase_keys_machine state machine to perform the erasing of keys\r
- */\r
-STATIC kv_update_event_t kv_update_action_erase_old_keys(void)\r
-{\r
-    g_search_filter.pattern = g_current_key.header.key_id;\r
-    g_search_filter.mask = 0xFFFF;\r
-    g_search_filter.state = KV_KEY_FILTER_STATE_VALID;\r
-    g_search_filter.type = KV_KEY_FILTER_TYPE_ANY;\r
-    g_search_filter.location = g_current_key.key_location;\r
-\r
-    errcode_t res = begin_state_machine(&g_erase_keys_machine);\r
-    if (res == ERRCODE_SUCC) {\r
-        return EVENT_NONE;\r
-    } else {\r
-        g_current_state_machine->error_code = res;\r
-        return EVENT_ERROR;\r
-    }\r
-}\r
-\r
-STATIC kv_update_event_t kv_update_action_update_nvmap_for_erase_key(void)\r
-{\r
-    kv_nvregion_map_t *nv_map = kv_nvregion_get_map();\r
-    uint32_t page_number = kv_nvregion_get_page_number(g_current_page.page_location);\r
-    if (page_number >= nv_map->num_entries) {\r
-        nv_log_debug("[NV] get erase page_number failed! page_location = 0x%x\r\n", g_current_page.page_location);\r
-        g_current_state_machine->error_code = ERRCODE_NV_INVALID_PAGE;\r
-        return EVENT_ERROR;\r
-    }\r
-\r
-    uint16_t key_size = (uint32_t)sizeof(kv_key_header_t);\r
-    uint16_t hash_crc_size;\r
-    if (g_current_key.header.enc_key == AES_KDFKEY_SDRK_TYPE) {\r
-        hash_crc_size = KV_CRYPTO_HASH_SIZE;\r
-    } else {\r
-        hash_crc_size = KV_CRYPTO_CRC_SIZE;\r
-    }\r
-\r
-    key_size += hash_crc_size;\r
-\r
-    kv_attributes_t attributes = kv_key_attributes(&g_current_key);\r
-    key_size += kv_key_padded_data_length(attributes, g_current_key.header.length);\r
-\r
-    nv_page_status_map_t *page_status = &(nv_map->page_status_map[page_number]);\r
-    page_status->reclaimable_space += key_size;\r
-    nv_log_debug("[NV] update nv map for erase key = 0x%x (page = 0x%x) size = %d\r\n",\r
-        g_current_key.header.key_id, g_current_page.page_location, key_size);\r
-    return EVENT_PAGE_MAP_UPDATED;\r
-}\r
-\r
-STATIC kv_update_event_t kv_update_action_update_nvmap_for_new_key(void)\r
-{\r
-    kv_nvregion_map_t *nv_map = kv_nvregion_get_map();\r
-\r
-    uint32_t page_number = kv_nvregion_get_page_number(g_current_page.page_location);\r
-    if (page_number >= nv_map->num_entries) {\r
-        nv_log_debug("[NV] get new key page_number failed! page_location = 0x%x\r\n", g_current_page.page_location);\r
-        g_current_state_machine->error_code = ERRCODE_NV_INVALID_PAGE;\r
-        return EVENT_ERROR;\r
-    }\r
-\r
-    uint16_t key_size = (uint32_t)sizeof(kv_key_header_t);\r
-    uint16_t hash_crc_size;\r
-    if (((uint32_t)g_new_key_details.attributes & (uint32_t)KV_ATTRIBUTE_ENCRYPTED) != 0) {\r
-        hash_crc_size = KV_CRYPTO_HASH_SIZE;\r
-    } else {\r
-        hash_crc_size = KV_CRYPTO_CRC_SIZE;\r
-    }\r
-\r
-    key_size += hash_crc_size;\r
-    key_size += kv_key_padded_data_length(g_new_key_details.attributes, g_new_key_details.kvalue_length);\r
-\r
-    nv_page_status_map_t *page_status = &(nv_map->page_status_map[page_number]);\r
-    page_status->used_space += key_size;\r
-    page_status->first_writable_offset += key_size;\r
-    nv_log_debug("[NV] update nv map for new key = 0x%x (page = 0x%x) size = %d\r\n",\r
-        g_new_key_details.key_id, g_current_page.page_location, key_size);\r
-    return EVENT_PAGE_MAP_UPDATED;\r
-}\r
-\r
-/*\r
- * Begins a new state machine by creating a new entry at the end of the active state machines list\r
- * and updating g_current_state_machine\r
- *\r
- * Either called to begin processing a *new* top-level state machine, before calling process_state_machine()\r
- * or called by a state machine action function to kick off the processing of a new (nested) state machine\r
- */\r
-STATIC errcode_t begin_state_machine(const kv_state_machine_t *machine)\r
-{\r
-    kv_active_state_machine_t *new_state_machine =\r
-        (kv_active_state_machine_t *)kv_malloc(sizeof(kv_active_state_machine_t));\r
-    if (new_state_machine == NULL) {\r
-        return ERRCODE_MALLOC;\r
-    }\r
-    (void)memset_s(new_state_machine, sizeof(kv_active_state_machine_t), 0, sizeof(kv_active_state_machine_t));\r
-    new_state_machine->prev = g_current_state_machine;\r
-\r
-    /* Configure default initial state and event for new state machine */\r
-    new_state_machine->machine = machine;\r
-    new_state_machine->state = machine->initial_state;\r
-    new_state_machine->event = EVENT_NONE;\r
-    new_state_machine->error_code = ERRCODE_SUCC;\r
-    g_current_state_machine = new_state_machine;\r
-\r
-    if (g_current_state_machine->machine->write_buffer_size > 0) {\r
-        return kv_create_write_buffer(0, g_current_state_machine->machine->write_buffer_size);\r
-    } else {\r
-        return ERRCODE_SUCC;\r
-    }\r
-}\r
-\r
-/*\r
- * Should only be called by process_state_machine()\r
- *\r
- * Ends current state machine and updates g_current_state_machine to point to the previous state machine.\r
- * Passes either the pre-defined exit_event or the last event returned by an action function as the\r
- * event received by the previous state machine.\r
- */\r
-STATIC void end_state_machine(void)\r
-{\r
-    if (g_current_state_machine != NULL) {\r
-        kv_remove_write_buffer();\r
-        kv_remove_source_buffer();\r
-\r
-        kv_active_state_machine_t *prev_state_machine = g_current_state_machine->prev;\r
-        if (prev_state_machine != NULL) {\r
-            if (g_current_state_machine->machine->exit_event != EVENT_NONE) {\r
-                /* Single explicit exit event defined for exiting state machine */\r
-                prev_state_machine->event = g_current_state_machine->machine->exit_event;\r
-            } else {\r
-                /* Pass last event raised from exiting state machine back to invoking state machine */\r
-                prev_state_machine->event = g_current_state_machine->event;\r
-            }\r
-        }\r
-\r
-        kv_free(g_current_state_machine);\r
-        g_current_state_machine = prev_state_machine;\r
-    }\r
-}\r
-\r
-static void clean_state_machine(void)\r
-{\r
-    while (g_current_state_machine != NULL) {\r
-        end_state_machine();\r
-    }\r
-}\r
-\r
-/*\r
- * Should only be called by process_state_machine()\r
- *\r
- * Attempts to locate and call an action function based on the state of the current state machine\r
- * An action function may spawn another state machine and hence cause g_current_state_machine to change.\r
- *\r
- * g_current_state_machine->event is used to record the return value from the action function.\r
- *\r
- * If a new state machine is spawned, this return value will effectively be lost as the procedure for processing\r
- * new state machines is to assume there is no initial event, just an initial state and thus action to perform.\r
- *\r
- * If an action function is not found then g_current_state_machine->event will not be updated.  This really should\r
- * be reserved for when state transitions cause g_current_state_machine->state to be one of the following\r
- * special cases, which are handled by process_state_machine():\r
- *   - STATE_INVALID\r
- *   - STATE_SUSPENDED\r
- *   - STATE_EXIT\r
- */\r
-static void invoke_current_state_action(void)\r
-{\r
-    if (g_current_state_machine != NULL) {\r
-        /* Search action table to locate an action function for the current state */\r
-        /* STATE_EXIT always marks end of an action table                         */\r
-        const kv_update_action_t *update_action = g_current_state_machine->machine->action_table;\r
-        while (update_action->state != STATE_EXIT) {\r
-            if (update_action->state == g_current_state_machine->state) {\r
-                /* Found a matching entry */\r
-                break;\r
-            }\r
-            update_action++;\r
-        }\r
-\r
-        /* Call action function if we have found one */\r
-        if (update_action->action != NULL) {\r
-            /* Action function could cause a change of g_current_state_machine */\r
-            g_current_state_machine->event = (*update_action->action)();\r
-        }\r
-    }\r
-}\r
-\r
-/*\r
- * Should only be called by process_state_machine()\r
- *\r
- * Uses the last event recorded for the state machine, in g_current_state_machine->event, to select the\r
- * next appropriate state for the current state machine.\r
- *\r
- * In the case of no suitable entry on the transition_table an error state of STATE_INVALID is entered.\r
- * This will cause process_state_machine() to terminate processing of all queued state machines and\r
- * return an error.\r
- */\r
-STATIC void update_current_state(void)\r
-{\r
-    /* Don't update anything for EVENT_NONE.  We'll eventually call the action function again */\r
-    if ((g_current_state_machine != NULL) && (g_current_state_machine->event != EVENT_NONE)) {\r
-        /* Search transition table looking for a transition entry for current state and event */\r
-        /* A transition table is always terminated with transition->state == STATE_EXIT       */\r
-        const kv_update_transition_t *transition = g_current_state_machine->machine->transition_table;\r
-        while (transition->state != STATE_EXIT) {\r
-            if ((g_current_state_machine->state == transition->state) &&\r
-                (g_current_state_machine->event == transition->event)) {\r
-                /* Found a matching entry */\r
-                break;\r
-            }\r
-            transition++;\r
-        }\r
-\r
-        /* Update current state if we have found a suitable transition table entry */\r
-        if (transition->state != STATE_EXIT) {\r
-            g_current_state_machine->state = transition->next_state;\r
-        } else {\r
-            /* No state transition found for the current state and event */\r
-            g_current_state_machine->state = STATE_INVALID;\r
-        }\r
-    }\r
-}\r
-\r
-#if defined (DEBUG_PRINT_ENABLED)\r
-static const char *g_update_state_strings[STATE_EXIT + 1] = {\r
-    [STATE_INVALID] =             "STATE_INVALID",\r
-    [STATE_SELECT_FIRST_PAGE] =   "STATE_SELECT_FIRST_PAGE",\r
-    [STATE_SELECT_NEXT_PAGE] =    "STATE_SELECT_NEXT_PAGE",\r
-    [STATE_FIND_FIRST_KEY] =      "STATE_FIND_FIRST_KEY",\r
-    [STATE_FIND_NEXT_KEY] =       "STATE_FIND_NEXT_KEY",\r
-    [STATE_FIND_EXISTING_KEY] =   "STATE_FIND_EXISTING_KEY",\r
-    [STATE_PREP_COPY_KEY] =       "STATE_PREP_COPY_KEY",\r
-    [STATE_PREP_DELETE_KEY] =     "STATE_PREP_DELETE_KEY",\r
-    [STATE_PREP_MODIFY_KEY] =     "STATE_PREP_MODIFY_KEY",\r
-    [STATE_FIND_DEFRAG] =         "STATE_FIND_DEFRAG",\r
-    [STATE_ERASE_DEFRAG] =        "STATE_ERASE_DEFRAG",\r
-    [STATE_PREP_DEFRAG] =         "STATE_PREP_DEFRAG",\r
-    [STATE_COPY_ALL_KEYS] =       "STATE_COPY_ALL_KEYS",\r
-    [STATE_PREP_PAGE_HEADER] =    "STATE_PREP_PAGE_HEADER",\r
-    [STATE_WRITE_PAGE_HEADER] =   "STATE_WRITE_PAGE_HEADER",\r
-    [STATE_UPDATE_NVREGION_MAP] = "STATE_UPDATE_NVREGION_MAP",\r
-    [STATE_FIND_WRITE_POS] =      "STATE_FIND_WRITE_POS",\r
-    [STATE_DEFRAG_PAGE] =         "STATE_DEFRAG_PAGE",\r
-    [STATE_PREP_STORE] =          "STATE_PREP_STORE",\r
-    [STATE_PREP_KEY_DATA] =       "STATE_PREP_KEY_DATA",\r
-    [STATE_CLAIM_CRYPTO] =        "STATE_CLAIM_CRYPTO",\r
-    [STATE_ERASE_OLD_KEYS] =      "STATE_ERASE_OLD_KEYS",\r
-    [STATE_PRIME_WRITE] =         "STATE_PRIME_WRITE",\r
-    [STATE_PERFORM_WRITE] =       "STATE_PERFORM_WRITE",\r
-    [STATE_SUSPENDED] =           "STATE_SUSPENDED",\r
-    [STATE_EXIT] =                "STATE_EXIT"\r
-};\r
-\r
-#if defined (DEBUG_KV_UPDATE_STATE_MACHINE)\r
-static const char *g_update_event_strings[EVENT_ERROR + 1] = {\r
-    [EVENT_NONE] =                  "EVENT_NONE",\r
-    [EVENT_SUSPEND] =               "EVENT_SUSPEND",\r
-    [EVENT_WRITE_DATA_EXHAUSTED] =  "EVENT_WRITE_DATA_EXHAUSTED",\r
-    [EVENT_WRITE_BUFFER_PRIMED] =   "EVENT_WRITE_BUFFER_PRIMED",\r
-    [EVENT_WRITE_BUFFER_STORED] =   "EVENT_WRITE_BUFFER_STORED",\r
-    [EVENT_PAGE_SELECTED] =         "EVENT_PAGE_SELECTED",\r
-    [EVENT_PAGE_NOT_SELECTED] =     "EVENT_PAGE_NOT_SELECTED",\r
-    [EVENT_KEY_FOUND] =             "EVENT_KEY_FOUND",\r
-    [EVENT_KEY_NOT_FOUND] =         "EVENT_KEY_NOT_FOUND",\r
-    [EVENT_COPY_KEY_READY] =        "EVENT_COPY_KEY_READY",\r
-    [EVENT_KEYS_ERASED] =           "EVENT_KEYS_ERASED",\r
-    [EVENT_KEY_UPDATE_REQUIRED] =   "EVENT_KEY_UPDATE_REQUIRED",\r
-    [EVENT_KEY_UPDATE_NOT_NEEDED] = "EVENT_KEY_UPDATE_NOT_NEEDED",\r
-    [EVENT_DEFRAG_FOUND] =          "EVENT_DEFRAG_FOUND",\r
-    [EVENT_DEFRAG_ERASED] =         "EVENT_DEFRAG_ERASED",\r
-    [EVENT_DEFRAG_PREPARED] =       "EVENT_DEFRAG_PREPARED",\r
-    [EVENT_ALL_KEYS_COPIED] =       "EVENT_ALL_KEYS_COPIED",\r
-    [EVENT_PAGE_HEADER_READY] =     "EVENT_PAGE_HEADER_READY",\r
-    [EVENT_NVREGION_MAP_UPDATED] =  "EVENT_NVREGION_MAP_UPDATED",\r
-    [EVENT_DEFRAG_REQUIRED] =       "EVENT_DEFRAG_REQUIRED",\r
-    [EVENT_DEFRAG_COMPLETE] =       "EVENT_DEFRAG_COMPLETE",\r
-    [EVENT_WRITE_POS_FOUND] =       "EVENT_WRITE_POS_FOUND",\r
-    [EVENT_STORE_READY] =           "EVENT_STORE_READY",\r
-    [EVENT_KEY_DATA_READY] =        "EVENT_KEY_DATA_READY",\r
-    [EVENT_CRYPTO_CLAIMED] =        "EVENT_CRYPTO_CLAIMED",\r
-    [EVENT_WRITE_COMPLETE] =        "EVENT_WRITE_COMPLETE",\r
-    [EVENT_ERROR] =                 "EVENT_ERROR"\r
-};\r
-#endif\r
-#endif\r
-\r
-static void dprint_state_machine(const char *str)\r
-{\r
-    unused(str);\r
-#if defined (DEBUG_KV_UPDATE_STATE_MACHINE)\r
-    if (g_current_state_machine != NULL) {\r
-        nv_log_debug("%08X:  ", (uint32_t)g_current_state_machine);\r
-        nv_log_debug("%s  ", g_update_state_strings[g_current_state_machine->state]);\r
-        nv_log_debug("%s  ", str);\r
-        nv_log_debug("%s\r\n", g_update_event_strings[g_current_state_machine->event]);\r
-    } else {\r
-        nv_log_debug("*** State Machine  %s ***\r\n", str);\r
-    }\r
-#endif\r
-}\r
-\r
-/*\r
- * Function used to process queued state machines\r
- *\r
- * There is only ever one state machine being processed at any one time.\r
- *\r
- * State machines are started (queued) by explicitly calling begin_state_machine() before this function is called.\r
- * State machines themselves can spawn a nested state machine by also calling begin_state_machine() in an action\r
- * function.\r
- * When started, a state machine will be in the initial_state defined for the state machine.\r
- *\r
- * State machines are ended normally by transitioning to STATE_EXIT or abnormally by transitioning to STATE_INVALID.\r
- * In such instances, process_state_machine(), will call end_state_machine() to tidy up.\r
- *\r
- * State machines can be suspended at any point by transitioning to STATE_SUSPENDED.\r
- * When resumed, by calling process_state_machine() again, they will start from the resume_state defined for the\r
- * state machine.\r
- *\r
- * g_current_state_machine points to the current active state machine\r
- *\r
- * When a state machine is processed for the first time, or resumed following suspension, it is assumed there is no\r
- * current event that exists for the state machine in this context.  An action function for the current state, which\r
- * will be defined by initial_state or resume_state, will provide an event to provide for further transitions through\r
- * the state machine.\r
- */\r
-STATIC errcode_t process_state_machine(void)\r
-{\r
-    errcode_t error_code = ERRCODE_SUCC;\r
-    uint64_t flash_access_time = 0;\r
-    unused(flash_access_time);\r
-\r
-    while (g_current_state_machine != NULL) {\r
-        /* Call action function for the current state */\r
-        dprint_state_machine("---");\r
-        invoke_current_state_action();\r
-        dprint_state_machine("-->");\r
-\r
-        /* Check event returned by action function */\r
-        if (g_current_state_machine->event == EVENT_ERROR) {\r
-            /* Ripple back down chain of state machines and report error */\r
-            error_code = g_current_state_machine->error_code;\r
-            clean_state_machine();\r
-            return error_code;\r
-        }\r
-\r
-        /* Transition state machine */\r
-        update_current_state();\r
-        dprint_state_machine("<--");\r
-\r
-        /* Has the state machine finished? */\r
-        while ((g_current_state_machine != NULL) && (g_current_state_machine->state == STATE_EXIT)) {\r
-            invoke_current_state_action();  /* Exit state could have an action function if it needs to do more */\r
-            end_state_machine();            /* than just end the current state machine                         */\r
-            update_current_state();\r
-            dprint_state_machine("<==");\r
-        }\r
-\r
-        /* Has state machine processing been suspended? */\r
-        if ((g_current_state_machine != NULL) && (g_current_state_machine->state == STATE_SUSPENDED)) {\r
-#ifdef CONFIG_NV_SUPPORT_SINGLE_CORE_SYSTEM\r
-            /* if in one-core system, the flash must be writen in one time */\r
-            /* so once the suspend happened, clear the state_machine */\r
-            clean_state_machine();\r
-#else\r
-            /* We need to suspend processing due to other cores waking up */\r
-            /* Configure state machine to resume from the correct place */\r
-            g_current_state_machine->state = g_current_state_machine->machine->resume_state;\r
-            g_current_state_machine->event = EVENT_NONE;\r
-#endif\r
-            kv_release_crypto();\r
-            return ERRCODE_NV_WRITE_VETOED;\r
-        }\r
-\r
-        /* Has the state machine entered an invalid state? */\r
-        if ((g_current_state_machine != NULL) && (g_current_state_machine->state == STATE_INVALID)) {\r
-#ifdef CONFIG_NV_SUPPORT_SINGLE_CORE_SYSTEM\r
-            clean_state_machine();\r
-#endif\r
-            kv_release_crypto();\r
-            return ERRCODE_NV_STATE_INVALID;\r
-        }\r
-    }\r
-\r
-    return error_code;\r
-}\r
-\r
-/* Creates a write buffer used to prepare data, gathered from one or more source buffers, for writing to flash */\r
-STATIC errcode_t kv_create_write_buffer(uint32_t write_location, uint32_t size)\r
-{\r
-    if (size == 0) {\r
-        return ERRCODE_INVALID_PARAM;\r
-    }\r
-\r
-    if (g_current_state_machine->write_buffer != NULL) {\r
-        return ERRCODE_FAIL;\r
-    }\r
-\r
-    uint8_t *data = (uint8_t *)kv_malloc(size);\r
-    if (data == NULL) {\r
-        return ERRCODE_MALLOC;\r
-    }\r
-    kv_managed_write_buffer_t *write_buffer =\r
-        (kv_managed_write_buffer_t *)kv_malloc(sizeof(kv_managed_write_buffer_t));\r
-    if (write_buffer == NULL) {\r
-        kv_free(data);\r
-        return ERRCODE_MALLOC;\r
-    }\r
-\r
-    (void)memset_s(write_buffer, sizeof(kv_managed_write_buffer_t), 0, sizeof(kv_managed_write_buffer_t));\r
-    write_buffer->data = data;\r
-    write_buffer->size = (uint16_t)size;\r
-    write_buffer->data_consumed = (uint16_t)size;\r
-    write_buffer->write_location = write_location;\r
-    write_buffer->resume_location = write_location;\r
-    g_current_state_machine->write_buffer = write_buffer;\r
-\r
-    return ERRCODE_SUCC;\r
-}\r
-\r
-/* Removes the write buffer owned by the current state machine */\r
-STATIC void kv_remove_write_buffer(void)\r
-{\r
-    if (g_current_state_machine->write_buffer != NULL) {\r
-        kv_free(g_current_state_machine->write_buffer->data);\r
-        kv_free(g_current_state_machine->write_buffer);\r
-        g_current_state_machine->write_buffer = NULL;\r
-    }\r
-}\r
-\r
-/* Every key consists of a header, data and a hash.  Multiple kv_managed_source_buffer_t are constructed to\r
- * manage these separate blocks of data.\r
- * They keep track of where the data is located and how much of it has\r
- * been written to flash.\r
- * These buffers are used in a scatter-gather type approach to feed a single write buffer that holds data\r
- * that has been fully prepared for writing to flash */\r
-STATIC kv_managed_source_buffer_t* kv_update_source_buffer(uint8_t *data, uint32_t data_length)\r
-{\r
-    kv_managed_source_buffer_t *source_buffer = kv_malloc(sizeof(kv_managed_source_buffer_t));\r
-    if (source_buffer == NULL) {\r
-        return NULL;\r
-    }\r
-\r
-    errno_t err = memset_s(source_buffer, sizeof(kv_managed_source_buffer_t), 0, sizeof(kv_managed_source_buffer_t));\r
-    if (err != EOK) {\r
-        kv_free(source_buffer);\r
-        return NULL;\r
-    }\r
-    source_buffer->data = data;\r
-    source_buffer->data_length = (uint16_t)data_length;\r
-    source_buffer->next = NULL;\r
-\r
-    /* Append new buffer to end of list */\r
-    kv_managed_source_buffer_t **next_buffer = &g_current_state_machine->source_buffer;\r
-    while (*next_buffer != NULL) {\r
-        next_buffer = &(*next_buffer)->next;\r
-    }\r
-    *next_buffer = source_buffer;\r
-    return source_buffer;\r
-}\r
-\r
-/* Removes kv_managed_source_buffer_t data structures, freeing memory holding actual data too, if necessary */\r
-STATIC void kv_remove_source_buffer(void)\r
-{\r
-    kv_managed_source_buffer_t *current = g_current_state_machine->source_buffer;\r
-    while (current != NULL) {\r
-        kv_managed_source_buffer_t *next = current->next;\r
-        if (current->release_data) {\r
-            kv_free(current->data);\r
-        }\r
-        kv_free(current);\r
-        current = next;\r
-    }\r
-    g_current_state_machine->source_buffer = NULL;\r
-}\r
-\r
-/* Releases claim over hardware AES and hash functions */\r
-STATIC void kv_release_crypto(void)\r
-{\r
-    if (g_current_state_machine == NULL) {\r
-        return;\r
-    }\r
-    kv_managed_write_buffer_t *write_buffer = g_current_state_machine->write_buffer;\r
-    uint32_t status;\r
-\r
-    if (write_buffer != NULL) {\r
-        status = osal_irq_lock();\r
-        if (write_buffer->crc_claimed) {\r
-            write_buffer->crc_ret = 0;\r
-            write_buffer->crc_claimed = false;\r
-        }\r
-#if (CONFIG_NV_SUPPORT_ENCRYPT == NV_YES)\r
-        if (write_buffer->hash_claimed) {\r
-            write_buffer->hash_claimed = false;\r
-        }\r
-        if (write_buffer->gcm_tag_claimed) {\r
-            write_buffer->gcm_tag_claimed = false;\r
-        }\r
-        if (write_buffer->encrypt_claimed) {\r
-            nv_crypto_release_aes(write_buffer->crypto_handle);\r
-            write_buffer->crypto_handle = INVAILD_CRYPTO_HANDLE;\r
-            write_buffer->encrypt_claimed = false;\r
-        }\r
-#endif\r
-        osal_irq_restore(status);\r
-    }\r
-}\r
-\r
-STATIC bool active_state_machine(void)\r
-{\r
-    if (g_current_state_machine != NULL) {\r
-        return true;\r
-    }\r
-    return false;\r
-}\r
-\r
-STATIC uint32_t determine_flash_task_state_code(errcode_t res)\r
-{\r
-    switch (res) {\r
-        case ERRCODE_NV_WRITE_VETOED:\r
-        case ERRCODE_FLASH_TASK_PE_VETO:\r
-            return FLASH_TASK_BEING_PROCESSED;\r
-        case ERRCODE_SUCC:\r
-            return FLASH_TASK_COMPLETED;\r
-        default:\r
-            return (uint32_t)res;\r
-    }\r
-}\r
-\r
-#if defined(CONFIG_PARTITION_FEATURE_SUPPORT)\r
-STATIC errcode_t nv_read_partition_addr(uint32_t *start_address, uint32_t *size)\r
-{\r
-    /* 获取分区表标记 */\r
-    errcode_t ret;\r
-    partition_information_t info;\r
-\r
-    ret = uapi_partition_get_info(PARTITION_NV_DATA, &info);\r
-    if (ret != ERRCODE_SUCC) {\r
-        return ret;\r
-    }\r
-    *start_address = info.part_info.addr_info.addr + FLASH_PHYSICAL_ADDR_START;\r
-    *size = info.part_info.addr_info.size;\r
-\r
-    return ERRCODE_SUCC;\r
-}\r
-#endif\r
-\r
-errcode_t kv_update_init(cores_t core)\r
-{\r
-    unused(core);\r
-\r
-    errcode_t res;\r
-    uint32_t kv_start_addr = 0;\r
-    uint32_t kv_size = 0;\r
-#if defined(CONFIG_PARTITION_FEATURE_SUPPORT)\r
-    res = nv_read_partition_addr(&kv_start_addr, &kv_size);\r
-    if (res != ERRCODE_SUCC) {\r
-        return res;\r
-    }\r
-#endif\r
-    if (kv_start_addr != 0 && kv_size != 0) {\r
-        kv_nvregion_init(kv_start_addr, KV_STORE_DATA_SIZE, kv_start_addr + KV_STORE_DATA_SIZE, KV_BACKUP_DATA_SIZE);\r
-    } else {\r
-        kv_nvregion_init(KV_STORE_START_ADDR, KV_STORE_DATA_SIZE, KV_BACKUP_START_ADDR, KV_BACKUP_DATA_SIZE);\r
-    }\r
-\r
-    /* Scan NV region looking for KV pages */\r
-    res = kv_nvregion_scan();\r
-    if (res != ERRCODE_SUCC) {\r
-        return res;\r
-    }\r
-\r
-    /* Check expected KV pages have been found */\r
-    for (uint8_t store = (uint8_t)KV_STORE_APPLICATION; store < (uint8_t)KV_STORE_MAX_NUM; store++) {\r
-        uint16_t store_id = kv_store_get_id(store);\r
-        uint8_t pages_num = kv_store_get_page_count(store);\r
-        for (uint8_t page_index = 0; page_index < pages_num; page_index++) {\r
-            res = kv_nvregion_find_page(store_id, page_index, NULL, NULL);\r
-            if (res != ERRCODE_SUCC) {\r
-                /* NV Region does not contain an expected KV page, attempt to create it */\r
-                res = kv_nvregion_create_page(store_id, page_index);\r
-            }\r
-            if (res != ERRCODE_SUCC) {\r
-                return ERRCODE_FAIL;\r
-            }\r
-        }\r
-    }\r
-    return ERRCODE_SUCC;\r
-}\r
-\r
-#if (CONFIG_NV_SUPPORT_BACKUP_RESTORE == NV_YES)\r
-STATIC errcode_t kv_updata_backup_page_head_is_valid(const kv_page_header_t *backup_head)\r
-{\r
-    if ((backup_head->details.store_id == KV_STORE_ID_BACKUP) &&\r
-        ((~backup_head->inverted_details_word) == *(uint32_t *)(uintptr_t)(&backup_head->details)) &&\r
-        ((~backup_head->inverted_sequence_number) == backup_head->sequence_number)) {\r
-            return ERRCODE_SUCC;\r
-    }\r
-    return ERRCODE_FAIL;\r
-}\r
-\r
-STATIC errcode_t kv_updata_backup_fail_process(uint32_t back_maybe_need_process_location)\r
-{\r
-    errcode_t res;\r
-    kv_page_location unused_page_location = NULL;\r
-    uint32_t page_head_size = (uint32_t)sizeof(kv_page_header_t);\r
-    kv_nvregion_area_t* nvregion_area =  nv_get_region_area();\r
-    if (nvregion_area == NULL) {\r
-        return ERRCODE_FAIL;\r
-    }\r
-    /* 去找工作区可以换页的页,然后将可以换页的页地址给传出 */\r
-    res = kv_nvregion_find_unused_page(&unused_page_location);\r
-    if (res != ERRCODE_SUCC) {\r
-        return res;\r
-    }\r
-    /* 获取工作区换页页的页头  */\r
-    kv_page_header_t store_head_buffer;\r
-    res = kv_key_helper_copy_flash((uint32_t)(uintptr_t)&store_head_buffer,\r
-        (uint32_t)unused_page_location, page_head_size);\r
-    if (res != ERRCODE_SUCC) {\r
-        return res;\r
-    }\r
-    /* 如果页头中包含 KV_STORE_ID_BACKUP 并且该page_location与maybe_need_process_location时都指向同一页 那么说明存在掉电丢数据的情况 */\r
-    if (kv_updata_backup_page_head_is_valid(&store_head_buffer) == ERRCODE_SUCC) {\r
-        uint32_t back_page_location = nvregion_area->nv_backup_addr\r
-            + store_head_buffer.details.page_index * KV_PAGE_SIZE;\r
-        if (back_page_location == back_maybe_need_process_location) {\r
-            res = kv_key_erase_flash(back_page_location, KV_PAGE_SIZE);\r
-            if (res != ERRCODE_SUCC) {\r
-                return res;\r
-            }\r
-            res = kv_backup_copy_unused_page_to_dragpage(back_page_location, (uint32_t)unused_page_location);\r
-            if (res != ERRCODE_SUCC) {\r
-                return res;\r
-            }\r
-        }\r
-    }\r
-    return ERRCODE_SUCC;\r
-}\r
-\r
-errcode_t kv_update_backup_init(void)\r
-{\r
-    /* Initializes the page header of the backup area */\r
-    errcode_t res;\r
-    uint32_t backup_not_inited_count = 0; /* 重启时备份区没有初始化的数量为0 */\r
-    uint32_t back_maybe_need_process_location = 0;\r
-    kv_nvregion_area_t* nvregion_area =  nv_get_region_area();\r
-    if (nvregion_area == NULL) {\r
-        return ERRCODE_FAIL;\r
-    }\r
-    uint32_t back_page_location = nvregion_area->nv_backup_addr;\r
-    kv_page_header_t backup_head_buffer;\r
-    for (uint32_t page_index = 0; page_index < KV_BACKUP_PAGE_NUM; page_index++) {\r
-        res = kv_key_helper_copy_flash((uint32_t)(uintptr_t)&backup_head_buffer,\r
-            (uint32_t)back_page_location, sizeof(kv_page_header_t));\r
-        if (res != ERRCODE_SUCC) {\r
-            return res;\r
-        }\r
-        if (kv_updata_backup_page_head_is_valid(&backup_head_buffer) == ERRCODE_FAIL) {\r
-            backup_not_inited_count++;\r
-            res = kv_nvregion_write_page((kv_page_location)back_page_location, KV_STORE_ID_BACKUP, page_index);\r
-            if (res != ERRCODE_SUCC) {\r
-                return res;\r
-            }\r
-            back_maybe_need_process_location = back_page_location;\r
-        }\r
-        back_page_location += KV_PAGE_SIZE;\r
-    }\r
-\r
-    /* 如果备份区没有初始化的页的数量为0, 说明备份区页不存在异常,正常重启 */\r
-    /* 如果备份区未初始化的页的数量大于1, 说明是刚刚烧录状态,对备份区页头的初始化 */\r
-    /* 如果备份区没有初始化的页的数量为1, 那么说明可能存在掉电异常场景进行处理 */\r
-    if (backup_not_inited_count == 1) {\r
-        res = kv_updata_backup_fail_process(back_maybe_need_process_location);\r
-        if (res != ERRCODE_SUCC) {\r
-            return res;\r
-        }\r
-    }\r
-    return res;\r
-}\r
-#endif /* #if (CONFIG_NV_SUPPORT_BACKUP_RESTORE == NV_YES) */\r
-\r
-\r
-/* Top level function used to mark a single key in a store as invalid (and hence erased) */\r
-/* Will actually scan a store for all keys matching the specified key_id, to ensure they are all marked as erased */\r
-errcode_t kv_update_erase_key(kv_store_t core, flash_task_node *sanitised_tasks)\r
-{\r
-    if (!active_state_machine()) {\r
-        g_current_store = core;\r
-\r
-        /* Configure search filter to obtain all valid instances of a specific key_id */\r
-        g_search_filter.pattern = sanitised_tasks->data.kv_erase.key;\r
-        g_search_filter.mask = 0xFFFF;\r
-        g_search_filter.state = KV_KEY_FILTER_STATE_VALID;\r
-        g_search_filter.type = KV_KEY_FILTER_TYPE_ANY;\r
-        g_search_filter.location = 0;\r
-\r
-        /* Queue Erase Keys state machine for processing */\r
-        begin_state_machine(&g_erase_keys_machine);\r
-    }\r
-\r
-    /* Run state machine until it is either suspended (yielding due to flash contention) or */\r
-    /* completed (either successfully or otherwise)                                         */\r
-    sanitised_tasks->state_code = determine_flash_task_state_code(process_state_machine());\r
-#ifdef CONFIG_NV_SUPPORT_SINGLE_CORE_SYSTEM\r
-    if (sanitised_tasks->state_code == FLASH_TASK_COMPLETED) {\r
-        return ERRCODE_SUCC;\r
-    } else {\r
-        return (errcode_t)sanitised_tasks->state_code;\r
-    }\r
-#else\r
-    return ERRCODE_SUCC;\r
-#endif\r
-}\r
-\r
-/* Top level function to write a new key or modify an existing key-value */\r
-/* Will cause a new instance of the key to be generated */\r
-errcode_t kv_update_write_key(kv_store_t core, flash_task_node *sanitised_task)\r
-{\r
-    if (!active_state_machine()) {\r
-        g_current_store = core;\r
-\r
-        /* Log details of new key to be written */\r
-        g_new_key_details.key_id = sanitised_task->data.kv.key;\r
-        g_new_key_details.kvalue = sanitised_task->data.kv.kvalue;\r
-        g_new_key_details.kvalue_length = sanitised_task->data.kv.kvalue_length;\r
-        g_new_key_details.attributes = sanitised_task->data.kv.attribute;\r
-        g_new_key_details.focre_write = sanitised_task->data.kv.force_write;\r
-\r
-        /* Queue Write Key state machine for processing */\r
-        begin_state_machine(&g_write_key_machine);\r
-    }\r
-\r
-    /* Run state machine until it is either suspended (yielding due to flash contention) or */\r
-    /* completed (either successfully or otherwise)                                         */\r
-    sanitised_task->state_code = determine_flash_task_state_code(process_state_machine());\r
-#ifdef CONFIG_NV_SUPPORT_SINGLE_CORE_SYSTEM\r
-    if (sanitised_task->state_code == FLASH_TASK_COMPLETED) {\r
-        return ERRCODE_SUCC;\r
-    } else {\r
-        return (errcode_t)sanitised_task->state_code;\r
-    }\r
-#else\r
-    return ERRCODE_SUCC;\r
-#endif\r
-}\r
-\r
-/* Modify the attribute on an existing key-value */\r
-/* Top level function to modify the attributes of an existing key */\r
-/* Will cause a new instance of the key to be generated */\r
-/* Existing key attributes will be maintained */\r
-errcode_t kv_update_modify_attribute(kv_store_t core, flash_task_node *sanitised_task)\r
-{\r
-    uint8_t *old_kvalue = NULL;\r
-    errcode_t res;\r
-    if (!active_state_machine()) {\r
-        g_current_store = core;\r
-        /* Log details of *additional* attributes to be applied to an existing key */\r
-        g_new_key_details.key_id = sanitised_task->data.kv_attribute.key;\r
-        g_new_key_details.kvalue = NULL;\r
-        g_new_key_details.kvalue_length = 0;\r
-        g_new_key_details.attributes = sanitised_task->data.kv_attribute.attribute;\r
-        g_new_key_details.focre_write = false;\r
-\r
-        res = kv_update_helper_get_current_key(&old_kvalue, &g_new_key_details.kvalue_length);\r
-        if (res != ERRCODE_SUCC) {\r
-            return res;\r
-        }\r
-        g_new_key_details.kvalue = old_kvalue;\r
-        /* Queue Modify Key state machine for processing */\r
-        begin_state_machine(&g_write_key_machine);\r
-    }\r
-\r
-    /* Run state machine until it is either suspended (yielding due to flash contention) or */\r
-    /* completed (either successfully or otherwise)                                         */\r
-    sanitised_task->state_code = determine_flash_task_state_code(process_state_machine());\r
-#ifdef CONFIG_NV_SUPPORT_SINGLE_CORE_SYSTEM\r
-    kv_free((void *)old_kvalue);\r
-    if (sanitised_task->state_code == FLASH_TASK_COMPLETED) {\r
-        return ERRCODE_SUCC;\r
-    } else {\r
-        return (errcode_t)sanitised_task->state_code;\r
-    }\r
-#else\r
-    if (sanitised_task->state_code != FLASH_TASK_BEING_PROCESSED) {\r
-        kv_free((void *)old_kvalue);\r
-    }\r
-    return ERRCODE_SUCC;\r
-#endif\r
-}\r
-\r
+/*
+ * Copyright (c) @CompanyNameMagicTag 2019-2022. All rights reserved.
+ * Description: KV Storage Library flash updating module implementation
+ */
+
+#include "nv_update.h"
+#include "nv_store.h"
+#include "nv_page.h"
+#include "nv_key.h"
+#include "nv_porting.h"
+#include "nv_config.h"
+#include "nv_reset.h"
+#include "nv_nvregion.h"
+#if defined(CONFIG_PARTITION_FEATURE_SUPPORT)
+#include "partition.h"
+#endif
+#include "assert.h"
+#include "common_def.h"
+#include "uapi_crc.h"
+#ifndef CONFIG_NV_SUPPORT_SINGLE_CORE_SYSTEM
+#include "flash_task_mutex.h"
+#include "flash_task_adapt.h"
+#endif
+
+#define KV_WRITE_KEY_BUFFER_SIZE    NV_KEY_DATA_CHUNK_LEN
+#define KV_WRITE_CHUNK_SIZE         32
+
+#define assert__(x)        ((void)0)
+
+/* Pointer to current state machine being processed.
+ * Will point to the last instance in a list of kv_active_state_machine_t, or NULL if
+ * no state machine is being processed */
+STATIC kv_active_state_machine_t *g_current_state_machine = NULL;
+
+/* Holds a search filter being used by searching operations performed by state machines */
+STATIC kv_key_filter_t g_search_filter;
+
+/* Holds details of key data to be written to a store */
+STATIC kv_key_details_t g_new_key_details;
+
+/* The key within a KV store begin accessed by a state machine */
+STATIC kv_key_handle_t g_current_key;
+
+/* The flash page within a KV store begin accessed by a state machine */
+STATIC kv_page_handle_t g_current_page;
+
+/* The KV store begin accessed by a state machine */
+STATIC kv_store_t g_current_store;
+
+/* The position in a flash page where a new key will be written */
+STATIC kv_key_location g_current_store_write_location;
+
+/* Memory address of flash page being used to defrag an existing page into */
+STATIC kv_page_location g_defrag_page_location = NULL;
+
+
+STATIC errcode_t kv_create_write_buffer(uint32_t write_location, uint32_t size);
+STATIC void kv_remove_write_buffer(void);
+STATIC kv_managed_source_buffer_t* kv_update_source_buffer(uint8_t *data, uint32_t data_length);
+STATIC void kv_remove_source_buffer(void);
+STATIC void kv_release_crypto(void);
+STATIC errcode_t begin_state_machine(const kv_state_machine_t *machine);
+STATIC void end_state_machine(void);
+
+/* State machine action functions */
+STATIC kv_update_event_t kv_update_action_store_write_buffer(void);
+STATIC kv_update_event_t kv_update_action_prime_write_buffer(void);
+
+STATIC kv_update_event_t kv_update_action_select_first_page(void);
+STATIC kv_update_event_t kv_update_action_select_next_page(void);
+STATIC kv_update_event_t kv_update_action_find_first_key(void);
+STATIC kv_update_event_t kv_update_action_find_next_key(void);
+STATIC kv_update_event_t kv_update_action_prepare_delete_key(void);
+
+STATIC kv_update_event_t kv_update_action_find_defrag_page(void);
+STATIC kv_update_event_t kv_update_action_erase_defrag_page(void);
+STATIC kv_update_event_t kv_update_action_prepare_copy_key(void);
+
+STATIC kv_update_event_t kv_update_action_prepare_defrag_page(void);
+STATIC kv_update_event_t kv_update_action_copy_all_keys(void);
+STATIC kv_update_event_t kv_update_action_prepare_page_header(void);
+STATIC kv_update_event_t kv_update_action_find_write_position(void);
+STATIC kv_update_event_t kv_update_action_defrag_current_page(void);
+STATIC kv_update_event_t kv_update_action_update_nvregion_map(void);
+
+STATIC kv_update_event_t kv_update_action_prepare_store(void);
+STATIC kv_update_event_t kv_update_action_prepare_write_key(void);
+STATIC kv_update_event_t kv_update_action_claim_crypto(void);
+STATIC kv_update_event_t kv_update_action_erase_old_keys(void);
+
+STATIC kv_update_event_t kv_update_action_update_nvmap_for_erase_key(void);
+STATIC kv_update_event_t kv_update_action_update_nvmap_for_new_key(void);
+
+
+/* State machine to iterate through keys in a store marking all keys as erased
+ * - Uses a pre-configured filter to determine which keys to select for erasing
+ */
+static const kv_update_transition_t g_erase_keys_transitions[] = {
+    {.state = STATE_SELECT_FIRST_PAGE,  .event = EVENT_PAGE_SELECTED,       .next_state = STATE_FIND_FIRST_KEY  },
+    {.state = STATE_SELECT_FIRST_PAGE,  .event = EVENT_PAGE_NOT_SELECTED,   .next_state = STATE_EXIT            },
+    {.state = STATE_SELECT_NEXT_PAGE,   .event = EVENT_PAGE_SELECTED,       .next_state = STATE_FIND_FIRST_KEY  },
+    {.state = STATE_SELECT_NEXT_PAGE,   .event = EVENT_PAGE_NOT_SELECTED,   .next_state = STATE_EXIT            },
+    {.state = STATE_FIND_FIRST_KEY,     .event = EVENT_KEY_FOUND,           .next_state = STATE_PREP_DELETE_KEY },
+    {.state = STATE_FIND_FIRST_KEY,     .event = EVENT_KEY_NOT_FOUND,       .next_state = STATE_SELECT_NEXT_PAGE},
+    {.state = STATE_FIND_NEXT_KEY,      .event = EVENT_KEY_FOUND,           .next_state = STATE_PREP_DELETE_KEY },
+    {.state = STATE_FIND_NEXT_KEY,      .event = EVENT_KEY_NOT_FOUND,       .next_state = STATE_SELECT_NEXT_PAGE},
+    {.state = STATE_PREP_DELETE_KEY,    .event = EVENT_WRITE_BUFFER_PRIMED, .next_state = STATE_PERFORM_WRITE   },
+    {.state = STATE_PERFORM_WRITE,      .event = EVENT_WRITE_BUFFER_STORED, .next_state = STATE_UPDATE_MAP_FOR_OLD },
+    {.state = STATE_UPDATE_MAP_FOR_OLD, .event = EVENT_PAGE_MAP_UPDATED,    .next_state = STATE_FIND_NEXT_KEY   },
+    {.state = STATE_PERFORM_WRITE,      .event = EVENT_SUSPEND,             .next_state = STATE_SUSPENDED       },
+    {.state = STATE_EXIT,               .event = EVENT_NONE,                .next_state = STATE_EXIT            }
+};
+static const kv_update_action_t g_erase_keys_actions[] = {
+    {.state = STATE_SELECT_FIRST_PAGE,  .action = kv_update_action_select_first_page },
+    {.state = STATE_SELECT_NEXT_PAGE,   .action = kv_update_action_select_next_page  },
+    {.state = STATE_FIND_FIRST_KEY,     .action = kv_update_action_find_first_key    },
+    {.state = STATE_FIND_NEXT_KEY,      .action = kv_update_action_find_next_key     },
+    {.state = STATE_PREP_DELETE_KEY,    .action = kv_update_action_prepare_delete_key},
+    {.state = STATE_PERFORM_WRITE,      .action = kv_update_action_store_write_buffer},
+    {.state = STATE_UPDATE_MAP_FOR_OLD, .action = kv_update_action_update_nvmap_for_erase_key},
+    {.state = STATE_EXIT,               .action = NULL                            }
+};
+static const kv_state_machine_t g_erase_keys_machine = {
+    .initial_state     = STATE_SELECT_FIRST_PAGE,
+    .resume_state      = STATE_PERFORM_WRITE,
+    .exit_event        = EVENT_KEYS_ERASED,
+    .transition_table  = g_erase_keys_transitions,
+    .action_table      = g_erase_keys_actions,
+    .write_buffer_size = sizeof(uint32_t)
+};
+
+/*
+ * State machine to locate a defrag page
+ * - Scans NV Region for an unused page of flash
+ * - Sets g_defrag_page_location to point the unused flash page, thus declaring it to be the current defrag page
+ * - Ensures defrag page is erased
+ */
+static const kv_update_transition_t g_prep_defrag_page_transitions[] = {
+    {.state = STATE_FIND_DEFRAG,  .event = EVENT_DEFRAG_FOUND,  .next_state = STATE_ERASE_DEFRAG},
+    {.state = STATE_ERASE_DEFRAG, .event = EVENT_DEFRAG_ERASED, .next_state = STATE_EXIT        },
+    {.state = STATE_ERASE_DEFRAG, .event = EVENT_SUSPEND,       .next_state = STATE_SUSPENDED   },
+    {.state = STATE_EXIT,         .event = EVENT_NONE,          .next_state = STATE_EXIT        }
+};
+static const kv_update_action_t g_prep_defrag_page_actions[] = {
+    {.state = STATE_FIND_DEFRAG,  .action = kv_update_action_find_defrag_page },
+    {.state = STATE_ERASE_DEFRAG, .action = kv_update_action_erase_defrag_page},
+    {.state = STATE_EXIT,         .action = NULL                           }
+};
+static const kv_state_machine_t g_prep_defrag_page_machine = {
+    .initial_state     = STATE_FIND_DEFRAG,
+    .resume_state      = STATE_ERASE_DEFRAG,
+    .exit_event        = EVENT_DEFRAG_PREPARED,
+    .transition_table  = g_prep_defrag_page_transitions,
+    .action_table      = g_prep_defrag_page_actions,
+    .write_buffer_size = 0
+};
+
+/*
+ * State machine to copy keys from the current page to the defrag page.
+ * Keys to copy are selected by a pre-configured filter, contained in g_search_filter
+ * Current page identified by g_current_page
+ * Defrag page identified by g_defrag_page_location
+ */
+static const kv_update_transition_t g_copy_all_keys_transitions[] = {
+    {.state = STATE_FIND_FIRST_KEY, .event = EVENT_KEY_FOUND,            .next_state = STATE_PREP_COPY_KEY  },
+    {.state = STATE_FIND_FIRST_KEY, .event = EVENT_KEY_NOT_FOUND,        .next_state = STATE_EXIT           },
+    {.state = STATE_FIND_NEXT_KEY,  .event = EVENT_KEY_FOUND,            .next_state = STATE_PREP_COPY_KEY  },
+    {.state = STATE_FIND_NEXT_KEY,  .event = EVENT_KEY_NOT_FOUND,        .next_state = STATE_EXIT           },
+    {.state = STATE_PREP_COPY_KEY,  .event = EVENT_COPY_KEY_READY,       .next_state = STATE_PRIME_WRITE    },
+    {.state = STATE_PRIME_WRITE,    .event = EVENT_WRITE_BUFFER_PRIMED,  .next_state = STATE_PERFORM_WRITE  },
+    {.state = STATE_PRIME_WRITE,    .event = EVENT_WRITE_DATA_EXHAUSTED, .next_state = STATE_FIND_NEXT_KEY  },
+    {.state = STATE_PERFORM_WRITE,  .event = EVENT_WRITE_BUFFER_STORED,  .next_state = STATE_PRIME_WRITE    },
+    {.state = STATE_PERFORM_WRITE,  .event = EVENT_SUSPEND,              .next_state = STATE_SUSPENDED      },
+    {.state = STATE_EXIT,           .event = EVENT_NONE,                 .next_state = STATE_EXIT           }
+};
+static const kv_update_action_t g_copy_all_keys_actions[] = {
+    {.state = STATE_FIND_FIRST_KEY, .action = kv_update_action_find_first_key    },
+    {.state = STATE_FIND_NEXT_KEY,  .action = kv_update_action_find_next_key     },
+    {.state = STATE_PREP_COPY_KEY,  .action = kv_update_action_prepare_copy_key  },
+    {.state = STATE_PRIME_WRITE,    .action = kv_update_action_prime_write_buffer},
+    {.state = STATE_PERFORM_WRITE,  .action = kv_update_action_store_write_buffer},
+    {.state = STATE_EXIT,           .action = NULL                            }
+};
+static const kv_state_machine_t g_copy_all_keys_machine = {
+    .initial_state     = STATE_FIND_FIRST_KEY,
+    .resume_state      = STATE_PERFORM_WRITE,
+    .exit_event        = EVENT_ALL_KEYS_COPIED,
+    .transition_table  = g_copy_all_keys_transitions,
+    .action_table      = g_copy_all_keys_actions,
+    .write_buffer_size = KV_WRITE_KEY_BUFFER_SIZE
+};
+
+/*
+ * State machine to defrag a store page
+ * Makes use of the g_prep_defrag_page_machine state machine
+ * Makes use of the g_copy_all_keys_machine state machine
+ * - Locates an unused flash page in the NV Region and erased it
+ * - Copies valid keys from page being defragged to the new page
+ * - Writes an updated page header to top of the new page, so that it supercedes the recently defragged page
+ */
+static const kv_update_transition_t g_defrag_page_transitions[] = {
+    {.state = STATE_PREP_DEFRAG,         .event = EVENT_DEFRAG_PREPARED,      .next_state = STATE_COPY_ALL_KEYS      },
+    {.state = STATE_COPY_ALL_KEYS,       .event = EVENT_ALL_KEYS_COPIED,      .next_state = STATE_PREP_PAGE_HEADER   },
+    {.state = STATE_PREP_PAGE_HEADER,    .event = EVENT_WRITE_BUFFER_PRIMED,  .next_state = STATE_WRITE_PAGE_HEADER  },
+    {.state = STATE_WRITE_PAGE_HEADER,   .event = EVENT_WRITE_BUFFER_STORED,  .next_state = STATE_UPDATE_NVREGION_MAP},
+    {.state = STATE_WRITE_PAGE_HEADER,   .event = EVENT_SUSPEND,              .next_state = STATE_SUSPENDED          },
+    {.state = STATE_UPDATE_NVREGION_MAP, .event = EVENT_NVREGION_MAP_UPDATED, .next_state = STATE_EXIT               },
+    {.state = STATE_EXIT,                .event = EVENT_NONE,                 .next_state = STATE_EXIT               }
+};
+static const kv_update_action_t g_defrag_page_actions[] = {
+    {.state = STATE_PREP_DEFRAG,         .action = kv_update_action_prepare_defrag_page},
+    {.state = STATE_COPY_ALL_KEYS,       .action = kv_update_action_copy_all_keys      },
+    {.state = STATE_PREP_PAGE_HEADER,    .action = kv_update_action_prepare_page_header},
+    {.state = STATE_WRITE_PAGE_HEADER,   .action = kv_update_action_store_write_buffer },
+    {.state = STATE_UPDATE_NVREGION_MAP, .action = kv_update_action_update_nvregion_map},
+    {.state = STATE_EXIT,                .action = NULL                             }
+};
+static const kv_state_machine_t g_defrag_page_machine = {
+    .initial_state     = STATE_PREP_DEFRAG,
+    .resume_state      = STATE_WRITE_PAGE_HEADER,
+    .exit_event        = EVENT_DEFRAG_COMPLETE,
+    .transition_table  = g_defrag_page_transitions,
+    .action_table      = g_defrag_page_actions,
+    .write_buffer_size = sizeof(kv_page_header_t)
+};
+
+/*
+ * State machine to prepare a store for writing a key
+ * May make use of the g_defrag_page_machine state machine
+ * - Selects a suitable page in a store for receiving a key
+ * - Kicks off a defrag of the selected page if necessary
+ */
+static const kv_update_transition_t g_prepare_store_transitions[] = {
+    {.state = STATE_FIND_WRITE_POS, .event = EVENT_DEFRAG_REQUIRED, .next_state = STATE_DEFRAG_PAGE   },
+    {.state = STATE_FIND_WRITE_POS, .event = EVENT_WRITE_POS_FOUND, .next_state = STATE_EXIT          },
+    {.state = STATE_DEFRAG_PAGE,    .event = EVENT_DEFRAG_COMPLETE, .next_state = STATE_FIND_WRITE_POS},
+    {.state = STATE_EXIT,           .event = EVENT_NONE,            .next_state = STATE_EXIT          }
+};
+static const kv_update_action_t g_prepare_store_actions[] = {
+    {.state = STATE_FIND_WRITE_POS, .action = kv_update_action_find_write_position},
+    {.state = STATE_DEFRAG_PAGE,    .action = kv_update_action_defrag_current_page},
+    {.state = STATE_EXIT,           .action = NULL                             }
+};
+STATIC const kv_state_machine_t g_prepare_store_machine = {
+    .initial_state     = STATE_FIND_WRITE_POS,
+    .resume_state      = STATE_INVALID,
+    .exit_event        = EVENT_STORE_READY,
+    .transition_table  = g_prepare_store_transitions,
+    .action_table      = g_prepare_store_actions,
+    .write_buffer_size = 0
+};
+
+/*
+ * State machine to write a key to a store
+ * Makes use of the g_prepare_store_machine state machine
+ */
+static const kv_update_transition_t g_write_key_transitions[] = {
+    {.state = STATE_PREP_STORE,         .event = EVENT_STORE_READY,           .next_state = STATE_PREP_KEY_DATA     },
+    {.state = STATE_PREP_KEY_DATA,      .event = EVENT_KEY_UPDATE_NOT_NEEDED, .next_state = STATE_EXIT              },
+    {.state = STATE_PREP_KEY_DATA,      .event = EVENT_KEY_DATA_READY,        .next_state = STATE_CLAIM_CRYPTO      },
+    {.state = STATE_CLAIM_CRYPTO,       .event = EVENT_CRYPTO_CLAIMED,        .next_state = STATE_PRIME_WRITE       },
+    {.state = STATE_PRIME_WRITE,        .event = EVENT_WRITE_BUFFER_PRIMED,   .next_state = STATE_PERFORM_WRITE     },
+    {.state = STATE_PRIME_WRITE,        .event = EVENT_WRITE_DATA_EXHAUSTED,  .next_state = STATE_UPDATE_MAP_FOR_NEW},
+    {.state = STATE_UPDATE_MAP_FOR_NEW, .event = EVENT_PAGE_MAP_UPDATED,      .next_state = STATE_ERASE_OLD_KEYS    },
+    {.state = STATE_PERFORM_WRITE,      .event = EVENT_WRITE_BUFFER_STORED,   .next_state = STATE_PRIME_WRITE       },
+    {.state = STATE_PERFORM_WRITE,      .event = EVENT_SUSPEND,               .next_state = STATE_SUSPENDED         },
+    {.state = STATE_ERASE_OLD_KEYS,     .event = EVENT_KEYS_ERASED,           .next_state = STATE_EXIT              },
+    {.state = STATE_EXIT,               .event = EVENT_NONE,                  .next_state = STATE_EXIT              }
+};
+static const kv_update_action_t g_write_key_actions[] = {
+    {.state = STATE_PREP_STORE,         .action = kv_update_action_prepare_store     },
+    {.state = STATE_PREP_KEY_DATA,      .action = kv_update_action_prepare_write_key },
+    {.state = STATE_CLAIM_CRYPTO,       .action = kv_update_action_claim_crypto      },
+    {.state = STATE_PRIME_WRITE,        .action = kv_update_action_prime_write_buffer},
+    {.state = STATE_PERFORM_WRITE,      .action = kv_update_action_store_write_buffer},
+    {.state = STATE_UPDATE_MAP_FOR_NEW, .action = kv_update_action_update_nvmap_for_new_key},
+    {.state = STATE_ERASE_OLD_KEYS,     .action = kv_update_action_erase_old_keys    },
+    {.state = STATE_EXIT,               .action = NULL                            }
+};
+static const kv_state_machine_t g_write_key_machine = {
+    .initial_state     = STATE_PREP_STORE,
+    .resume_state      = STATE_CLAIM_CRYPTO,
+    .exit_event        = EVENT_WRITE_COMPLETE,
+    .transition_table  = g_write_key_transitions,
+    .action_table      = g_write_key_actions,
+    .write_buffer_size = KV_WRITE_KEY_BUFFER_SIZE
+};
+
+/* Attempts to write all data in a write buffer to flash */
+STATIC kv_update_event_t kv_update_action_store_write_buffer(void)
+{
+    errcode_t ret;
+    uint32_t read_location;
+    uint32_t write_length;
+    uint32_t written;
+
+    kv_managed_write_buffer_t *write_buffer = g_current_state_machine->write_buffer;
+
+    /* Skip over section of write buffer that has already been written, due to being suspended */
+    if (write_buffer->write_location < write_buffer->resume_location) {
+        uint32_t data_already_written = write_buffer->resume_location - write_buffer->write_location;
+        if (data_already_written > write_buffer->data_length) {
+            data_already_written = write_buffer->data_length;
+        }
+        write_buffer->data_consumed += (uint16_t)data_already_written;
+        write_buffer->write_location += data_already_written;
+    }
+
+    /* Attempt to write chunks of data from the write_buffer to flash */
+    while (write_buffer->data_consumed < write_buffer->data_length) {
+        /* Determine size and position of chunk to write */
+        read_location = (uint32_t)(uintptr_t)write_buffer->data + write_buffer->data_consumed;
+        write_length = uapi_min(KV_WRITE_CHUNK_SIZE, write_buffer->data_length - write_buffer->data_consumed);
+
+        /* Attempt to write chunk */
+        ret = kv_key_write_flash(write_buffer->write_location, write_length, (uint8_t *)(uintptr_t)read_location);
+        if (ret == ERRCODE_SUCC) {
+            written = write_length;
+        } else {
+            written = 0;
+        }
+        write_buffer->data_consumed += (uint16_t)written;
+        /* Update write position, automatically allowing for subsequent writes to occur sequentially in flash */
+        write_buffer->write_location += written;
+        if (written < write_length) {
+            /* Write was aborted early */
+            write_buffer->resume_location = write_buffer->write_location;
+            return EVENT_SUSPEND;
+        }
+    }
+    /* Write completed */
+    return EVENT_WRITE_BUFFER_STORED;
+}
+STATIC errcode_t kv_update_hash_encrypt_chunk(kv_managed_write_buffer_t *write_buffer,
+    const kv_managed_source_buffer_t *source_buffer, uint32_t chunk_dest, uint32_t chunk_len)
+{
+    /* Need to cal CRC? */
+    errcode_t ret = ERRCODE_SUCC;
+    if (source_buffer->crc_data) {
+        if (!write_buffer->crc_claimed) {
+            return ERRCODE_NV_HASH_UNAVAILABLE;
+        }
+        write_buffer->crc_ret = uapi_crc32(write_buffer->crc_ret, (const uint8_t *)(uintptr_t)chunk_dest,
+                                           chunk_len);
+    }
+
+#if (CONFIG_NV_SUPPORT_ENCRYPT == NV_YES)
+    /* Need to hash data? */
+    if (source_buffer->hash_data) {
+        if (!write_buffer->hash_claimed) {
+            return ERRCODE_NV_HASH_UNAVAILABLE;
+        }
+        nv_crypto_update_hash((const uint8_t *)(uintptr_t)chunk_dest, chunk_len);
+    }
+
+    /* Need to encrypt data? */
+    if (source_buffer->encrypt_data) {
+        if (!write_buffer->encrypt_claimed) {
+            return ERRCODE_NV_AES_UNAVAILABLE;
+        }
+
+        ret = nv_crypto_encode(write_buffer->crypto_handle, (uintptr_t)chunk_dest, (uintptr_t)chunk_dest, chunk_len);
+    }
+
+    if (source_buffer->gcm_tag_data || source_buffer->hash_data) {
+        if ((source_buffer->gcm_tag_data && !write_buffer->gcm_tag_claimed) ||
+            (source_buffer->hash_data && !write_buffer->hash_claimed)) {
+            return ERRCODE_NV_HASH_UNAVAILABLE;
+        }
+        write_buffer->crc_ret = uapi_crc32(write_buffer->crc_ret, (const uint8_t *)(uintptr_t)chunk_dest,
+                                           chunk_len);
+    }
+#endif
+    return ret;
+}
+
+/* Copy data from the selected source buffer to the write_buffer, hashing and encrypting the data as necessary */
+STATIC errcode_t prime_next_chunk(void)
+{
+    kv_managed_source_buffer_t *source_buffer = g_current_state_machine->current_source;
+    kv_managed_write_buffer_t *write_buffer = g_current_state_machine->write_buffer;
+
+    uint32_t remaining_dest_space = write_buffer->size - write_buffer->data_length;
+    uint32_t remaining_src_data = source_buffer->data_length - source_buffer->data_consumed;
+    uint16_t chunk_len = (uint16_t)uapi_min(remaining_dest_space, remaining_src_data);
+
+    uint32_t chunk_dest = (uint32_t)(uintptr_t)write_buffer->data + write_buffer->data_length;
+    uint32_t chunk_src = (uint32_t)(uintptr_t)source_buffer->data + source_buffer->data_consumed;
+
+    if (source_buffer->encrypt_data) {
+        /* For encrypted data, the length of each operation is the same as that of NV reading.
+         * CNCommont: 对于加密数据,每次操作的数据长度与读NV时保持一致(KEY_DATA_CHUNK_LEN),因此当write_buffer剩余空间
+         * 小于KEY_DATA_CHUNK_LEN时,暂不处理.
+         */
+        chunk_len = (uint16_t)uapi_min(chunk_len, NV_KEY_DATA_CHUNK_LEN);
+        if (remaining_dest_space < NV_KEY_DATA_CHUNK_LEN) {
+            return ERRCODE_NV_BUFFER_PRIMED_PREMATURELY;
+        }
+    }
+
+    kv_attributes_t attributes = (source_buffer->encrypt_data) ? KV_ATTRIBUTE_ENCRYPTED : 0;
+    if (remaining_dest_space < kv_key_padded_data_length(attributes, chunk_len)) {
+        /* Not enough space for padded data, exit early and write what we have */
+        return ERRCODE_NV_BUFFER_PRIMED_PREMATURELY;
+    }
+
+    /* Copy a chunk of source_buffer data to write buffer */
+    if ((chunk_src >= FLASH_PHYSICAL_ADDR_START) &&
+        (chunk_src + chunk_len) <= FLASH_PHYSICAL_ADDR_END) {
+        /* Source buffer is referencing data in Flash */
+        errcode_t res = kv_key_helper_copy_flash(chunk_dest, chunk_src, chunk_len);
+        if (res != ERRCODE_SUCC) {
+            return res;
+        }
+    } else {
+        int32_t result;
+        /* Source buffer is referencing data in RAM */
+        result = memcpy_s((void *)(uintptr_t)chunk_dest, remaining_dest_space,
+                          (const void *)(uintptr_t)chunk_src, chunk_len);
+        if (result != (int32_t)EOK) {
+            assert__(false);
+        }
+    }
+
+    /* Round chunk_len up to a multiple of 4 or 16 bytes, depending upon the encryption requirement */
+    /* We have already checked there is enough space in the write buffer                            */
+    chunk_len = kv_key_padded_data_length(attributes, chunk_len);
+
+    errcode_t hash_crypt_ret;
+    hash_crypt_ret = kv_update_hash_encrypt_chunk(write_buffer, source_buffer, chunk_dest, chunk_len);
+    if (hash_crypt_ret != ERRCODE_SUCC) {
+        return hash_crypt_ret;
+    }
+
+    write_buffer->data_length += chunk_len;
+    source_buffer->data_consumed += chunk_len;
+    return ERRCODE_SUCC;
+}
+
+/* Select next source buffer, filling it with a hash if required */
+STATIC errcode_t select_next_source_buffer(void)
+{
+    kv_managed_source_buffer_t *source_buffer = g_current_state_machine->current_source->next;
+    kv_managed_write_buffer_t *write_buffer = g_current_state_machine->write_buffer;
+
+    g_current_state_machine->current_source = source_buffer;
+
+    /* Has the next source_buffer buffer been designated to receive the hash calculation */
+    if ((source_buffer != NULL) && (source_buffer->receive_hash)) {
+        if (write_buffer->crc_claimed) {
+            if (source_buffer->data_length < KV_CRYPTO_CRC_SIZE) {
+                return ERRCODE_NV_KEY_HASH_BUFFER_TOO_SMALL;
+            }
+
+            write_buffer->crc_ret = kv_crc32_swap(write_buffer->crc_ret);
+            (void)memcpy_s((void *)source_buffer->data, KV_CRYPTO_CRC_SIZE, (const void *)&write_buffer->crc_ret,
+                KV_CRYPTO_CRC_SIZE);
+            write_buffer->crc_claimed = false;
+            source_buffer->data_length = KV_CRYPTO_CRC_SIZE;
+        }
+#if (CONFIG_NV_SUPPORT_ENCRYPT == NV_YES)
+        else if (write_buffer->hash_claimed) {
+            if (source_buffer->data_length < KV_CRYPTO_HASH_SIZE) {
+                return ERRCODE_NV_KEY_HASH_BUFFER_TOO_SMALL;
+            }
+            (void)memset_s(source_buffer->data,  source_buffer->data_length, 0, source_buffer->data_length);
+            nv_crypto_complete_hash(source_buffer->data);
+
+            write_buffer->crc_ret = kv_crc32_swap(write_buffer->crc_ret);
+            (void)memcpy_s((void *)(source_buffer->data + KV_CRYPTO_HASH_SIZE - KV_CRYPTO_CRC_SIZE),
+                KV_CRYPTO_CRC_SIZE, (const void *)&write_buffer->crc_ret, KV_CRYPTO_CRC_SIZE);
+
+            write_buffer->hash_claimed = false;
+            source_buffer->data_length = KV_CRYPTO_HASH_SIZE;
+        } else if (write_buffer->gcm_tag_claimed) {
+            uint32_t tag_len = NV_AES_GCM_TAG_LENGTH;
+            if (source_buffer->data_length < KV_CRYPTO_HASH_SIZE) {
+                return ERRCODE_NV_KEY_HASH_BUFFER_TOO_SMALL;
+            }
+
+            write_buffer->crc_ret = kv_crc32_swap(write_buffer->crc_ret);
+            memset_s(source_buffer->data, source_buffer->data_length, 0, source_buffer->data_length);
+
+            nv_crypto_get_tag(write_buffer->crypto_handle, source_buffer->data, &tag_len);
+
+            (void)memcpy_s((void *)(source_buffer->data + KV_CRYPTO_HASH_SIZE - KV_CRYPTO_CRC_SIZE),
+                KV_CRYPTO_CRC_SIZE, (const void *)&write_buffer->crc_ret, KV_CRYPTO_CRC_SIZE);
+
+            write_buffer->gcm_tag_claimed = false;
+            source_buffer->data_length = KV_CRYPTO_HASH_SIZE;
+        }
+#endif
+        else {
+            return ERRCODE_NV_HASH_UNAVAILABLE;
+        }
+    }
+
+    return ERRCODE_SUCC;
+}
+
+/* Gather data from one or more source buffers to fill write_buffer with more data ready for writing to flash */
+STATIC kv_update_event_t kv_update_action_prime_write_buffer(void)
+{
+    errcode_t res;
+
+    kv_managed_source_buffer_t *source_buffer = g_current_state_machine->current_source;
+    kv_managed_write_buffer_t *write_buffer = g_current_state_machine->write_buffer;
+
+    (void)memset_s(write_buffer->data, write_buffer->size, 0, write_buffer->size);
+
+    write_buffer->data_length = 0;
+    write_buffer->data_consumed = 0;
+
+    while ((source_buffer != NULL) && (write_buffer->data_length < write_buffer->size)) {
+        if (source_buffer->data_consumed < source_buffer->data_length) {
+            res = prime_next_chunk();
+            if (res == ERRCODE_NV_BUFFER_PRIMED_PREMATURELY) {
+                /* Not enough space for padded data so just write what we have for now */
+                break;
+            }
+            if (res != ERRCODE_SUCC) {
+                g_current_state_machine->error_code = res;
+                return EVENT_ERROR;
+            }
+        } else {
+            /* Select next source buffer */
+            res = select_next_source_buffer();
+            if (res != ERRCODE_SUCC) {
+                g_current_state_machine->error_code = res;
+                return EVENT_ERROR;
+            }
+            source_buffer = g_current_state_machine->current_source;
+        }
+    }
+
+    /* Did we manage to place any data in the write buffer? */
+    if (write_buffer->data_length == 0) {
+        kv_release_crypto();
+        return EVENT_WRITE_DATA_EXHAUSTED;
+    } else {
+        return EVENT_WRITE_BUFFER_PRIMED;
+    }
+}
+
+/*
+ * Attempts to obtain a handle to the first page of the g_current_store
+ * - g_current_page will be populated if a page is obtained
+ */
+STATIC kv_update_event_t kv_update_action_select_first_page(void)
+{
+    errcode_t res;
+
+    res = kv_store_get_page_handle(g_current_store, 0, &g_current_page);
+    if (res == ERRCODE_SUCC) {
+        return EVENT_PAGE_SELECTED;
+    }
+    return EVENT_PAGE_NOT_SELECTED;
+}
+
+/*
+ * Attempts to obtain a handle to the next page of the g_current_store, based on g_current_page
+ * - g_current_page will be updated if a page is obtained
+ */
+STATIC kv_update_event_t kv_update_action_select_next_page(void)
+{
+    errcode_t res;
+    uint32_t page_index;
+    if (kv_page_get_index(&g_current_page, &page_index) != ERRCODE_SUCC) {
+        return EVENT_PAGE_NOT_SELECTED;
+    }
+    page_index++;
+    if (page_index < kv_store_get_page_count(g_current_store)) {
+        res = kv_store_get_page_handle(g_current_store, page_index, &g_current_page);
+        if (res == ERRCODE_SUCC) {
+            return EVENT_PAGE_SELECTED;
+        }
+    }
+
+    return EVENT_PAGE_NOT_SELECTED;
+}
+
+/*
+ * Attempts to obtain the first key in the g_current_page, that conforms to g_search_filter
+ * - g_current_key will be populated if a key is obtained
+ */
+STATIC kv_update_event_t kv_update_action_find_first_key(void)
+{
+    errcode_t res;
+
+    res = kv_page_find_first_key(&g_current_page, &g_search_filter, &g_current_key);
+    while (res == ERRCODE_SUCC) {
+        if (g_current_key.key_location != g_search_filter.location) {
+            return EVENT_KEY_FOUND;
+        }
+        res = kv_page_find_next_key(&g_current_page, &g_search_filter, &g_current_key);
+    }
+    return EVENT_KEY_NOT_FOUND;
+}
+
+/*
+ * Attempts to obtain the next key in the g_current_page, based on g_current_key and that conforms to g_search_filter
+ * - g_current_key will be updated if a key is obtained
+ */
+STATIC kv_update_event_t kv_update_action_find_next_key(void)
+{
+    errcode_t res;
+
+    res = kv_page_find_next_key(&g_current_page, &g_search_filter, &g_current_key);
+    while (res == ERRCODE_SUCC) {
+        if (g_current_key.key_location != g_search_filter.location) {
+            return EVENT_KEY_FOUND;
+        }
+        res = kv_page_find_next_key(&g_current_page, &g_search_filter, &g_current_key);
+    }
+    return EVENT_KEY_NOT_FOUND;
+}
+
+/*
+ * Prepares the g_current_state_machine->write_buffer to mark g_current_key as invalid (and hence erased)
+ * Will not mark keys with the attribute KV_ATTRIBUTE_PERMANENT as invalid
+ */
+STATIC kv_update_event_t kv_update_action_prepare_delete_key(void)
+{
+    kv_managed_write_buffer_t *write_buffer = NULL;
+    kv_attributes_t attributes = kv_key_attributes(&g_current_key);
+    if (((uint32_t)attributes & (uint32_t)KV_ATTRIBUTE_PERMANENT) != 0  &&
+        (g_new_key_details.focre_write != true)) {
+        g_current_state_machine->error_code = ERRCODE_NV_TRYING_TO_MODIFY_A_PERMANENT_KEY;
+        return EVENT_ERROR;
+    }
+
+    write_buffer = g_current_state_machine->write_buffer;
+    if (write_buffer == NULL) {
+        g_current_state_machine->error_code = ERRCODE_NV_WRITE_BUFFER_NOT_ALLOCATED;
+        return EVENT_ERROR;
+    }
+    if (write_buffer->size < sizeof(uint32_t)) {
+        g_current_state_machine->error_code = ERRCODE_NV_WRITE_BUFFER_TOO_SMALL;
+        return EVENT_ERROR;
+    }
+
+    /* As only 4 bytes are being written, directly prime write buffer rather that setting up a source buffer */
+    *(uint32_t *)write_buffer->data = KV_KEY_INVALID;
+    write_buffer->data_consumed = 0;
+
+    if (g_nv_header_magic == KV_KEY_MAGIC) {
+        write_buffer->data_length = (uint16_t)sizeof(uint8_t);
+        /* Need to manually configure the write location for each key being deleted */
+        /* as they will not follow in an ordered sequence                           */
+        write_buffer->write_location = (uint32_t)(uintptr_t)((uint8_t *)g_current_key.key_location + sizeof(uint8_t));
+    } else {
+        write_buffer->data_length = (uint16_t)sizeof(uint16_t);
+        write_buffer->write_location = (uint32_t)(uintptr_t)g_current_key.key_location;
+    }
+
+    return EVENT_WRITE_BUFFER_PRIMED;
+}
+
+STATIC kv_update_event_t kv_update_action_prepare_copy_key(void)
+{
+    kv_managed_write_buffer_t *write_buffer = g_current_state_machine->write_buffer;
+    if (write_buffer == NULL) {
+        g_current_state_machine->error_code = ERRCODE_NV_WRITE_BUFFER_NOT_ALLOCATED;
+        return EVENT_ERROR;
+    }
+    if (write_buffer->write_location == 0) {
+        write_buffer->write_location = (uint32_t)(uintptr_t)g_defrag_page_location + (uint32_t)sizeof(kv_page_header_t);
+    }
+
+    /* Use a source buffer to manage copy progress of key data */
+    uint8_t *source = (uint8_t *)g_current_key.key_location;
+    uint16_t length = kv_key_flash_size(&g_current_key);
+    kv_managed_source_buffer_t *source_buffer = kv_update_source_buffer(source, length);
+    g_current_state_machine->current_source = source_buffer;  /* Point current source buffer at first buffer */
+    if (source_buffer == NULL) {
+        g_current_state_machine->error_code = ERRCODE_MALLOC;
+        return EVENT_ERROR;
+    }
+
+    return EVENT_COPY_KEY_READY;
+}
+
+/*
+ * Attempts to locate an unused page of flash, in the KV NV flash region, to use as the current defrag page
+ * g_defrag_page_location will be set to point to the unused flash page
+ */
+STATIC kv_update_event_t kv_update_action_find_defrag_page(void)
+{
+    errcode_t res;
+    g_defrag_page_location = NULL;
+    res = kv_nvregion_find_unused_page(&g_defrag_page_location);
+    if (res == ERRCODE_SUCC) {
+        nv_log_debug("[NV] found defrag_page. loc = 0x%x\r\n", g_defrag_page_location);
+        return EVENT_DEFRAG_FOUND;
+    } else {
+        g_current_state_machine->error_code = res;
+        return EVENT_ERROR;
+    }
+}
+
+/*
+ * Attempts to erase the current defrag page, as defined by g_defrag_page_location
+ */
+STATIC kv_update_event_t kv_update_action_erase_defrag_page(void)
+{
+    errcode_t res;
+    res = kv_nvregion_erase_page(g_defrag_page_location);
+    if (res == ERRCODE_SUCC) {
+        return EVENT_DEFRAG_ERASED;
+    } else if (res == ERRCODE_NV_WRITE_VETOED) {
+        return EVENT_SUSPEND;
+    } else {
+        g_current_state_machine->error_code = res;
+        return EVENT_ERROR;
+    }
+}
+
+/*
+ * Attempts to start the g_prep_defrag_page_machine state machine
+ */
+STATIC kv_update_event_t kv_update_action_prepare_defrag_page(void)
+{
+    errcode_t res = begin_state_machine(&g_prep_defrag_page_machine);
+    if (res == ERRCODE_SUCC) {
+        return EVENT_NONE;
+    } else {
+        g_current_state_machine->error_code = res;
+        return EVENT_ERROR;
+    }
+}
+
+/*
+ * Attempts to start the g_copy_all_keys_machine state machine
+ * Configures g_search_filter to find all valid (un-erased) keys
+ */
+STATIC kv_update_event_t kv_update_action_copy_all_keys(void)
+{
+    /* Configure search filter to copy all valid keys */
+    g_search_filter.pattern = 0;
+    g_search_filter.mask = 0;
+    g_search_filter.state = KV_KEY_FILTER_STATE_VALID;
+    g_search_filter.type = KV_KEY_FILTER_TYPE_ANY;
+    g_search_filter.location = 0;
+
+    errcode_t res = begin_state_machine(&g_copy_all_keys_machine);
+    if (res == ERRCODE_SUCC) {
+        return EVENT_NONE;
+    } else {
+        g_current_state_machine->error_code = res;
+        return EVENT_ERROR;
+    }
+}
+
+/*
+ * Prepares g_current_state_machine->write_buffer with information to construct a page header for the
+ * current defrag page, as defined by g_defrag_page_location
+ * All information is obtained from g_current_page
+ * The page sequence_number is updated to indicate that this page will supersede g_current_page
+ */
+STATIC kv_update_event_t kv_update_action_prepare_page_header(void)
+{
+    kv_managed_write_buffer_t *write_buffer = g_current_state_machine->write_buffer;
+    if (write_buffer == NULL) {
+        g_current_state_machine->error_code = ERRCODE_NV_WRITE_BUFFER_NOT_ALLOCATED;
+        return EVENT_ERROR;
+    }
+    write_buffer->write_location = (uint32_t)(uintptr_t)g_defrag_page_location;
+
+    if (memcpy_s(write_buffer->data, sizeof(kv_page_header_t), &g_current_page, sizeof(kv_page_header_t)) != EOK) {
+        return EVENT_ERROR;
+    }
+    write_buffer->data_length = (uint16_t)sizeof(kv_page_header_t);
+    write_buffer->data_consumed = 0;
+
+    /* Too specific, move to kv_page? */
+    kv_page_header_t *defrag_page_header = (kv_page_header_t *)write_buffer->data;
+    defrag_page_header->sequence_number++;
+    defrag_page_header->inverted_sequence_number = ~defrag_page_header->sequence_number;
+
+    return EVENT_WRITE_BUFFER_PRIMED;
+}
+
+/*
+ * Forces a re-scan of the KV NV flash region to update a map of KV pages
+ */
+STATIC kv_update_event_t kv_update_action_update_nvregion_map(void)
+{
+    errcode_t res;
+
+    res = kv_nvregion_scan();
+    if (res != ERRCODE_SUCC) {
+        g_current_state_machine->error_code = res;
+        return EVENT_ERROR;
+    }
+    return EVENT_NVREGION_MAP_UPDATED;
+}
+
+/*
+ * Attempts to find a suitable write location in g_current_store for g_new_key_details
+ * Will set g_current_store_write_location if enough space is found in g_current_store
+ * Will indicate that a defrag is required if there is not currently enough free space in g_current_store
+ * Will return an error if a defrag would not free up enough space for the new key
+ */
+STATIC kv_update_event_t kv_update_action_find_write_position(void)
+{
+    errcode_t res;
+    uint16_t required_space;
+    kv_key_handle_t new_key;
+    kv_page_status_t page_status;
+
+    /* Work out space needed for new key */
+    kv_key_build_from_new(&new_key, &g_new_key_details, 0);
+    required_space = kv_key_flash_size(&new_key);
+
+    res = kv_store_find_write_page(g_current_store, required_space, &g_current_page, &page_status);
+    if (res == ERRCODE_SUCC) {
+        g_current_store_write_location = (kv_key_location)(uintptr_t)page_status.first_writable_location;
+        return EVENT_WRITE_POS_FOUND;
+    } else if (res == ERRCODE_NV_DEFRAGMENTATION_NEEDED) {
+        return EVENT_DEFRAG_REQUIRED;
+    } else {
+        g_current_state_machine->error_code = res;
+        return EVENT_ERROR;
+    }
+}
+
+/*
+ * Attempts to start the g_defrag_page_machine state machine
+ */
+STATIC kv_update_event_t kv_update_action_defrag_current_page(void)
+{
+    errcode_t res = begin_state_machine(&g_defrag_page_machine);
+    if (res == ERRCODE_SUCC) {
+        return EVENT_NONE;
+    } else {
+        g_current_state_machine->error_code = res;
+        return EVENT_ERROR;
+    }
+}
+
+/*
+ * Attempts to start the g_prepare_store_machine state machine
+ */
+STATIC kv_update_event_t kv_update_action_prepare_store(void)
+{
+    errcode_t res = begin_state_machine(&g_prepare_store_machine);
+    if (res == ERRCODE_SUCC) {
+        return EVENT_NONE;
+    } else {
+        g_current_state_machine->error_code = res;
+        return EVENT_ERROR;
+    }
+}
+
+/*
+ * Configure write location for g_current_state_machine->write_buffer
+ * Attempt to allocate memory for AES Control data structure, if key data is to be encrypted
+ */
+STATIC kv_update_event_t kv_update_helper_prepare_write_buffer(void)
+{
+    kv_managed_write_buffer_t *write_buffer = g_current_state_machine->write_buffer;
+
+    if (write_buffer == NULL) {
+        g_current_state_machine->error_code = ERRCODE_NV_WRITE_BUFFER_NOT_ALLOCATED;
+        return EVENT_ERROR;
+    }
+    write_buffer->write_location = (uint32_t)(uintptr_t)g_current_store_write_location;
+    return EVENT_KEY_DATA_READY;
+}
+
+/*
+ * Attempt to allocate a kv_managed_source_buffer_t for a key header
+ */
+STATIC kv_update_event_t kv_update_helper_setup_key_header_source_buffer(void)
+{
+    kv_managed_source_buffer_t *source_buffer = NULL;
+
+    /* Setup source buffers for key header */
+    source_buffer = kv_update_source_buffer((uint8_t *)&g_current_key.header, sizeof(kv_key_header_t));
+    if (source_buffer == NULL) {
+        g_current_state_machine->error_code = ERRCODE_NV_KEY_HEADER_BUFFER_NOT_ALLOCATED;
+        return EVENT_ERROR;
+    }
+
+    if (((uint32_t)g_new_key_details.attributes & (uint32_t)KV_ATTRIBUTE_ENCRYPTED) != 0) {
+#if (CONFIG_NV_SUPPORT_HASH_FOR_CRYPT == NV_YES)
+        source_buffer->hash_data = true;
+#else
+        source_buffer->gcm_tag_data = true;
+#endif
+    } else {
+        source_buffer->crc_data = true;
+    }
+    source_buffer->encrypt_data = false;
+    return EVENT_KEY_DATA_READY;
+}
+
+/*
+ * Attempt to allocate a kv_managed_source_buffer_t for key data
+ */
+STATIC kv_update_event_t kv_update_helper_setup_key_data_source_buffer(bool release_key_data)
+{
+    kv_managed_source_buffer_t *source_buffer = NULL;
+
+    /* Setup source buffer for key data */
+    source_buffer = kv_update_source_buffer((uint8_t *)g_new_key_details.kvalue, g_new_key_details.kvalue_length);
+    if (source_buffer == NULL) {
+        g_current_state_machine->error_code = ERRCODE_NV_KEY_DATA_BUFFER_NOT_ALLOCATED;
+        return EVENT_ERROR;
+    }
+    source_buffer->release_data = release_key_data;
+
+    if (((uint32_t)g_new_key_details.attributes & (uint32_t)KV_ATTRIBUTE_ENCRYPTED) != 0) {
+#if (CONFIG_NV_SUPPORT_HASH_FOR_CRYPT == NV_YES)
+        source_buffer->hash_data = true;
+#else
+        source_buffer->gcm_tag_data = true;
+#endif
+    } else {
+        source_buffer->crc_data = true;
+    }
+    source_buffer->encrypt_data = (((uint32_t)g_new_key_details.attributes & (uint32_t)KV_ATTRIBUTE_ENCRYPTED) != 0);
+    return EVENT_KEY_DATA_READY;
+}
+
+/*
+ * Attempt to allocate a kv_managed_source_buffer_t for a key hash
+ * Will also attempt to allocate a buffer to contain the calculated hash
+ */
+STATIC kv_update_event_t kv_update_helper_setup_key_hash_source_buffer(void)
+{
+    uint8_t *key_hash = NULL;
+    kv_managed_source_buffer_t *source_buffer = NULL;
+    uint32_t hash_crc_len = 0;
+    if (((uint32_t)g_new_key_details.attributes & (uint32_t)KV_ATTRIBUTE_ENCRYPTED) != 0) {
+        hash_crc_len = KV_CRYPTO_HASH_SIZE;
+    } else {
+        hash_crc_len = KV_CRYPTO_CRC_SIZE;
+    }
+
+    /* Setup source buffer for key hash                                                               */
+    /* The hash is calculated while data is written to flash then placed into this buffer for writing */
+    key_hash = (uint8_t *)kv_malloc(hash_crc_len);
+    if (key_hash == NULL) {
+        g_current_state_machine->error_code = ERRCODE_MALLOC;
+        return EVENT_ERROR;
+    }
+    source_buffer = kv_update_source_buffer(key_hash, hash_crc_len);
+    if (source_buffer == NULL) {
+        kv_free(key_hash);
+        g_current_state_machine->error_code = ERRCODE_NV_KEY_HASH_BUFFER_NOT_ALLOCATED;
+        return EVENT_ERROR;
+    }
+    source_buffer->release_data = true;
+    source_buffer->receive_hash = true;
+    source_buffer->encrypt_data = false;
+    return EVENT_KEY_DATA_READY;
+}
+
+/*
+ * Prepare kv_managed_source_buffers for the three separate parts of a key i.e. header, data and hash
+ * Ensures state machine write buffer is ready to receive data for writing
+ * CNcomment: 准备好NV写入需要的source buffer,NV的三个部分(header、数据、HASH/CRC)被放置在三个source buffer中
+ */
+STATIC kv_update_event_t kv_update_helper_prepare_source_buffers(bool release_key_data)
+{
+    kv_update_event_t event;
+
+    event = kv_update_helper_prepare_write_buffer();
+    if (event == EVENT_KEY_DATA_READY) {
+        event = kv_update_helper_setup_key_header_source_buffer();
+    }
+    if (event == EVENT_KEY_DATA_READY) {
+        event = kv_update_helper_setup_key_data_source_buffer(release_key_data);
+    }
+    if ((event != EVENT_KEY_DATA_READY) && release_key_data) {
+        /* Ensure we release any new key data as it will not have been placed into a source buffer */
+        /* which get cleaned up automatically when a state machine ends                            */
+        kv_free((void *)g_new_key_details.kvalue);
+        g_new_key_details.kvalue = NULL;
+    }
+    if (event == EVENT_KEY_DATA_READY) {
+        event = kv_update_helper_setup_key_hash_source_buffer();
+    }
+    return event;
+}
+
+/*
+ * Checks if g_current_key would end up being modified by any changes detailed in g_new_key_details
+ * Will return an error if g_current_key is permanent
+ */
+STATIC kv_update_event_t kv_update_helper_check_for_key_updates(void)
+{
+    errcode_t res;
+    kv_attributes_t attributes = kv_key_attributes(&g_current_key);
+    if ((((uint32_t)attributes & (uint32_t)KV_ATTRIBUTE_PERMANENT) != 0) &&
+        (g_new_key_details.focre_write != true)) {
+        /* We can't modify permanent keys in any way */
+        g_current_state_machine->error_code = ERRCODE_NV_TRYING_TO_MODIFY_A_PERMANENT_KEY;
+        return EVENT_ERROR;
+    }
+    if (((uint32_t)attributes & (uint32_t)KV_ATTRIBUTE_NON_UPGRADE) !=
+        ((uint32_t)g_new_key_details.attributes & (uint32_t)KV_ATTRIBUTE_NON_UPGRADE)) {
+        /* Attributes are being updated */
+        return EVENT_KEY_UPDATE_REQUIRED;
+    }
+    if (((uint32_t)attributes & (uint32_t)g_new_key_details.attributes) != (uint32_t)g_new_key_details.attributes) {
+        /* Attributes are being updated */
+        return EVENT_KEY_UPDATE_REQUIRED;
+    }
+
+    if (g_current_key.header.length != g_new_key_details.kvalue_length) {
+        /* New data is of a different length */
+        return EVENT_KEY_UPDATE_REQUIRED;
+    }
+    res = kv_helper_compare_key_data(&g_current_key, g_new_key_details.kvalue,
+                                     (uint16_t)g_new_key_details.kvalue_length);
+    if (res != ERRCODE_SUCC) {
+        /* New data content is different */
+        return EVENT_KEY_UPDATE_REQUIRED;
+    }
+
+    /* Key not actually being updated */
+    return EVENT_KEY_UPDATE_NOT_NEEDED;
+}
+
+/*
+ * Constructs a new key header from g_new_key_details, copying the attributes of any existing key with the same key_id
+ * Updates g_current_key with details of the new key header
+ */
+STATIC kv_update_event_t kv_update_action_prepare_write_key(void)
+{
+    errcode_t res = kv_store_find_valid_key(g_current_store, g_new_key_details.key_id, &g_current_key);
+    if (res == ERRCODE_SUCC) {
+        kv_update_event_t event = kv_update_helper_check_for_key_updates();
+        if (event != EVENT_KEY_UPDATE_REQUIRED) {
+            nv_log_debug("[NV] The Key not need update. Key id = 0x%x\r\n", g_current_key.header.key_id);
+            return event;
+        }
+
+        /* Combine existing key attributes with those requested for the new key */
+        if (g_current_key.header.type != KV_KEY_TYPE_NORMAL) {
+            g_new_key_details.attributes = (kv_attributes_t)((uint32_t)g_new_key_details.attributes |
+                                                             (uint32_t)KV_ATTRIBUTE_PERMANENT);
+        }
+        if (g_current_key.header.enc_key != 0) {
+            g_new_key_details.attributes = (kv_attributes_t)((uint32_t)g_new_key_details.attributes |
+                                                             (uint32_t)KV_ATTRIBUTE_ENCRYPTED);
+        }
+    }
+
+    kv_key_build_from_new(&g_current_key, &g_new_key_details, g_current_store_write_location);
+    return kv_update_helper_prepare_source_buffers(false);
+}
+
+STATIC errcode_t kv_update_helper_get_current_key(uint8_t **old_kvalue, uint32_t *kvalue_length)
+{
+    kv_key_handle_t current_key;
+    errcode_t res;
+
+    res = kv_store_find_valid_key(g_current_store, g_new_key_details.key_id, &current_key);
+    if (res != ERRCODE_SUCC) {
+        return res;
+    }
+
+    kv_attributes_t attributes = kv_key_attributes(&current_key);
+    if (((uint32_t)attributes & KV_ATTRIBUTE_PERMANENT) != 0) {
+        return ERRCODE_SUCC;
+    }
+
+    if (((uint32_t)attributes & KV_ATTRIBUTE_ENCRYPTED) != 0) {
+        /* if old key is encrypted, the new key must be encrypted too */
+        g_new_key_details.attributes = (kv_attributes_t)((uint32_t)g_new_key_details.attributes |
+                                                         (uint32_t)KV_ATTRIBUTE_ENCRYPTED);
+    }
+
+    *kvalue_length = current_key.header.length;
+    *old_kvalue = (uint8_t *)kv_malloc(current_key.header.length);
+    if (*old_kvalue == NULL) {
+        return ERRCODE_MALLOC;
+    }
+
+    res = kv_key_read_data(&current_key, *old_kvalue);
+    if (res != ERRCODE_SUCC) {
+        kv_free((void *)*old_kvalue);
+    }
+    return res;
+}
+
+/*
+ * Attempt to claim access to hardware AES and hash functions
+ */
+STATIC kv_update_event_t kv_update_action_claim_crypto(void)
+{
+    kv_managed_write_buffer_t *write_buffer = g_current_state_machine->write_buffer;
+
+    /* Reset write location */
+    write_buffer->write_location = (uint32_t)(uintptr_t)g_current_key.key_location;
+
+    /* Point current source buffer at first buffer and reset data_consumed values */
+    g_current_state_machine->current_source = g_current_state_machine->source_buffer;
+    kv_managed_source_buffer_t *source_buffer = g_current_state_machine->source_buffer;
+    while (source_buffer != NULL) {
+        source_buffer->data_consumed = 0;
+        source_buffer = source_buffer->next;
+    }
+
+    write_buffer->crypto_handle = INVAILD_CRYPTO_HANDLE;
+
+    if (((uint32_t)g_new_key_details.attributes & (uint32_t)KV_ATTRIBUTE_ENCRYPTED) != 0) {
+#if (CONFIG_NV_SUPPORT_ENCRYPT == NV_YES)
+        /* Claim cryptographic engines */
+        if (!write_buffer->encrypt_claimed) {
+            errcode_t res = nv_crypto_claim_aes(&write_buffer->crypto_handle, &(g_current_key.header));
+            if (res != ERRCODE_SUCC) {
+                g_current_state_machine->error_code = res;
+                return EVENT_ERROR;
+            }
+            write_buffer->encrypt_claimed = true;
+        }
+
+#if (CONFIG_NV_SUPPORT_HASH_FOR_CRYPT == NV_YES)
+        if (!write_buffer->hash_claimed) {
+            errcode_t res = nv_crypto_start_hash();
+            if (res != ERRCODE_SUCC) {
+                nv_crypto_release_aes(write_buffer->crypto_handle);
+                write_buffer->crypto_handle = INVAILD_CRYPTO_HANDLE;
+                write_buffer->encrypt_claimed = false;
+                g_current_state_machine->error_code = res;
+                return EVENT_ERROR;
+            }
+            write_buffer->crc_ret = 0;
+            write_buffer->hash_claimed = true;
+        }
+#else
+        if (!write_buffer->gcm_tag_claimed) {
+            write_buffer->crc_ret = 0;
+            write_buffer->gcm_tag_claimed = true;
+        }
+#endif /* #if (CONFIG_NV_SUPPORT_HASH_FOR_CRYPT == NV_YES) */
+#endif /* #if (CONFIG_NV_SUPPORT_ENCRYPT == NV_YES) */
+    } else {
+        if (!write_buffer->crc_claimed) {
+            write_buffer->crc_ret = 0;
+            write_buffer->crc_claimed = true;
+        }
+    }
+
+    return EVENT_CRYPTO_CLAIMED;
+}
+
+/*
+ * Attempts to erases all instances of g_current_key (in g_current_store), by marking them as invalid
+ * Configures g_search_filter to find all valid keys with an id matching g_current_key.header.key_id
+ * Starts the g_erase_keys_machine state machine to perform the erasing of keys
+ */
+STATIC kv_update_event_t kv_update_action_erase_old_keys(void)
+{
+    g_search_filter.pattern = g_current_key.header.key_id;
+    g_search_filter.mask = 0xFFFF;
+    g_search_filter.state = KV_KEY_FILTER_STATE_VALID;
+    g_search_filter.type = KV_KEY_FILTER_TYPE_ANY;
+    g_search_filter.location = g_current_key.key_location;
+
+    errcode_t res = begin_state_machine(&g_erase_keys_machine);
+    if (res == ERRCODE_SUCC) {
+        return EVENT_NONE;
+    } else {
+        g_current_state_machine->error_code = res;
+        return EVENT_ERROR;
+    }
+}
+
+STATIC kv_update_event_t kv_update_action_update_nvmap_for_erase_key(void)
+{
+    kv_nvregion_map_t *nv_map = kv_nvregion_get_map();
+    uint32_t page_number = kv_nvregion_get_page_number(g_current_page.page_location);
+    if (page_number >= nv_map->num_entries) {
+        nv_log_debug("[NV] get erase page_number failed! page_location = 0x%x\r\n", g_current_page.page_location);
+        g_current_state_machine->error_code = ERRCODE_NV_INVALID_PAGE;
+        return EVENT_ERROR;
+    }
+
+    uint16_t key_size = (uint32_t)sizeof(kv_key_header_t);
+    uint16_t hash_crc_size;
+    if (g_current_key.header.enc_key == AES_KDFKEY_SDRK_TYPE) {
+        hash_crc_size = KV_CRYPTO_HASH_SIZE;
+    } else {
+        hash_crc_size = KV_CRYPTO_CRC_SIZE;
+    }
+
+    key_size += hash_crc_size;
+
+    kv_attributes_t attributes = kv_key_attributes(&g_current_key);
+    key_size += kv_key_padded_data_length(attributes, g_current_key.header.length);
+
+    nv_page_status_map_t *page_status = &(nv_map->page_status_map[page_number]);
+    page_status->reclaimable_space += key_size;
+    nv_log_debug("[NV] update nv map for erase key = 0x%x (page = 0x%x) size = %d\r\n",
+        g_current_key.header.key_id, g_current_page.page_location, key_size);
+    return EVENT_PAGE_MAP_UPDATED;
+}
+
+STATIC kv_update_event_t kv_update_action_update_nvmap_for_new_key(void)
+{
+    kv_nvregion_map_t *nv_map = kv_nvregion_get_map();
+
+    uint32_t page_number = kv_nvregion_get_page_number(g_current_page.page_location);
+    if (page_number >= nv_map->num_entries) {
+        nv_log_debug("[NV] get new key page_number failed! page_location = 0x%x\r\n", g_current_page.page_location);
+        g_current_state_machine->error_code = ERRCODE_NV_INVALID_PAGE;
+        return EVENT_ERROR;
+    }
+
+    uint16_t key_size = (uint32_t)sizeof(kv_key_header_t);
+    uint16_t hash_crc_size;
+    if (((uint32_t)g_new_key_details.attributes & (uint32_t)KV_ATTRIBUTE_ENCRYPTED) != 0) {
+        hash_crc_size = KV_CRYPTO_HASH_SIZE;
+    } else {
+        hash_crc_size = KV_CRYPTO_CRC_SIZE;
+    }
+
+    key_size += hash_crc_size;
+    key_size += kv_key_padded_data_length(g_new_key_details.attributes, g_new_key_details.kvalue_length);
+
+    nv_page_status_map_t *page_status = &(nv_map->page_status_map[page_number]);
+    page_status->used_space += key_size;
+    page_status->first_writable_offset += key_size;
+    nv_log_debug("[NV] update nv map for new key = 0x%x (page = 0x%x) size = %d\r\n",
+        g_new_key_details.key_id, g_current_page.page_location, key_size);
+    return EVENT_PAGE_MAP_UPDATED;
+}
+
+/*
+ * Begins a new state machine by creating a new entry at the end of the active state machines list
+ * and updating g_current_state_machine
+ *
+ * Either called to begin processing a *new* top-level state machine, before calling process_state_machine()
+ * or called by a state machine action function to kick off the processing of a new (nested) state machine
+ */
+STATIC errcode_t begin_state_machine(const kv_state_machine_t *machine)
+{
+    kv_active_state_machine_t *new_state_machine =
+        (kv_active_state_machine_t *)kv_malloc(sizeof(kv_active_state_machine_t));
+    if (new_state_machine == NULL) {
+        return ERRCODE_MALLOC;
+    }
+    (void)memset_s(new_state_machine, sizeof(kv_active_state_machine_t), 0, sizeof(kv_active_state_machine_t));
+    new_state_machine->prev = g_current_state_machine;
+
+    /* Configure default initial state and event for new state machine */
+    new_state_machine->machine = machine;
+    new_state_machine->state = machine->initial_state;
+    new_state_machine->event = EVENT_NONE;
+    new_state_machine->error_code = ERRCODE_SUCC;
+    g_current_state_machine = new_state_machine;
+
+    if (g_current_state_machine->machine->write_buffer_size > 0) {
+        return kv_create_write_buffer(0, g_current_state_machine->machine->write_buffer_size);
+    } else {
+        return ERRCODE_SUCC;
+    }
+}
+
+/*
+ * Should only be called by process_state_machine()
+ *
+ * Ends current state machine and updates g_current_state_machine to point to the previous state machine.
+ * Passes either the pre-defined exit_event or the last event returned by an action function as the
+ * event received by the previous state machine.
+ */
+STATIC void end_state_machine(void)
+{
+    if (g_current_state_machine != NULL) {
+        kv_remove_write_buffer();
+        kv_remove_source_buffer();
+
+        kv_active_state_machine_t *prev_state_machine = g_current_state_machine->prev;
+        if (prev_state_machine != NULL) {
+            if (g_current_state_machine->machine->exit_event != EVENT_NONE) {
+                /* Single explicit exit event defined for exiting state machine */
+                prev_state_machine->event = g_current_state_machine->machine->exit_event;
+            } else {
+                /* Pass last event raised from exiting state machine back to invoking state machine */
+                prev_state_machine->event = g_current_state_machine->event;
+            }
+        }
+
+        kv_free(g_current_state_machine);
+        g_current_state_machine = prev_state_machine;
+    }
+}
+
+static void clean_state_machine(void)
+{
+    while (g_current_state_machine != NULL) {
+        end_state_machine();
+    }
+}
+
+/*
+ * Should only be called by process_state_machine()
+ *
+ * Attempts to locate and call an action function based on the state of the current state machine
+ * An action function may spawn another state machine and hence cause g_current_state_machine to change.
+ *
+ * g_current_state_machine->event is used to record the return value from the action function.
+ *
+ * If a new state machine is spawned, this return value will effectively be lost as the procedure for processing
+ * new state machines is to assume there is no initial event, just an initial state and thus action to perform.
+ *
+ * If an action function is not found then g_current_state_machine->event will not be updated.  This really should
+ * be reserved for when state transitions cause g_current_state_machine->state to be one of the following
+ * special cases, which are handled by process_state_machine():
+ *   - STATE_INVALID
+ *   - STATE_SUSPENDED
+ *   - STATE_EXIT
+ */
+static void invoke_current_state_action(void)
+{
+    if (g_current_state_machine != NULL) {
+        /* Search action table to locate an action function for the current state */
+        /* STATE_EXIT always marks end of an action table                         */
+        const kv_update_action_t *update_action = g_current_state_machine->machine->action_table;
+        while (update_action->state != STATE_EXIT) {
+            if (update_action->state == g_current_state_machine->state) {
+                /* Found a matching entry */
+                break;
+            }
+            update_action++;
+        }
+
+        /* Call action function if we have found one */
+        if (update_action->action != NULL) {
+            /* Action function could cause a change of g_current_state_machine */
+            g_current_state_machine->event = (*update_action->action)();
+        }
+    }
+}
+
+/*
+ * Should only be called by process_state_machine()
+ *
+ * Uses the last event recorded for the state machine, in g_current_state_machine->event, to select the
+ * next appropriate state for the current state machine.
+ *
+ * In the case of no suitable entry on the transition_table an error state of STATE_INVALID is entered.
+ * This will cause process_state_machine() to terminate processing of all queued state machines and
+ * return an error.
+ */
+STATIC void update_current_state(void)
+{
+    /* Don't update anything for EVENT_NONE.  We'll eventually call the action function again */
+    if ((g_current_state_machine != NULL) && (g_current_state_machine->event != EVENT_NONE)) {
+        /* Search transition table looking for a transition entry for current state and event */
+        /* A transition table is always terminated with transition->state == STATE_EXIT       */
+        const kv_update_transition_t *transition = g_current_state_machine->machine->transition_table;
+        while (transition->state != STATE_EXIT) {
+            if ((g_current_state_machine->state == transition->state) &&
+                (g_current_state_machine->event == transition->event)) {
+                /* Found a matching entry */
+                break;
+            }
+            transition++;
+        }
+
+        /* Update current state if we have found a suitable transition table entry */
+        if (transition->state != STATE_EXIT) {
+            g_current_state_machine->state = transition->next_state;
+        } else {
+            /* No state transition found for the current state and event */
+            g_current_state_machine->state = STATE_INVALID;
+        }
+    }
+}
+
+#if defined (DEBUG_PRINT_ENABLED)
+static const char *g_update_state_strings[STATE_EXIT + 1] = {
+    [STATE_INVALID] =             "STATE_INVALID",
+    [STATE_SELECT_FIRST_PAGE] =   "STATE_SELECT_FIRST_PAGE",
+    [STATE_SELECT_NEXT_PAGE] =    "STATE_SELECT_NEXT_PAGE",
+    [STATE_FIND_FIRST_KEY] =      "STATE_FIND_FIRST_KEY",
+    [STATE_FIND_NEXT_KEY] =       "STATE_FIND_NEXT_KEY",
+    [STATE_FIND_EXISTING_KEY] =   "STATE_FIND_EXISTING_KEY",
+    [STATE_PREP_COPY_KEY] =       "STATE_PREP_COPY_KEY",
+    [STATE_PREP_DELETE_KEY] =     "STATE_PREP_DELETE_KEY",
+    [STATE_PREP_MODIFY_KEY] =     "STATE_PREP_MODIFY_KEY",
+    [STATE_FIND_DEFRAG] =         "STATE_FIND_DEFRAG",
+    [STATE_ERASE_DEFRAG] =        "STATE_ERASE_DEFRAG",
+    [STATE_PREP_DEFRAG] =         "STATE_PREP_DEFRAG",
+    [STATE_COPY_ALL_KEYS] =       "STATE_COPY_ALL_KEYS",
+    [STATE_PREP_PAGE_HEADER] =    "STATE_PREP_PAGE_HEADER",
+    [STATE_WRITE_PAGE_HEADER] =   "STATE_WRITE_PAGE_HEADER",
+    [STATE_UPDATE_NVREGION_MAP] = "STATE_UPDATE_NVREGION_MAP",
+    [STATE_FIND_WRITE_POS] =      "STATE_FIND_WRITE_POS",
+    [STATE_DEFRAG_PAGE] =         "STATE_DEFRAG_PAGE",
+    [STATE_PREP_STORE] =          "STATE_PREP_STORE",
+    [STATE_PREP_KEY_DATA] =       "STATE_PREP_KEY_DATA",
+    [STATE_CLAIM_CRYPTO] =        "STATE_CLAIM_CRYPTO",
+    [STATE_ERASE_OLD_KEYS] =      "STATE_ERASE_OLD_KEYS",
+    [STATE_PRIME_WRITE] =         "STATE_PRIME_WRITE",
+    [STATE_PERFORM_WRITE] =       "STATE_PERFORM_WRITE",
+    [STATE_SUSPENDED] =           "STATE_SUSPENDED",
+    [STATE_EXIT] =                "STATE_EXIT"
+};
+
+#if defined (DEBUG_KV_UPDATE_STATE_MACHINE)
+static const char *g_update_event_strings[EVENT_ERROR + 1] = {
+    [EVENT_NONE] =                  "EVENT_NONE",
+    [EVENT_SUSPEND] =               "EVENT_SUSPEND",
+    [EVENT_WRITE_DATA_EXHAUSTED] =  "EVENT_WRITE_DATA_EXHAUSTED",
+    [EVENT_WRITE_BUFFER_PRIMED] =   "EVENT_WRITE_BUFFER_PRIMED",
+    [EVENT_WRITE_BUFFER_STORED] =   "EVENT_WRITE_BUFFER_STORED",
+    [EVENT_PAGE_SELECTED] =         "EVENT_PAGE_SELECTED",
+    [EVENT_PAGE_NOT_SELECTED] =     "EVENT_PAGE_NOT_SELECTED",
+    [EVENT_KEY_FOUND] =             "EVENT_KEY_FOUND",
+    [EVENT_KEY_NOT_FOUND] =         "EVENT_KEY_NOT_FOUND",
+    [EVENT_COPY_KEY_READY] =        "EVENT_COPY_KEY_READY",
+    [EVENT_KEYS_ERASED] =           "EVENT_KEYS_ERASED",
+    [EVENT_KEY_UPDATE_REQUIRED] =   "EVENT_KEY_UPDATE_REQUIRED",
+    [EVENT_KEY_UPDATE_NOT_NEEDED] = "EVENT_KEY_UPDATE_NOT_NEEDED",
+    [EVENT_DEFRAG_FOUND] =          "EVENT_DEFRAG_FOUND",
+    [EVENT_DEFRAG_ERASED] =         "EVENT_DEFRAG_ERASED",
+    [EVENT_DEFRAG_PREPARED] =       "EVENT_DEFRAG_PREPARED",
+    [EVENT_ALL_KEYS_COPIED] =       "EVENT_ALL_KEYS_COPIED",
+    [EVENT_PAGE_HEADER_READY] =     "EVENT_PAGE_HEADER_READY",
+    [EVENT_NVREGION_MAP_UPDATED] =  "EVENT_NVREGION_MAP_UPDATED",
+    [EVENT_DEFRAG_REQUIRED] =       "EVENT_DEFRAG_REQUIRED",
+    [EVENT_DEFRAG_COMPLETE] =       "EVENT_DEFRAG_COMPLETE",
+    [EVENT_WRITE_POS_FOUND] =       "EVENT_WRITE_POS_FOUND",
+    [EVENT_STORE_READY] =           "EVENT_STORE_READY",
+    [EVENT_KEY_DATA_READY] =        "EVENT_KEY_DATA_READY",
+    [EVENT_CRYPTO_CLAIMED] =        "EVENT_CRYPTO_CLAIMED",
+    [EVENT_WRITE_COMPLETE] =        "EVENT_WRITE_COMPLETE",
+    [EVENT_ERROR] =                 "EVENT_ERROR"
+};
+#endif
+#endif
+
+static void dprint_state_machine(const char *str)
+{
+    unused(str);
+#if defined (DEBUG_KV_UPDATE_STATE_MACHINE)
+    if (g_current_state_machine != NULL) {
+        nv_log_debug("%08X:  ", (uint32_t)g_current_state_machine);
+        nv_log_debug("%s  ", g_update_state_strings[g_current_state_machine->state]);
+        nv_log_debug("%s  ", str);
+        nv_log_debug("%s\r\n", g_update_event_strings[g_current_state_machine->event]);
+    } else {
+        nv_log_debug("*** State Machine  %s ***\r\n", str);
+    }
+#endif
+}
+
+/*
+ * Function used to process queued state machines
+ *
+ * There is only ever one state machine being processed at any one time.
+ *
+ * State machines are started (queued) by explicitly calling begin_state_machine() before this function is called.
+ * State machines themselves can spawn a nested state machine by also calling begin_state_machine() in an action
+ * function.
+ * When started, a state machine will be in the initial_state defined for the state machine.
+ *
+ * State machines are ended normally by transitioning to STATE_EXIT or abnormally by transitioning to STATE_INVALID.
+ * In such instances, process_state_machine(), will call end_state_machine() to tidy up.
+ *
+ * State machines can be suspended at any point by transitioning to STATE_SUSPENDED.
+ * When resumed, by calling process_state_machine() again, they will start from the resume_state defined for the
+ * state machine.
+ *
+ * g_current_state_machine points to the current active state machine
+ *
+ * When a state machine is processed for the first time, or resumed following suspension, it is assumed there is no
+ * current event that exists for the state machine in this context.  An action function for the current state, which
+ * will be defined by initial_state or resume_state, will provide an event to provide for further transitions through
+ * the state machine.
+ */
+STATIC errcode_t process_state_machine(void)
+{
+    errcode_t error_code = ERRCODE_SUCC;
+    uint64_t flash_access_time = 0;
+    unused(flash_access_time);
+
+    while (g_current_state_machine != NULL) {
+        /* Call action function for the current state */
+        dprint_state_machine("---");
+        invoke_current_state_action();
+        dprint_state_machine("-->");
+
+        /* Check event returned by action function */
+        if (g_current_state_machine->event == EVENT_ERROR) {
+            /* Ripple back down chain of state machines and report error */
+            error_code = g_current_state_machine->error_code;
+            clean_state_machine();
+            return error_code;
+        }
+
+        /* Transition state machine */
+        update_current_state();
+        dprint_state_machine("<--");
+
+        /* Has the state machine finished? */
+        while ((g_current_state_machine != NULL) && (g_current_state_machine->state == STATE_EXIT)) {
+            invoke_current_state_action();  /* Exit state could have an action function if it needs to do more */
+            end_state_machine();            /* than just end the current state machine                         */
+            update_current_state();
+            dprint_state_machine("<==");
+        }
+
+        /* Has state machine processing been suspended? */
+        if ((g_current_state_machine != NULL) && (g_current_state_machine->state == STATE_SUSPENDED)) {
+#ifdef CONFIG_NV_SUPPORT_SINGLE_CORE_SYSTEM
+            /* if in one-core system, the flash must be writen in one time */
+            /* so once the suspend happened, clear the state_machine */
+            clean_state_machine();
+#else
+            /* We need to suspend processing due to other cores waking up */
+            /* Configure state machine to resume from the correct place */
+            g_current_state_machine->state = g_current_state_machine->machine->resume_state;
+            g_current_state_machine->event = EVENT_NONE;
+#endif
+            kv_release_crypto();
+            return ERRCODE_NV_WRITE_VETOED;
+        }
+
+        /* Has the state machine entered an invalid state? */
+        if ((g_current_state_machine != NULL) && (g_current_state_machine->state == STATE_INVALID)) {
+#ifdef CONFIG_NV_SUPPORT_SINGLE_CORE_SYSTEM
+            clean_state_machine();
+#endif
+            kv_release_crypto();
+            return ERRCODE_NV_STATE_INVALID;
+        }
+    }
+
+    return error_code;
+}
+
+/* Creates a write buffer used to prepare data, gathered from one or more source buffers, for writing to flash */
+STATIC errcode_t kv_create_write_buffer(uint32_t write_location, uint32_t size)
+{
+    if (size == 0) {
+        return ERRCODE_INVALID_PARAM;
+    }
+
+    if (g_current_state_machine->write_buffer != NULL) {
+        return ERRCODE_FAIL;
+    }
+
+    uint8_t *data = (uint8_t *)kv_malloc(size);
+    if (data == NULL) {
+        return ERRCODE_MALLOC;
+    }
+    kv_managed_write_buffer_t *write_buffer =
+        (kv_managed_write_buffer_t *)kv_malloc(sizeof(kv_managed_write_buffer_t));
+    if (write_buffer == NULL) {
+        kv_free(data);
+        return ERRCODE_MALLOC;
+    }
+
+    (void)memset_s(write_buffer, sizeof(kv_managed_write_buffer_t), 0, sizeof(kv_managed_write_buffer_t));
+    write_buffer->data = data;
+    write_buffer->size = (uint16_t)size;
+    write_buffer->data_consumed = (uint16_t)size;
+    write_buffer->write_location = write_location;
+    write_buffer->resume_location = write_location;
+    g_current_state_machine->write_buffer = write_buffer;
+
+    return ERRCODE_SUCC;
+}
+
+/* Removes the write buffer owned by the current state machine */
+STATIC void kv_remove_write_buffer(void)
+{
+    if (g_current_state_machine->write_buffer != NULL) {
+        kv_free(g_current_state_machine->write_buffer->data);
+        kv_free(g_current_state_machine->write_buffer);
+        g_current_state_machine->write_buffer = NULL;
+    }
+}
+
+/* Every key consists of a header, data and a hash.  Multiple kv_managed_source_buffer_t are constructed to
+ * manage these separate blocks of data.
+ * They keep track of where the data is located and how much of it has
+ * been written to flash.
+ * These buffers are used in a scatter-gather type approach to feed a single write buffer that holds data
+ * that has been fully prepared for writing to flash */
+STATIC kv_managed_source_buffer_t* kv_update_source_buffer(uint8_t *data, uint32_t data_length)
+{
+    kv_managed_source_buffer_t *source_buffer = kv_malloc(sizeof(kv_managed_source_buffer_t));
+    if (source_buffer == NULL) {
+        return NULL;
+    }
+
+    errno_t err = memset_s(source_buffer, sizeof(kv_managed_source_buffer_t), 0, sizeof(kv_managed_source_buffer_t));
+    if (err != EOK) {
+        kv_free(source_buffer);
+        return NULL;
+    }
+    source_buffer->data = data;
+    source_buffer->data_length = (uint16_t)data_length;
+    source_buffer->next = NULL;
+
+    /* Append new buffer to end of list */
+    kv_managed_source_buffer_t **next_buffer = &g_current_state_machine->source_buffer;
+    while (*next_buffer != NULL) {
+        next_buffer = &(*next_buffer)->next;
+    }
+    *next_buffer = source_buffer;
+    return source_buffer;
+}
+
+/* Removes kv_managed_source_buffer_t data structures, freeing memory holding actual data too, if necessary */
+STATIC void kv_remove_source_buffer(void)
+{
+    kv_managed_source_buffer_t *current = g_current_state_machine->source_buffer;
+    while (current != NULL) {
+        kv_managed_source_buffer_t *next = current->next;
+        if (current->release_data) {
+            kv_free(current->data);
+        }
+        kv_free(current);
+        current = next;
+    }
+    g_current_state_machine->source_buffer = NULL;
+}
+
+/* Releases claim over hardware AES and hash functions */
+STATIC void kv_release_crypto(void)
+{
+    if (g_current_state_machine == NULL) {
+        return;
+    }
+    kv_managed_write_buffer_t *write_buffer = g_current_state_machine->write_buffer;
+    uint32_t status;
+
+    if (write_buffer != NULL) {
+        status = osal_irq_lock();
+        if (write_buffer->crc_claimed) {
+            write_buffer->crc_ret = 0;
+            write_buffer->crc_claimed = false;
+        }
+#if (CONFIG_NV_SUPPORT_ENCRYPT == NV_YES)
+        if (write_buffer->hash_claimed) {
+            write_buffer->hash_claimed = false;
+        }
+        if (write_buffer->gcm_tag_claimed) {
+            write_buffer->gcm_tag_claimed = false;
+        }
+        if (write_buffer->encrypt_claimed) {
+            nv_crypto_release_aes(write_buffer->crypto_handle);
+            write_buffer->crypto_handle = INVAILD_CRYPTO_HANDLE;
+            write_buffer->encrypt_claimed = false;
+        }
+#endif
+        osal_irq_restore(status);
+    }
+}
+
+STATIC bool active_state_machine(void)
+{
+    if (g_current_state_machine != NULL) {
+        return true;
+    }
+    return false;
+}
+
+STATIC uint32_t determine_flash_task_state_code(errcode_t res)
+{
+    switch (res) {
+        case ERRCODE_NV_WRITE_VETOED:
+        case ERRCODE_FLASH_TASK_PE_VETO:
+            return FLASH_TASK_BEING_PROCESSED;
+        case ERRCODE_SUCC:
+            return FLASH_TASK_COMPLETED;
+        default:
+            return (uint32_t)res;
+    }
+}
+
+#if defined(CONFIG_PARTITION_FEATURE_SUPPORT)
+STATIC errcode_t nv_read_partition_addr(uint32_t *start_address, uint32_t *size)
+{
+    /* 获取分区表标记 */
+    errcode_t ret;
+    partition_information_t info;
+
+    ret = uapi_partition_get_info(PARTITION_NV_DATA, &info);
+    if (ret != ERRCODE_SUCC) {
+        return ret;
+    }
+    *start_address = info.part_info.addr_info.addr + FLASH_PHYSICAL_ADDR_START;
+    *size = info.part_info.addr_info.size;
+
+    return ERRCODE_SUCC;
+}
+#endif
+
+errcode_t kv_update_init(cores_t core)
+{
+    unused(core);
+
+    errcode_t res;
+    uint32_t kv_start_addr = 0;
+    uint32_t kv_size = 0;
+#if defined(CONFIG_PARTITION_FEATURE_SUPPORT)
+    res = nv_read_partition_addr(&kv_start_addr, &kv_size);
+    if (res != ERRCODE_SUCC) {
+        return res;
+    }
+#endif
+    if (kv_start_addr != 0 && kv_size != 0) {
+        kv_nvregion_init(kv_start_addr, KV_STORE_DATA_SIZE, kv_start_addr + KV_STORE_DATA_SIZE, KV_BACKUP_DATA_SIZE);
+    } else {
+        kv_nvregion_init(KV_STORE_START_ADDR, KV_STORE_DATA_SIZE, KV_BACKUP_START_ADDR, KV_BACKUP_DATA_SIZE);
+    }
+
+    /* Scan NV region looking for KV pages */
+    res = kv_nvregion_scan();
+    if (res != ERRCODE_SUCC) {
+        return res;
+    }
+
+    /* Check expected KV pages have been found */
+    for (uint8_t store = (uint8_t)KV_STORE_APPLICATION; store < (uint8_t)KV_STORE_MAX_NUM; store++) {
+        uint16_t store_id = kv_store_get_id(store);
+        uint8_t pages_num = kv_store_get_page_count(store);
+        for (uint8_t page_index = 0; page_index < pages_num; page_index++) {
+            res = kv_nvregion_find_page(store_id, page_index, NULL, NULL);
+            if (res != ERRCODE_SUCC) {
+                /* NV Region does not contain an expected KV page, attempt to create it */
+                res = kv_nvregion_create_page(store_id, page_index);
+            }
+            if (res != ERRCODE_SUCC) {
+                return ERRCODE_FAIL;
+            }
+        }
+    }
+    return ERRCODE_SUCC;
+}
+
+#if (CONFIG_NV_SUPPORT_BACKUP_RESTORE == NV_YES)
+STATIC errcode_t kv_updata_backup_page_head_is_valid(const kv_page_header_t *backup_head)
+{
+    if ((backup_head->details.store_id == KV_STORE_ID_BACKUP) &&
+        ((~backup_head->inverted_details_word) == *(uint32_t *)(uintptr_t)(&backup_head->details)) &&
+        ((~backup_head->inverted_sequence_number) == backup_head->sequence_number)) {
+            return ERRCODE_SUCC;
+    }
+    return ERRCODE_FAIL;
+}
+
+STATIC errcode_t kv_updata_backup_fail_process(uint32_t back_maybe_need_process_location)
+{
+    errcode_t res;
+    kv_page_location unused_page_location = NULL;
+    uint32_t page_head_size = (uint32_t)sizeof(kv_page_header_t);
+    kv_nvregion_area_t* nvregion_area =  nv_get_region_area();
+    if (nvregion_area == NULL) {
+        return ERRCODE_FAIL;
+    }
+    /* 去找工作区可以换页的页,然后将可以换页的页地址给传出 */
+    res = kv_nvregion_find_unused_page(&unused_page_location);
+    if (res != ERRCODE_SUCC) {
+        return res;
+    }
+    /* 获取工作区换页页的页头  */
+    kv_page_header_t store_head_buffer;
+    res = kv_key_helper_copy_flash((uint32_t)(uintptr_t)&store_head_buffer,
+        (uint32_t)unused_page_location, page_head_size);
+    if (res != ERRCODE_SUCC) {
+        return res;
+    }
+    /* 如果页头中包含 KV_STORE_ID_BACKUP 并且该page_location与maybe_need_process_location时都指向同一页 那么说明存在掉电丢数据的情况 */
+    if (kv_updata_backup_page_head_is_valid(&store_head_buffer) == ERRCODE_SUCC) {
+        uint32_t back_page_location = nvregion_area->nv_backup_addr
+            + store_head_buffer.details.page_index * KV_PAGE_SIZE;
+        if (back_page_location == back_maybe_need_process_location) {
+            res = kv_key_erase_flash(back_page_location, KV_PAGE_SIZE);
+            if (res != ERRCODE_SUCC) {
+                return res;
+            }
+            res = kv_backup_copy_unused_page_to_dragpage(back_page_location, (uint32_t)unused_page_location);
+            if (res != ERRCODE_SUCC) {
+                return res;
+            }
+        }
+    }
+    return ERRCODE_SUCC;
+}
+
+errcode_t kv_update_backup_init(void)
+{
+    /* Initializes the page header of the backup area */
+    errcode_t res;
+    uint32_t backup_not_inited_count = 0; /* 重启时备份区没有初始化的数量为0 */
+    uint32_t back_maybe_need_process_location = 0;
+    kv_nvregion_area_t* nvregion_area =  nv_get_region_area();
+    if (nvregion_area == NULL) {
+        return ERRCODE_FAIL;
+    }
+    uint32_t back_page_location = nvregion_area->nv_backup_addr;
+    kv_page_header_t backup_head_buffer;
+    for (uint32_t page_index = 0; page_index < KV_BACKUP_PAGE_NUM; page_index++) {
+        res = kv_key_helper_copy_flash((uint32_t)(uintptr_t)&backup_head_buffer,
+            (uint32_t)back_page_location, sizeof(kv_page_header_t));
+        if (res != ERRCODE_SUCC) {
+            return res;
+        }
+        if (kv_updata_backup_page_head_is_valid(&backup_head_buffer) == ERRCODE_FAIL) {
+            backup_not_inited_count++;
+            res = kv_nvregion_write_page((kv_page_location)back_page_location, KV_STORE_ID_BACKUP, page_index);
+            if (res != ERRCODE_SUCC) {
+                return res;
+            }
+            back_maybe_need_process_location = back_page_location;
+        }
+        back_page_location += KV_PAGE_SIZE;
+    }
+
+    /* 如果备份区没有初始化的页的数量为0, 说明备份区页不存在异常,正常重启 */
+    /* 如果备份区未初始化的页的数量大于1, 说明是刚刚烧录状态,对备份区页头的初始化 */
+    /* 如果备份区没有初始化的页的数量为1, 那么说明可能存在掉电异常场景进行处理 */
+    if (backup_not_inited_count == 1) {
+        res = kv_updata_backup_fail_process(back_maybe_need_process_location);
+        if (res != ERRCODE_SUCC) {
+            return res;
+        }
+    }
+    return res;
+}
+#endif /* #if (CONFIG_NV_SUPPORT_BACKUP_RESTORE == NV_YES) */
+
+
+/* Top level function used to mark a single key in a store as invalid (and hence erased) */
+/* Will actually scan a store for all keys matching the specified key_id, to ensure they are all marked as erased */
+errcode_t kv_update_erase_key(kv_store_t core, flash_task_node *sanitised_tasks)
+{
+    if (!active_state_machine()) {
+        g_current_store = core;
+
+        /* Configure search filter to obtain all valid instances of a specific key_id */
+        g_search_filter.pattern = sanitised_tasks->data.kv_erase.key;
+        g_search_filter.mask = 0xFFFF;
+        g_search_filter.state = KV_KEY_FILTER_STATE_VALID;
+        g_search_filter.type = KV_KEY_FILTER_TYPE_ANY;
+        g_search_filter.location = 0;
+
+        /* Queue Erase Keys state machine for processing */
+        begin_state_machine(&g_erase_keys_machine);
+    }
+
+    /* Run state machine until it is either suspended (yielding due to flash contention) or */
+    /* completed (either successfully or otherwise)                                         */
+    sanitised_tasks->state_code = determine_flash_task_state_code(process_state_machine());
+#ifdef CONFIG_NV_SUPPORT_SINGLE_CORE_SYSTEM
+    if (sanitised_tasks->state_code == FLASH_TASK_COMPLETED) {
+        return ERRCODE_SUCC;
+    } else {
+        return (errcode_t)sanitised_tasks->state_code;
+    }
+#else
+    return ERRCODE_SUCC;
+#endif
+}
+
+/* Top level function to write a new key or modify an existing key-value */
+/* Will cause a new instance of the key to be generated */
+errcode_t kv_update_write_key(kv_store_t core, flash_task_node *sanitised_task)
+{
+    if (!active_state_machine()) {
+        g_current_store = core;
+
+        /* Log details of new key to be written */
+        g_new_key_details.key_id = sanitised_task->data.kv.key;
+        g_new_key_details.kvalue = sanitised_task->data.kv.kvalue;
+        g_new_key_details.kvalue_length = sanitised_task->data.kv.kvalue_length;
+        g_new_key_details.attributes = sanitised_task->data.kv.attribute;
+        g_new_key_details.focre_write = sanitised_task->data.kv.force_write;
+
+        /* Queue Write Key state machine for processing */
+        begin_state_machine(&g_write_key_machine);
+    }
+
+    /* Run state machine until it is either suspended (yielding due to flash contention) or */
+    /* completed (either successfully or otherwise)                                         */
+    sanitised_task->state_code = determine_flash_task_state_code(process_state_machine());
+#ifdef CONFIG_NV_SUPPORT_SINGLE_CORE_SYSTEM
+    if (sanitised_task->state_code == FLASH_TASK_COMPLETED) {
+        return ERRCODE_SUCC;
+    } else {
+        return (errcode_t)sanitised_task->state_code;
+    }
+#else
+    return ERRCODE_SUCC;
+#endif
+}
+
+/* Modify the attribute on an existing key-value */
+/* Top level function to modify the attributes of an existing key */
+/* Will cause a new instance of the key to be generated */
+/* Existing key attributes will be maintained */
+errcode_t kv_update_modify_attribute(kv_store_t core, flash_task_node *sanitised_task)
+{
+    uint8_t *old_kvalue = NULL;
+    errcode_t res;
+    if (!active_state_machine()) {
+        g_current_store = core;
+        /* Log details of *additional* attributes to be applied to an existing key */
+        g_new_key_details.key_id = sanitised_task->data.kv_attribute.key;
+        g_new_key_details.kvalue = NULL;
+        g_new_key_details.kvalue_length = 0;
+        g_new_key_details.attributes = sanitised_task->data.kv_attribute.attribute;
+        g_new_key_details.focre_write = false;
+
+        res = kv_update_helper_get_current_key(&old_kvalue, &g_new_key_details.kvalue_length);
+        if (res != ERRCODE_SUCC) {
+            return res;
+        }
+        g_new_key_details.kvalue = old_kvalue;
+        /* Queue Modify Key state machine for processing */
+        begin_state_machine(&g_write_key_machine);
+    }
+
+    /* Run state machine until it is either suspended (yielding due to flash contention) or */
+    /* completed (either successfully or otherwise)                                         */
+    sanitised_task->state_code = determine_flash_task_state_code(process_state_machine());
+#ifdef CONFIG_NV_SUPPORT_SINGLE_CORE_SYSTEM
+    kv_free((void *)old_kvalue);
+    if (sanitised_task->state_code == FLASH_TASK_COMPLETED) {
+        return ERRCODE_SUCC;
+    } else {
+        return (errcode_t)sanitised_task->state_code;
+    }
+#else
+    if (sanitised_task->state_code != FLASH_TASK_BEING_PROCESSED) {
+        kv_free((void *)old_kvalue);
+    }
+    return ERRCODE_SUCC;
+#endif
+}
+
index b61a463..530d623 100755 (executable)
-/*\r
- * Copyright (c) @CompanyNameMagicTag 2019-2022. All rights reserved.\r
- * Description: KV Storage Library flash updating module interface\r
- */\r
-\r
-#ifndef NV_UPDATE_H_\r
-#define NV_UPDATE_H_\r
-\r
-#ifdef CONFIG_NV_SUPPORT_SINGLE_CORE_SYSTEM\r
-#include "nv_task_adapt.h"\r
-#else\r
-#include "flash_task_types.h"\r
-#endif\r
-#include "nv_store.h"\r
-#include "errcode.h"\r
-#include "nv_porting.h"\r
-\r
-#ifdef __cplusplus\r
-#if __cplusplus\r
-extern "C" {\r
-#endif /* __cplusplus */\r
-#endif /* __cplusplus */\r
-\r
-/* Unused states and events should be removed */\r
-typedef enum {\r
-    STATE_INVALID,\r
-\r
-    /* erase_all_keys, erase_old_keys, copy_all_keys */\r
-    STATE_SELECT_FIRST_PAGE,\r
-    STATE_SELECT_NEXT_PAGE,\r
-    STATE_FIND_FIRST_KEY,\r
-    STATE_FIND_NEXT_KEY,\r
-    STATE_FIND_EXISTING_KEY,\r
-    STATE_PREP_COPY_KEY,\r
-    STATE_PREP_DELETE_KEY,\r
-    STATE_PREP_MODIFY_KEY,\r
-    STATE_UPDATE_MAP_FOR_OLD,\r
-\r
-    /* prep_defrag_page, defrag_page */\r
-    STATE_FIND_DEFRAG,\r
-    STATE_ERASE_DEFRAG,\r
-    STATE_PREP_DEFRAG,\r
-    STATE_COPY_ALL_KEYS,\r
-    STATE_PREP_PAGE_HEADER,\r
-    STATE_WRITE_PAGE_HEADER,\r
-    STATE_UPDATE_NVREGION_MAP,\r
-\r
-    /* prepare_write */\r
-    STATE_FIND_WRITE_POS,\r
-    STATE_DEFRAG_PAGE,\r
-\r
-    /* write_key */\r
-    STATE_PREP_STORE,\r
-    STATE_PREP_KEY_DATA,\r
-    STATE_CLAIM_CRYPTO,\r
-    STATE_ERASE_OLD_KEYS,\r
-\r
-    STATE_PRIME_WRITE,\r
-    STATE_PERFORM_WRITE,\r
-    STATE_UPDATE_MAP_FOR_NEW,\r
-\r
-    STATE_SUSPENDED = 0x1E,\r
-    STATE_EXIT      = 0x1F\r
-} kv_update_state_t;\r
-\r
-typedef enum {\r
-    EVENT_NONE,\r
-    EVENT_SUSPEND,\r
-\r
-    EVENT_WRITE_DATA_EXHAUSTED,\r
-    EVENT_WRITE_BUFFER_PRIMED,\r
-    EVENT_WRITE_BUFFER_STORED,\r
-\r
-    /* erase_all_keys, erase_old_keys, copy_all_keys, modify_key */\r
-    EVENT_PAGE_SELECTED,\r
-    EVENT_PAGE_NOT_SELECTED,\r
-    EVENT_KEY_FOUND,\r
-    EVENT_KEY_NOT_FOUND,\r
-    EVENT_COPY_KEY_READY,\r
-\r
-    /* erase_all_keys */\r
-    EVENT_KEYS_ERASED,\r
-\r
-    /* modify_key */\r
-    EVENT_KEY_UPDATE_REQUIRED,\r
-    EVENT_KEY_UPDATE_NOT_NEEDED,\r
-\r
-    /* prep_defrag_page */\r
-    EVENT_DEFRAG_FOUND,\r
-    EVENT_DEFRAG_ERASED,\r
-\r
-    /* defrag_page */\r
-    EVENT_DEFRAG_PREPARED,\r
-    EVENT_ALL_KEYS_COPIED,\r
-    EVENT_PAGE_HEADER_READY,\r
-    EVENT_NVREGION_MAP_UPDATED,\r
-\r
-    /* prepare_write */\r
-    EVENT_DEFRAG_REQUIRED,\r
-    EVENT_DEFRAG_COMPLETE,\r
-    EVENT_WRITE_POS_FOUND,\r
-\r
-    /* write_key */\r
-    EVENT_STORE_READY,\r
-    EVENT_KEY_DATA_READY,\r
-    EVENT_CRYPTO_CLAIMED,\r
-    EVENT_WRITE_COMPLETE,\r
-    EVENT_PAGE_MAP_UPDATED,\r
-\r
-    EVENT_ERROR = 0x1F\r
-} kv_update_event_t;\r
-\r
-/* State machine action function */\r
-typedef kv_update_event_t (*kv_state_action)(void);\r
-\r
-/* Data to be written to flash can be scattered across a chain of one or more source buffers */\r
-typedef struct managed_source_buffer {\r
-    struct managed_source_buffer *next;      /* Pointer to next source buffer in chain */\r
-    uint8_t *data;                           /* Pointer to data in RAM/Flash */\r
-    uint16_t data_length;                    /* Length of the data */\r
-    uint16_t data_consumed;                  /* How much of the data has been read so far */\r
-    bool release_data : 1;              /* Data pointer is a temporary buffer that needs freeing */\r
-    bool receive_hash : 1;              /* Data buffer should receive a hash/CRC calculation */\r
-    bool hash_data : 1;                 /* Indicates that the data needs hashing */\r
-    bool crc_data : 1;                  /* Indicates that the data needs CRC calculation */\r
-    bool encrypt_data : 1;              /* Indicates that the data need encrypting */\r
-    bool gcm_tag_data : 1;              /* Indicates that the data needs AES GCM tag */\r
-} kv_managed_source_buffer_t;\r
-\r
-/* Write buffer, used to gather chunks of data from one or more source buffers */\r
-typedef struct {\r
-    uint8_t *data;                /* RAM buffer used to hold chunks of data to be written to flash */\r
-    uint32_t write_location;      /* Current location in flash to write to */\r
-    uint32_t resume_location;     /* Write location reached when state machine was suspended */\r
-    uint32_t crypto_handle;       /* AES crypo handle */\r
-    uint16_t size;                /* Size of the RAM buffer */\r
-    uint16_t data_length;         /* Length of data written to RAM buffer */\r
-    uint32_t crc_ret;             /* crc_ret counter */\r
-    uint16_t data_consumed;       /* How much of the data has been written to flash */\r
-    bool hash_claimed : 1;        /* Hash function (SHA256) has been claimed */\r
-    bool encrypt_claimed : 1;     /* Encryption function (AES) has been claimed */\r
-    bool crc_claimed : 1;         /* CRC function has been claimed */\r
-    bool gcm_tag_claimed : 1;     /* AES GCM tag has been claimed */\r
-} kv_managed_write_buffer_t;\r
-\r
-/* State machine state transition table entry */\r
-typedef struct {\r
-    kv_update_state_t state : 5;       /* Current state                           */\r
-    kv_update_state_t next_state : 5;  /* State after the transition has occurred */\r
-    kv_update_event_t event : 5;       /* Event required to cause the transition (raised by an action function) */\r
-} kv_update_transition_t;\r
-\r
-/* State machine state action table entry */\r
-typedef struct {\r
-    kv_update_state_t state;   /* Applicable state             */\r
-    kv_state_action action;    /* Action function to be called */\r
-} kv_update_action_t;\r
-\r
-/* Structure used to describe a state machine */\r
-typedef struct {\r
-    const kv_update_transition_t *transition_table;  /* State Transition table for this state machine */\r
-    const kv_update_action_t *action_table;  /* State Action table for this state machine */\r
-    uint16_t write_buffer_size;        /* Size of the write buffer needed for this state machine */\r
-    kv_update_state_t initial_state;   /* State to set on initial entry to this state machine */\r
-    kv_update_state_t resume_state;    /* State to set on resuming this state machine */\r
-    kv_update_event_t exit_event;      /* Event to send to previous state machine, if no exit action function defined */\r
-} kv_state_machine_t;\r
-\r
-/* Used to hold run-time details of a state machine being processed */\r
-/* Individual state machines will often invoke a sub state machine.\r
- * These data structures will be used to form a linked list of currently active state machines, although only one\r
- * state machine is ever being processed at any one time.\r
- * The tail of the list will be the initial state machine, started by one of the four kv_update_xxx() functions at the\r
- * end of this file.\r
- * The head of the list will be the current state machine being actively processed.\r
- * The 'prev' field provides a path back to the initial state machine\r
- */\r
-typedef struct kv_active_state_machine_t {\r
-    struct kv_active_state_machine_t *prev;      /* Previous state machine. Will be NULL if this is a root machine */\r
-    const kv_state_machine_t *machine;           /* State machine being processed */\r
-    kv_managed_write_buffer_t *write_buffer;     /* Holds chunk of data to be written to flash */\r
-    kv_managed_source_buffer_t *source_buffer;   /* Linked list of source data buffers used to populate write buffer */\r
-    kv_managed_source_buffer_t *current_source;  /* Current source buffer being used */\r
-    kv_update_state_t state;                     /* Current state machine state */\r
-    kv_update_event_t event;                     /* Last event raised (will have caused transition to current state) */\r
-    errcode_t error_code;                       /* Records the error code produced when raising an error event */\r
-} kv_active_state_machine_t;\r
-\r
-errcode_t kv_update_init(cores_t core);\r
-errcode_t kv_update_erase_key(kv_store_t core, flash_task_node *sanitised_tasks);\r
-errcode_t kv_update_write_key(kv_store_t core, flash_task_node *sanitised_task);\r
-errcode_t kv_update_modify_attribute(kv_store_t core, flash_task_node *sanitised_task);\r
-errcode_t kv_update_backup_init(void);\r
-\r
-#ifdef __cplusplus\r
-#if __cplusplus\r
-}\r
-#endif /* __cplusplus */\r
-#endif /* __cplusplus */\r
-\r
-#endif\r
+/*
+ * Copyright (c) @CompanyNameMagicTag 2019-2022. All rights reserved.
+ * Description: KV Storage Library flash updating module interface
+ */
+
+#ifndef NV_UPDATE_H_
+#define NV_UPDATE_H_
+
+#ifdef CONFIG_NV_SUPPORT_SINGLE_CORE_SYSTEM
+#include "nv_task_adapt.h"
+#else
+#include "flash_task_types.h"
+#endif
+#include "nv_store.h"
+#include "errcode.h"
+#include "nv_porting.h"
+
+#ifdef __cplusplus
+#if __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+/* Unused states and events should be removed */
+typedef enum {
+    STATE_INVALID,
+
+    /* erase_all_keys, erase_old_keys, copy_all_keys */
+    STATE_SELECT_FIRST_PAGE,
+    STATE_SELECT_NEXT_PAGE,
+    STATE_FIND_FIRST_KEY,
+    STATE_FIND_NEXT_KEY,
+    STATE_FIND_EXISTING_KEY,
+    STATE_PREP_COPY_KEY,
+    STATE_PREP_DELETE_KEY,
+    STATE_PREP_MODIFY_KEY,
+    STATE_UPDATE_MAP_FOR_OLD,
+
+    /* prep_defrag_page, defrag_page */
+    STATE_FIND_DEFRAG,
+    STATE_ERASE_DEFRAG,
+    STATE_PREP_DEFRAG,
+    STATE_COPY_ALL_KEYS,
+    STATE_PREP_PAGE_HEADER,
+    STATE_WRITE_PAGE_HEADER,
+    STATE_UPDATE_NVREGION_MAP,
+
+    /* prepare_write */
+    STATE_FIND_WRITE_POS,
+    STATE_DEFRAG_PAGE,
+
+    /* write_key */
+    STATE_PREP_STORE,
+    STATE_PREP_KEY_DATA,
+    STATE_CLAIM_CRYPTO,
+    STATE_ERASE_OLD_KEYS,
+
+    STATE_PRIME_WRITE,
+    STATE_PERFORM_WRITE,
+    STATE_UPDATE_MAP_FOR_NEW,
+
+    STATE_SUSPENDED = 0x1E,
+    STATE_EXIT      = 0x1F
+} kv_update_state_t;
+
+typedef enum {
+    EVENT_NONE,
+    EVENT_SUSPEND,
+
+    EVENT_WRITE_DATA_EXHAUSTED,
+    EVENT_WRITE_BUFFER_PRIMED,
+    EVENT_WRITE_BUFFER_STORED,
+
+    /* erase_all_keys, erase_old_keys, copy_all_keys, modify_key */
+    EVENT_PAGE_SELECTED,
+    EVENT_PAGE_NOT_SELECTED,
+    EVENT_KEY_FOUND,
+    EVENT_KEY_NOT_FOUND,
+    EVENT_COPY_KEY_READY,
+
+    /* erase_all_keys */
+    EVENT_KEYS_ERASED,
+
+    /* modify_key */
+    EVENT_KEY_UPDATE_REQUIRED,
+    EVENT_KEY_UPDATE_NOT_NEEDED,
+
+    /* prep_defrag_page */
+    EVENT_DEFRAG_FOUND,
+    EVENT_DEFRAG_ERASED,
+
+    /* defrag_page */
+    EVENT_DEFRAG_PREPARED,
+    EVENT_ALL_KEYS_COPIED,
+    EVENT_PAGE_HEADER_READY,
+    EVENT_NVREGION_MAP_UPDATED,
+
+    /* prepare_write */
+    EVENT_DEFRAG_REQUIRED,
+    EVENT_DEFRAG_COMPLETE,
+    EVENT_WRITE_POS_FOUND,
+
+    /* write_key */
+    EVENT_STORE_READY,
+    EVENT_KEY_DATA_READY,
+    EVENT_CRYPTO_CLAIMED,
+    EVENT_WRITE_COMPLETE,
+    EVENT_PAGE_MAP_UPDATED,
+
+    EVENT_ERROR = 0x1F
+} kv_update_event_t;
+
+/* State machine action function */
+typedef kv_update_event_t (*kv_state_action)(void);
+
+/* Data to be written to flash can be scattered across a chain of one or more source buffers */
+typedef struct managed_source_buffer {
+    struct managed_source_buffer *next;      /* Pointer to next source buffer in chain */
+    uint8_t *data;                           /* Pointer to data in RAM/Flash */
+    uint16_t data_length;                    /* Length of the data */
+    uint16_t data_consumed;                  /* How much of the data has been read so far */
+    bool release_data : 1;              /* Data pointer is a temporary buffer that needs freeing */
+    bool receive_hash : 1;              /* Data buffer should receive a hash/CRC calculation */
+    bool hash_data : 1;                 /* Indicates that the data needs hashing */
+    bool crc_data : 1;                  /* Indicates that the data needs CRC calculation */
+    bool encrypt_data : 1;              /* Indicates that the data need encrypting */
+    bool gcm_tag_data : 1;              /* Indicates that the data needs AES GCM tag */
+} kv_managed_source_buffer_t;
+
+/* Write buffer, used to gather chunks of data from one or more source buffers */
+typedef struct {
+    uint8_t *data;                /* RAM buffer used to hold chunks of data to be written to flash */
+    uint32_t write_location;      /* Current location in flash to write to */
+    uint32_t resume_location;     /* Write location reached when state machine was suspended */
+    uint32_t crypto_handle;       /* AES crypo handle */
+    uint16_t size;                /* Size of the RAM buffer */
+    uint16_t data_length;         /* Length of data written to RAM buffer */
+    uint32_t crc_ret;             /* crc_ret counter */
+    uint16_t data_consumed;       /* How much of the data has been written to flash */
+    bool hash_claimed : 1;        /* Hash function (SHA256) has been claimed */
+    bool encrypt_claimed : 1;     /* Encryption function (AES) has been claimed */
+    bool crc_claimed : 1;         /* CRC function has been claimed */
+    bool gcm_tag_claimed : 1;     /* AES GCM tag has been claimed */
+} kv_managed_write_buffer_t;
+
+/* State machine state transition table entry */
+typedef struct {
+    kv_update_state_t state : 5;       /* Current state                           */
+    kv_update_state_t next_state : 5;  /* State after the transition has occurred */
+    kv_update_event_t event : 5;       /* Event required to cause the transition (raised by an action function) */
+} kv_update_transition_t;
+
+/* State machine state action table entry */
+typedef struct {
+    kv_update_state_t state;   /* Applicable state             */
+    kv_state_action action;    /* Action function to be called */
+} kv_update_action_t;
+
+/* Structure used to describe a state machine */
+typedef struct {
+    const kv_update_transition_t *transition_table;  /* State Transition table for this state machine */
+    const kv_update_action_t *action_table;  /* State Action table for this state machine */
+    uint16_t write_buffer_size;        /* Size of the write buffer needed for this state machine */
+    kv_update_state_t initial_state;   /* State to set on initial entry to this state machine */
+    kv_update_state_t resume_state;    /* State to set on resuming this state machine */
+    kv_update_event_t exit_event;      /* Event to send to previous state machine, if no exit action function defined */
+} kv_state_machine_t;
+
+/* Used to hold run-time details of a state machine being processed */
+/* Individual state machines will often invoke a sub state machine.
+ * These data structures will be used to form a linked list of currently active state machines, although only one
+ * state machine is ever being processed at any one time.
+ * The tail of the list will be the initial state machine, started by one of the four kv_update_xxx() functions at the
+ * end of this file.
+ * The head of the list will be the current state machine being actively processed.
+ * The 'prev' field provides a path back to the initial state machine
+ */
+typedef struct kv_active_state_machine_t {
+    struct kv_active_state_machine_t *prev;      /* Previous state machine. Will be NULL if this is a root machine */
+    const kv_state_machine_t *machine;           /* State machine being processed */
+    kv_managed_write_buffer_t *write_buffer;     /* Holds chunk of data to be written to flash */
+    kv_managed_source_buffer_t *source_buffer;   /* Linked list of source data buffers used to populate write buffer */
+    kv_managed_source_buffer_t *current_source;  /* Current source buffer being used */
+    kv_update_state_t state;                     /* Current state machine state */
+    kv_update_event_t event;                     /* Last event raised (will have caused transition to current state) */
+    errcode_t error_code;                       /* Records the error code produced when raising an error event */
+} kv_active_state_machine_t;
+
+errcode_t kv_update_init(cores_t core);
+errcode_t kv_update_erase_key(kv_store_t core, flash_task_node *sanitised_tasks);
+errcode_t kv_update_write_key(kv_store_t core, flash_task_node *sanitised_task);
+errcode_t kv_update_modify_attribute(kv_store_t core, flash_task_node *sanitised_task);
+errcode_t kv_update_backup_init(void);
+
+#ifdef __cplusplus
+#if __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+#endif
index 6e02770..101525c 100755 (executable)
-/*\r
- * Copyright (c) @CompanyNameMagicTag 2022-2022. All rights reserved.\r
- * Description: UPG KV functions source file\r
- */\r
-\r
-#include "nv_porting.h"\r
-#if (defined(CONFIG_OTA_UPDATE_SUPPORT) && (CONFIG_NV_SUPPORT_OTA_UPDATE == NV_YES))\r
-#include "upg_common.h"\r
-#include "upg_definitions.h"\r
-#include "nv_key.h"\r
-#include "nv_update.h"\r
-#include "nv_store.h"\r
-#include "nv.h"\r
-#include "nv_storage.h"\r
-#include "upg_porting.h"\r
-#include "upg_alloc.h"\r
-#include "nv_async_store.h"\r
-#include "nv_upg.h"\r
-\r
-#define KV_INDEX 0\r
-#define KV_CRC_DATA_LENGTH 4\r
-\r
-#ifndef UPG_VERIFY_CIPHER_BUF_ATTR\r
-#define UPG_VERIFY_CIPHER_BUF_ATTR    DRV_CIPHER_BUF_NONSECURE\r
-#endif\r
-#ifndef STATIC_UT\r
-#define STATIC_UT static\r
-#endif\r
-\r
-static inline uint32_t kv_aligned(uint32_t len, uint32_t align)\r
-{\r
-    return ((uint32_t)(len) + ((align) - 1)) & ~((align) - 1);\r
-}\r
-\r
-STATIC_UT bool kv_upg_upgrade_is_update_requested(fota_upgrade_flag_area_t *flag_info)\r
-{\r
-    upg_image_status_t status;\r
-    status = upg_get_image_update_status(flag_info, KV_INDEX, UPG_IMAGE_ID_NV);\r
-    if (status == UPG_IMAGE_STATUS_FINISHED || status == UPG_IMAGE_STATUS_NOT_STARTED) {\r
-        return false;\r
-    }\r
-    return true;\r
-}\r
-\r
-STATIC_UT errcode_t kv_upg_copy_pkg_image_data(uint32_t data_addr, uint32_t data_length,\r
-                                               uint32_t data_offset, uint32_t *data_len, uint8_t *img_data)\r
-{\r
-    errcode_t ret_val;\r
-    uint32_t aligned_image_len = kv_aligned(data_length, 16); /* 16-byte alignment */\r
-    uint32_t actual_len;\r
-\r
-    if (data_offset >= aligned_image_len || img_data == NULL ||\r
-        data_len == NULL || *data_len == 0) {\r
-        return ERRCODE_UPG_INVALID_PARAMETER;\r
-    }\r
-\r
-    actual_len = (data_offset + *data_len > aligned_image_len) ? (aligned_image_len - data_offset) : *data_len;\r
-    ret_val = upg_read_fota_pkg_data(data_addr + data_offset, img_data, &actual_len);\r
-    if (ret_val != ERRCODE_SUCC) {\r
-        return ret_val;\r
-    }\r
-    *data_len = actual_len;\r
-    return ERRCODE_SUCC;\r
-}\r
-\r
-STATIC_UT errcode_t kv_upg_upgrade_data_verify(uint32_t kv_data_offset, uint32_t kv_data_len, const uint8_t* hash_data)\r
-{\r
-    uint32_t handle;\r
-    uint32_t out_length = SHA_256_LENGTH;\r
-    uint32_t image_offset = 0;\r
-    uint8_t data_sha[SHA_256_LENGTH] = {0};\r
-    uint32_t aligned_image_len = kv_aligned(kv_data_len, 16); /* 16-byte alignment */\r
-\r
-    /* 考虑内存资源按0x1000处理 */\r
-    uint8_t *image_data = (uint8_t *)kv_malloc(VERIFY_BUFF_LEN);\r
-    if (image_data == NULL) {\r
-        return ERRCODE_MALLOC;\r
-    }\r
-\r
-    errcode_t ret = uapi_drv_cipher_sha256_start(&handle);\r
-    if (ret != ERRCODE_SUCC) {\r
-        kv_free(image_data);\r
-        return ret;\r
-    }\r
-\r
-    do {\r
-        uint32_t read_len = (image_offset + VERIFY_BUFF_LEN < aligned_image_len) ?\r
-            VERIFY_BUFF_LEN : (aligned_image_len - image_offset);\r
-        ret = kv_upg_copy_pkg_image_data(kv_data_offset, kv_data_len,\r
-                                         image_offset, &read_len, image_data);\r
-        if (ret != ERRCODE_SUCC) {\r
-            nv_log_err("[NV] kv upgrade kv_upg_copy_pkg_image_data error\r\n");\r
-            break;\r
-        }\r
-\r
-        ret = uapi_drv_cipher_sha256_update(handle, image_data, read_len);\r
-        if (ret != ERRCODE_SUCC) {\r
-            nv_log_err("[NV] kv upgrade uapi_drv_cipher_sha256_update error\r\n");\r
-            break;\r
-        }\r
-        image_offset += read_len;\r
-    } while (image_offset < aligned_image_len);\r
-\r
-    kv_free(image_data);\r
-    ret = uapi_drv_cipher_sha256_finish(handle, data_sha, &out_length);\r
-    if (ret != ERRCODE_SUCC) {\r
-        return ret;\r
-    }\r
-\r
-    if (memcmp(hash_data, data_sha, SHA_256_LENGTH) != 0) {\r
-        return ERRCODE_FAIL;\r
-    }\r
-    return ERRCODE_SUCC;\r
-}\r
-\r
-STATIC_UT errcode_t kv_upg_upgrade_key_helper(kv_store_t core, kv_key_header_t* key_header)\r
-{\r
-    uint8_t attributes;\r
-    flash_task_node task_node = {0};\r
-    if (key_header->valid == 0 && key_header->length == 0) {\r
-        task_node.data.kv_erase.key = key_header->key_id;\r
-        (void)kv_update_erase_key(core, &task_node);\r
-    } else {\r
-        attributes = 0;\r
-        if (key_header->upgrade == 0) {\r
-            attributes = NV_ATTRIBUTE_NON_UPGRADE;\r
-        }\r
-        /* 如果既是不可升级又是永久的,属性设置为永久即可 */\r
-        if (key_header->type == 0) {\r
-            attributes = NV_ATTRIBUTE_PERMANENT;\r
-        }\r
-\r
-        task_node.data.kv.key = key_header->key_id;\r
-        task_node.data.kv.kvalue = (uint8_t *)(key_header + 1);\r
-        task_node.data.kv.kvalue_length = key_header->length;\r
-        task_node.data.kv.attribute = attributes;\r
-        (void)kv_update_write_key(core, &task_node);\r
-    }\r
-    return task_node.state_code;\r
-}\r
-\r
-STATIC_UT bool kv_upg_check_upgradeable(kv_key_header_t* key_header)\r
-{\r
-    kv_attributes_t attr = 0;\r
-    uint16_t key_length = 0;\r
-\r
-    (void)kv_store_get_key_attr(KV_STORE_APPLICATION, key_header->key_id, &key_length, &attr);\r
-    if ((((uint32_t)attr & NV_ATTRIBUTE_PERMANENT) != 0) || (((uint32_t)attr & NV_ATTRIBUTE_NON_UPGRADE) != 0)) {\r
-        return false;\r
-    }\r
-    return true;\r
-}\r
-\r
-STATIC_UT kv_store_t kv_upg_convert_core_id(uint16_t core_id)\r
-{\r
-    switch (core_id) {\r
-        case KV_STORE_ID_ACPU:\r
-            return KV_STORE_APPLICATION;\r
-        default:\r
-            return KV_STORE_MAX_NUM;\r
-    }\r
-}\r
-\r
-STATIC_UT errcode_t kv_upg_process_one_page(kv_store_t core, uint8_t* image_data, uint32_t data_len)\r
-{\r
-    errcode_t ret;\r
-    uint32_t offset = 0;\r
-    kv_key_header_t* key_header = NULL;\r
-    uint32_t key_flash_size;\r
-    uint32_t key_length;\r
-\r
-    key_header = (kv_key_header_t *)image_data;\r
-    while (offset + sizeof(kv_key_header_t) <= data_len &&\r
-           offset + sizeof(kv_key_header_t) + key_header->length <= data_len) {\r
-        if (kv_upg_check_upgradeable(key_header)) {\r
-            ret = kv_upg_upgrade_key_helper(core, key_header);\r
-            if (ret != ERRCODE_FLASH_TASK_COMPLETED && ret != ERRCODE_NV_KEY_NOT_FOUND) {\r
-                nv_log_err("[NV] kv upgrade error keyid:0x%x\r\n", key_header->key_id);\r
-                return ret;\r
-            }\r
-        }\r
-        key_length = kv_aligned(key_header->length, 4); /* 4-byte alignment */\r
-        key_flash_size = (uint32_t)sizeof(kv_key_header_t) + key_length + KV_CRC_DATA_LENGTH;\r
-        offset += key_flash_size;\r
-        key_header = (kv_key_header_t *)((uintptr_t)key_header + key_flash_size);\r
-    }\r
-\r
-    return ERRCODE_SUCC;\r
-}\r
-\r
-STATIC_UT errcode_t kv_upg_process_kv_data(uint32_t kv_data_offset, uint32_t length)\r
-{\r
-    errcode_t ret;\r
-    uint32_t offset = 0;\r
-    uint32_t read_len;\r
-    kv_page_header_t *page_head = NULL;\r
-    kv_store_t core;\r
-\r
-    if (length % VERIFY_BUFF_LEN != 0) {\r
-        nv_log_err("[NV] kv upgrade data length error!\r\n");\r
-        return ERRCODE_FAIL;\r
-    }\r
-\r
-    uint8_t *image_data = (uint8_t *)kv_malloc(VERIFY_BUFF_LEN);\r
-    if (image_data == NULL) {\r
-        return ERRCODE_MALLOC;\r
-    }\r
-\r
-    while (offset < length) {\r
-        read_len = VERIFY_BUFF_LEN;\r
-        ret = kv_upg_copy_pkg_image_data(kv_data_offset, length, offset, &read_len, image_data);\r
-        if (ret != ERRCODE_SUCC) {\r
-            kv_free(image_data);\r
-            return ret;\r
-        }\r
-\r
-        page_head = (kv_page_header_t*)image_data;\r
-        core = kv_upg_convert_core_id(page_head->details.store_id);\r
-        if (core == KV_STORE_MAX_NUM) {\r
-            offset += VERIFY_BUFF_LEN;\r
-            continue;\r
-        }\r
-\r
-        ret = kv_upg_process_one_page(core, image_data + sizeof(kv_page_header_t), read_len - sizeof(kv_page_header_t));\r
-        if (ret != ERRCODE_SUCC) {\r
-            nv_log_err("[NV] kv upgrade data error read_len_:%d offset:%d\r\n", read_len, offset);\r
-            kv_free(image_data);\r
-            return ret;\r
-        }\r
-\r
-        offset += VERIFY_BUFF_LEN;\r
-    }\r
-    kv_free(image_data);\r
-    return ERRCODE_SUCC;\r
-}\r
-\r
-STATIC_UT errcode_t kv_upg_upgrade_process(fota_upgrade_flag_area_t* upg_flag)\r
-{\r
-    errcode_t ret;\r
-    uint32_t hash_read_len = upg_flag->nv_hash_len;\r
-\r
-    uint8_t *hash_data = (uint8_t *)kv_malloc(upg_flag->nv_hash_len);\r
-    if (hash_data == NULL) {\r
-        return ERRCODE_MALLOC;\r
-    }\r
-\r
-    ret = kv_upg_copy_pkg_image_data(upg_flag->nv_hash_offset, upg_flag->nv_hash_len,\r
-                                     0, &hash_read_len, hash_data);\r
-    if (ret != ERRCODE_SUCC) {\r
-        kv_free(hash_data);\r
-        return ret;\r
-    }\r
-\r
-    ret = kv_upg_upgrade_data_verify(upg_flag->nv_data_offset, upg_flag->nv_data_len, hash_data);\r
-    if (ret != ERRCODE_SUCC) {\r
-        nv_log_err("[NV] upg verify fail!\r\n");\r
-        kv_free(hash_data);\r
-        return ret;\r
-    }\r
-\r
-    kv_free(hash_data);\r
-\r
-    ret = kv_upg_process_kv_data(upg_flag->nv_data_offset, upg_flag->nv_data_len);\r
-\r
-    return ret;\r
-}\r
-\r
-#endif /* (defined(CONFIG_OTA_UPDATE_SUPPORT) && (CONFIG_NV_SUPPORT_OTA_UPDATE == NV_YES)) */\r
-\r
-errcode_t nv_upg_upgrade_task_process(void)\r
-{\r
-#if (defined(CONFIG_OTA_UPDATE_SUPPORT) && (CONFIG_NV_SUPPORT_OTA_UPDATE == NV_YES))\r
-\r
-    errcode_t ret;\r
-    upg_image_status_switch_t status;\r
-    fota_upgrade_flag_area_t *upg_flag_info = NULL;\r
-\r
-    ret = upg_alloc_and_get_upgrade_flag(&upg_flag_info);\r
-    if (ret != ERRCODE_SUCC || upg_flag_info == NULL) {\r
-        nv_log_err("[NV] get upgrade flag error!\r\n");\r
-        return ret;\r
-    }\r
-\r
-    if (kv_upg_upgrade_is_update_requested(upg_flag_info) == false) {\r
-        nv_log_info("[NV] Not need to upgrade NV ...\r\n");\r
-        upg_free(upg_flag_info);\r
-        return ERRCODE_SUCC;\r
-    }\r
-\r
-    ret = upg_set_firmware_update_status(upg_flag_info, UPG_IMAGE_ID_NV, UPG_IMAGE_STATUS_SWITCH_TO_STARTED);\r
-    if (ret != ERRCODE_SUCC) {\r
-        nv_log_err("[NV] upg set update status error\r\n");\r
-    }\r
-\r
-    ret = kv_upg_upgrade_process(upg_flag_info);\r
-    if (ret == ERRCODE_SUCC) {\r
-        nv_log_err("[NV] kv upgrade success!\r\n");\r
-        status = UPG_IMAGE_STATUS_SWITCH_TO_FINISHED;\r
-    } else {\r
-        nv_log_err("[NV] kv upgrade fail! error code:0x%x", ret);\r
-        status = UPG_IMAGE_STATUS_SWITCH_TO_RETRY;\r
-    }\r
-\r
-    ret = upg_set_firmware_update_status(upg_flag_info, UPG_IMAGE_ID_NV, status);\r
-    upg_free(upg_flag_info);\r
-\r
-    /* 升级成功之后再进行NV-Hashtable的初始化 */\r
-#if (CONFIG_NV_SUPPORT_ASYNCHRONOUS_STORE == NV_YES)\r
-    ret = nv_key_map_init(KV_STORE_APPLICATION, kv_store_get_page_count(KV_STORE_APPLICATION));\r
-#endif\r
-    return ret;\r
-\r
-#endif\r
-    return ERRCODE_SUCC;\r
-}\r
-\r
+/*
+ * Copyright (c) @CompanyNameMagicTag 2022-2022. All rights reserved.
+ * Description: UPG KV functions source file
+ */
+
+#include "nv_porting.h"
+#if (defined(CONFIG_OTA_UPDATE_SUPPORT) && (CONFIG_NV_SUPPORT_OTA_UPDATE == NV_YES))
+#include "upg_common.h"
+#include "upg_definitions.h"
+#include "nv_key.h"
+#include "nv_update.h"
+#include "nv_store.h"
+#include "nv.h"
+#include "nv_storage.h"
+#include "upg_porting.h"
+#include "upg_alloc.h"
+#include "nv_async_store.h"
+#include "nv_upg.h"
+
+#define KV_INDEX 0
+#define KV_CRC_DATA_LENGTH 4
+
+#ifndef UPG_VERIFY_CIPHER_BUF_ATTR
+#define UPG_VERIFY_CIPHER_BUF_ATTR    DRV_CIPHER_BUF_NONSECURE
+#endif
+#ifndef STATIC_UT
+#define STATIC_UT static
+#endif
+
+static inline uint32_t kv_aligned(uint32_t len, uint32_t align)
+{
+    return ((uint32_t)(len) + ((align) - 1)) & ~((align) - 1);
+}
+
+STATIC_UT bool kv_upg_upgrade_is_update_requested(fota_upgrade_flag_area_t *flag_info)
+{
+    upg_image_status_t status;
+    status = upg_get_image_update_status(flag_info, KV_INDEX, UPG_IMAGE_ID_NV);
+    if (status == UPG_IMAGE_STATUS_FINISHED || status == UPG_IMAGE_STATUS_NOT_STARTED) {
+        return false;
+    }
+    return true;
+}
+
+STATIC_UT errcode_t kv_upg_copy_pkg_image_data(uint32_t data_addr, uint32_t data_length,
+                                               uint32_t data_offset, uint32_t *data_len, uint8_t *img_data)
+{
+    errcode_t ret_val;
+    uint32_t aligned_image_len = kv_aligned(data_length, 16); /* 16-byte alignment */
+    uint32_t actual_len;
+
+    if (data_offset >= aligned_image_len || img_data == NULL ||
+        data_len == NULL || *data_len == 0) {
+        return ERRCODE_UPG_INVALID_PARAMETER;
+    }
+
+    actual_len = (data_offset + *data_len > aligned_image_len) ? (aligned_image_len - data_offset) : *data_len;
+    ret_val = upg_read_fota_pkg_data(data_addr + data_offset, img_data, &actual_len);
+    if (ret_val != ERRCODE_SUCC) {
+        return ret_val;
+    }
+    *data_len = actual_len;
+    return ERRCODE_SUCC;
+}
+
+STATIC_UT errcode_t kv_upg_upgrade_data_verify(uint32_t kv_data_offset, uint32_t kv_data_len, const uint8_t* hash_data)
+{
+    uint32_t handle;
+    uint32_t out_length = SHA_256_LENGTH;
+    uint32_t image_offset = 0;
+    uint8_t data_sha[SHA_256_LENGTH] = {0};
+    uint32_t aligned_image_len = kv_aligned(kv_data_len, 16); /* 16-byte alignment */
+
+    /* 考虑内存资源按0x1000处理 */
+    uint8_t *image_data = (uint8_t *)kv_malloc(VERIFY_BUFF_LEN);
+    if (image_data == NULL) {
+        return ERRCODE_MALLOC;
+    }
+
+    errcode_t ret = uapi_drv_cipher_sha256_start(&handle);
+    if (ret != ERRCODE_SUCC) {
+        kv_free(image_data);
+        return ret;
+    }
+
+    do {
+        uint32_t read_len = (image_offset + VERIFY_BUFF_LEN < aligned_image_len) ?
+            VERIFY_BUFF_LEN : (aligned_image_len - image_offset);
+        ret = kv_upg_copy_pkg_image_data(kv_data_offset, kv_data_len,
+                                         image_offset, &read_len, image_data);
+        if (ret != ERRCODE_SUCC) {
+            nv_log_err("[NV] kv upgrade kv_upg_copy_pkg_image_data error\r\n");
+            break;
+        }
+
+        ret = uapi_drv_cipher_sha256_update(handle, image_data, read_len);
+        if (ret != ERRCODE_SUCC) {
+            nv_log_err("[NV] kv upgrade uapi_drv_cipher_sha256_update error\r\n");
+            break;
+        }
+        image_offset += read_len;
+    } while (image_offset < aligned_image_len);
+
+    kv_free(image_data);
+    ret = uapi_drv_cipher_sha256_finish(handle, data_sha, &out_length);
+    if (ret != ERRCODE_SUCC) {
+        return ret;
+    }
+
+    if (memcmp(hash_data, data_sha, SHA_256_LENGTH) != 0) {
+        return ERRCODE_FAIL;
+    }
+    return ERRCODE_SUCC;
+}
+
+STATIC_UT errcode_t kv_upg_upgrade_key_helper(kv_store_t core, kv_key_header_t* key_header)
+{
+    uint8_t attributes;
+    flash_task_node task_node = {0};
+    if (key_header->valid == 0 && key_header->length == 0) {
+        task_node.data.kv_erase.key = key_header->key_id;
+        (void)kv_update_erase_key(core, &task_node);
+    } else {
+        attributes = 0;
+        if (key_header->upgrade == 0) {
+            attributes = NV_ATTRIBUTE_NON_UPGRADE;
+        }
+        /* 如果既是不可升级又是永久的,属性设置为永久即可 */
+        if (key_header->type == 0) {
+            attributes = NV_ATTRIBUTE_PERMANENT;
+        }
+
+        task_node.data.kv.key = key_header->key_id;
+        task_node.data.kv.kvalue = (uint8_t *)(key_header + 1);
+        task_node.data.kv.kvalue_length = key_header->length;
+        task_node.data.kv.attribute = attributes;
+        (void)kv_update_write_key(core, &task_node);
+    }
+    return task_node.state_code;
+}
+
+STATIC_UT bool kv_upg_check_upgradeable(kv_key_header_t* key_header)
+{
+    kv_attributes_t attr = 0;
+    uint16_t key_length = 0;
+
+    (void)kv_store_get_key_attr(KV_STORE_APPLICATION, key_header->key_id, &key_length, &attr);
+    if ((((uint32_t)attr & NV_ATTRIBUTE_PERMANENT) != 0) || (((uint32_t)attr & NV_ATTRIBUTE_NON_UPGRADE) != 0)) {
+        return false;
+    }
+    return true;
+}
+
+STATIC_UT kv_store_t kv_upg_convert_core_id(uint16_t core_id)
+{
+    switch (core_id) {
+        case KV_STORE_ID_ACPU:
+            return KV_STORE_APPLICATION;
+        default:
+            return KV_STORE_MAX_NUM;
+    }
+}
+
+STATIC_UT errcode_t kv_upg_process_one_page(kv_store_t core, uint8_t* image_data, uint32_t data_len)
+{
+    errcode_t ret;
+    uint32_t offset = 0;
+    kv_key_header_t* key_header = NULL;
+    uint32_t key_flash_size;
+    uint32_t key_length;
+
+    key_header = (kv_key_header_t *)image_data;
+    while (offset + sizeof(kv_key_header_t) <= data_len &&
+           offset + sizeof(kv_key_header_t) + key_header->length <= data_len) {
+        if (kv_upg_check_upgradeable(key_header)) {
+            ret = kv_upg_upgrade_key_helper(core, key_header);
+            if (ret != ERRCODE_FLASH_TASK_COMPLETED && ret != ERRCODE_NV_KEY_NOT_FOUND) {
+                nv_log_err("[NV] kv upgrade error keyid:0x%x\r\n", key_header->key_id);
+                return ret;
+            }
+        }
+        key_length = kv_aligned(key_header->length, 4); /* 4-byte alignment */
+        key_flash_size = (uint32_t)sizeof(kv_key_header_t) + key_length + KV_CRC_DATA_LENGTH;
+        offset += key_flash_size;
+        key_header = (kv_key_header_t *)((uintptr_t)key_header + key_flash_size);
+    }
+
+    return ERRCODE_SUCC;
+}
+
+STATIC_UT errcode_t kv_upg_process_kv_data(uint32_t kv_data_offset, uint32_t length)
+{
+    errcode_t ret;
+    uint32_t offset = 0;
+    uint32_t read_len;
+    kv_page_header_t *page_head = NULL;
+    kv_store_t core;
+
+    if (length % VERIFY_BUFF_LEN != 0) {
+        nv_log_err("[NV] kv upgrade data length error!\r\n");
+        return ERRCODE_FAIL;
+    }
+
+    uint8_t *image_data = (uint8_t *)kv_malloc(VERIFY_BUFF_LEN);
+    if (image_data == NULL) {
+        return ERRCODE_MALLOC;
+    }
+
+    while (offset < length) {
+        read_len = VERIFY_BUFF_LEN;
+        ret = kv_upg_copy_pkg_image_data(kv_data_offset, length, offset, &read_len, image_data);
+        if (ret != ERRCODE_SUCC) {
+            kv_free(image_data);
+            return ret;
+        }
+
+        page_head = (kv_page_header_t*)image_data;
+        core = kv_upg_convert_core_id(page_head->details.store_id);
+        if (core == KV_STORE_MAX_NUM) {
+            offset += VERIFY_BUFF_LEN;
+            continue;
+        }
+
+        ret = kv_upg_process_one_page(core, image_data + sizeof(kv_page_header_t), read_len - sizeof(kv_page_header_t));
+        if (ret != ERRCODE_SUCC) {
+            nv_log_err("[NV] kv upgrade data error read_len_:%d offset:%d\r\n", read_len, offset);
+            kv_free(image_data);
+            return ret;
+        }
+
+        offset += VERIFY_BUFF_LEN;
+    }
+    kv_free(image_data);
+    return ERRCODE_SUCC;
+}
+
+STATIC_UT errcode_t kv_upg_upgrade_process(fota_upgrade_flag_area_t* upg_flag)
+{
+    errcode_t ret;
+    uint32_t hash_read_len = upg_flag->nv_hash_len;
+
+    uint8_t *hash_data = (uint8_t *)kv_malloc(upg_flag->nv_hash_len);
+    if (hash_data == NULL) {
+        return ERRCODE_MALLOC;
+    }
+
+    ret = kv_upg_copy_pkg_image_data(upg_flag->nv_hash_offset, upg_flag->nv_hash_len,
+                                     0, &hash_read_len, hash_data);
+    if (ret != ERRCODE_SUCC) {
+        kv_free(hash_data);
+        return ret;
+    }
+
+    ret = kv_upg_upgrade_data_verify(upg_flag->nv_data_offset, upg_flag->nv_data_len, hash_data);
+    if (ret != ERRCODE_SUCC) {
+        nv_log_err("[NV] upg verify fail!\r\n");
+        kv_free(hash_data);
+        return ret;
+    }
+
+    kv_free(hash_data);
+
+    ret = kv_upg_process_kv_data(upg_flag->nv_data_offset, upg_flag->nv_data_len);
+
+    return ret;
+}
+
+#endif /* (defined(CONFIG_OTA_UPDATE_SUPPORT) && (CONFIG_NV_SUPPORT_OTA_UPDATE == NV_YES)) */
+
+errcode_t nv_upg_upgrade_task_process(void)
+{
+#if (defined(CONFIG_OTA_UPDATE_SUPPORT) && (CONFIG_NV_SUPPORT_OTA_UPDATE == NV_YES))
+
+    errcode_t ret;
+    upg_image_status_switch_t status;
+    fota_upgrade_flag_area_t *upg_flag_info = NULL;
+
+    ret = upg_alloc_and_get_upgrade_flag(&upg_flag_info);
+    if (ret != ERRCODE_SUCC || upg_flag_info == NULL) {
+        nv_log_err("[NV] get upgrade flag error!\r\n");
+        return ret;
+    }
+
+    if (kv_upg_upgrade_is_update_requested(upg_flag_info) == false) {
+        nv_log_info("[NV] Not need to upgrade NV ...\r\n");
+        upg_free(upg_flag_info);
+        return ERRCODE_SUCC;
+    }
+
+    ret = upg_set_firmware_update_status(upg_flag_info, UPG_IMAGE_ID_NV, UPG_IMAGE_STATUS_SWITCH_TO_STARTED);
+    if (ret != ERRCODE_SUCC) {
+        nv_log_err("[NV] upg set update status error\r\n");
+    }
+
+    ret = kv_upg_upgrade_process(upg_flag_info);
+    if (ret == ERRCODE_SUCC) {
+        nv_log_err("[NV] kv upgrade success!\r\n");
+        status = UPG_IMAGE_STATUS_SWITCH_TO_FINISHED;
+    } else {
+        nv_log_err("[NV] kv upgrade fail! error code:0x%x", ret);
+        status = UPG_IMAGE_STATUS_SWITCH_TO_RETRY;
+    }
+
+    ret = upg_set_firmware_update_status(upg_flag_info, UPG_IMAGE_ID_NV, status);
+    upg_free(upg_flag_info);
+
+    /* 升级成功之后再进行NV-Hashtable的初始化 */
+#if (CONFIG_NV_SUPPORT_ASYNCHRONOUS_STORE == NV_YES)
+    ret = nv_key_map_init(KV_STORE_APPLICATION, kv_store_get_page_count(KV_STORE_APPLICATION));
+#endif
+    return ret;
+
+#endif
+    return ERRCODE_SUCC;
+}
+
index b1fe2f0..79e0bef 100755 (executable)
@@ -1,25 +1,25 @@
-/*\r
- * Copyright (c) @CompanyNameMagicTag 2021-2022. All rights reserved.\r
- * Description: UPG nv functions header file\r
- */\r
-\r
-#ifndef NV_UPG_H\r
-#define NV_UPG_H\r
-\r
-#include "errcode.h"\r
-\r
-#ifdef __cplusplus\r
-#if __cplusplus\r
-extern "C" {\r
-#endif /* __cplusplus */\r
-#endif /* __cplusplus */\r
-\r
-errcode_t nv_upg_upgrade_task_process(void);\r
-\r
-#ifdef __cplusplus\r
-#if __cplusplus\r
-}\r
-#endif /* __cplusplus */\r
-#endif /* __cplusplus */\r
-\r
+/*
+ * Copyright (c) @CompanyNameMagicTag 2021-2022. All rights reserved.
+ * Description: UPG nv functions header file
+ */
+
+#ifndef NV_UPG_H
+#define NV_UPG_H
+
+#include "errcode.h"
+
+#ifdef __cplusplus
+#if __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
+errcode_t nv_upg_upgrade_task_process(void);
+
+#ifdef __cplusplus
+#if __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* __cplusplus */
+
 #endif /* NV_UPG_H */
\ No newline at end of file