From: SnickerSun Date: Thu, 29 Feb 2024 07:04:36 +0000 (+0800) Subject: 转换nv库源码为unix格式方便对比更新内容,修复uapi_nv_write 失效问题。解决write sn函数失效bug X-Git-Tag: release_V1.2.70_20241020_135402~1274^2~48 X-Git-Url: http://git.snicker.com.cn/Users/apple/Desktop/static/gitweb.css?a=commitdiff_plain;h=cd6bbedcb5e40dac21add655d3bf1f115e370e70;p=mirrors%2FFD230.git 转换nv库源码为unix格式方便对比更新内容,修复uapi_nv_write 失效问题。解决write sn函数失效bug --- diff --git a/code/sdk/drivers/peripheral/utils/custom_utils.c b/code/sdk/drivers/peripheral/utils/custom_utils.c index 24c6d5150..cdc14f367 100644 --- a/code/sdk/drivers/peripheral/utils/custom_utils.c +++ b/code/sdk/drivers/peripheral/utils/custom_utils.c @@ -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); diff --git a/code/sdk/drivers/peripheral/utils/custom_utils_at_cmd.c b/code/sdk/drivers/peripheral/utils/custom_utils_at_cmd.c index cf7a55235..ea9416ce2 100644 --- a/code/sdk/drivers/peripheral/utils/custom_utils_at_cmd.c +++ b/code/sdk/drivers/peripheral/utils/custom_utils_at_cmd.c @@ -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[] = { diff --git a/code/sdk/middleware/utils/nv/CMakeLists.txt b/code/sdk/middleware/utils/nv/CMakeLists.txt index 1549be868..0cce4a786 100755 --- a/code/sdk/middleware/utils/nv/CMakeLists.txt +++ b/code/sdk/middleware/utils/nv/CMakeLists.txt @@ -1,54 +1,54 @@ -#=============================================================================== -# @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 -) +#=============================================================================== +# @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 diff --git a/code/sdk/middleware/utils/nv/nv_storage_app/nv_storage.h b/code/sdk/middleware/utils/nv/nv_storage_app/nv_storage.h index 8fe59cdd7..75f1a8d13 100755 --- a/code/sdk/middleware/utils/nv/nv_storage_app/nv_storage.h +++ b/code/sdk/middleware/utils/nv/nv_storage_app/nv_storage.h @@ -1,102 +1,102 @@ -/* - * 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 */ +/* + * 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 */ diff --git a/code/sdk/middleware/utils/nv/nv_storage_app/soc_nv_storage.c b/code/sdk/middleware/utils/nv/nv_storage_app/soc_nv_storage.c index 255ee9461..99a09bbec 100755 --- a/code/sdk/middleware/utils/nv/nv_storage_app/soc_nv_storage.c +++ b/code/sdk/middleware/utils/nv/nv_storage_app/soc_nv_storage.c @@ -1,221 +1,225 @@ -/* - * 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) -{ - return uapi_nv_write_with_attr(key, kvalue, kvalue_length, NULL, 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; -} +/* + * 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; +} diff --git a/code/sdk/middleware/utils/nv/nv_storage_app/soc_nv_storage_handle.c b/code/sdk/middleware/utils/nv/nv_storage_app/soc_nv_storage_handle.c index 0c5fb3501..4c0fe326d 100755 --- a/code/sdk/middleware/utils/nv/nv_storage_app/soc_nv_storage_handle.c +++ b/code/sdk/middleware/utils/nv/nv_storage_app/soc_nv_storage_handle.c @@ -1,461 +1,461 @@ -/* - * 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"); -} +/* + * 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"); +} diff --git a/code/sdk/middleware/utils/nv/nv_storage_lib/nv_debug.c b/code/sdk/middleware/utils/nv/nv_storage_lib/nv_debug.c index 0523b23ba..cca261ff6 100644 --- a/code/sdk/middleware/utils/nv/nv_storage_lib/nv_debug.c +++ b/code/sdk/middleware/utils/nv/nv_storage_lib/nv_debug.c @@ -1,20 +1,20 @@ -/* - * 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_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; -} +/* + * 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; +} diff --git a/code/sdk/middleware/utils/nv/nv_storage_lib/nv_debug.h b/code/sdk/middleware/utils/nv/nv_storage_lib/nv_debug.h index bcb9f4b0c..5265e3fb3 100644 --- a/code/sdk/middleware/utils/nv/nv_storage_lib/nv_debug.h +++ b/code/sdk/middleware/utils/nv/nv_storage_lib/nv_debug.h @@ -1,37 +1,37 @@ -/* - * 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 */ +/* + * 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 */ diff --git a/code/sdk/middleware/utils/nv/nv_storage_lib/nv_key.c b/code/sdk/middleware/utils/nv/nv_storage_lib/nv_key.c index df44bae59..01cea3367 100755 --- a/code/sdk/middleware/utils/nv/nv_storage_lib/nv_key.c +++ b/code/sdk/middleware/utils/nv/nv_storage_lib/nv_key.c @@ -1,898 +1,898 @@ -/* - * 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)); +/* + * 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 diff --git a/code/sdk/middleware/utils/nv/nv_storage_lib/nv_key.h b/code/sdk/middleware/utils/nv/nv_storage_lib/nv_key.h index 33c36a125..52f498850 100755 --- a/code/sdk/middleware/utils/nv/nv_storage_lib/nv_key.h +++ b/code/sdk/middleware/utils/nv/nv_storage_lib/nv_key.h @@ -1,146 +1,146 @@ -/* - * 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 */ +/* + * 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 */ diff --git a/code/sdk/middleware/utils/nv/nv_storage_lib/nv_nvregion.c b/code/sdk/middleware/utils/nv/nv_storage_lib/nv_nvregion.c index 3348cb0cd..225c63cca 100755 --- a/code/sdk/middleware/utils/nv/nv_storage_lib/nv_nvregion.c +++ b/code/sdk/middleware/utils/nv/nv_storage_lib/nv_nvregion.c @@ -1,299 +1,299 @@ -/* - * 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; +/* + * 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 diff --git a/code/sdk/middleware/utils/nv/nv_storage_lib/nv_nvregion.h b/code/sdk/middleware/utils/nv/nv_storage_lib/nv_nvregion.h index 212c742f4..65768a0b6 100755 --- a/code/sdk/middleware/utils/nv/nv_storage_lib/nv_nvregion.h +++ b/code/sdk/middleware/utils/nv/nv_storage_lib/nv_nvregion.h @@ -1,65 +1,65 @@ -/* - * 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 */ +/* + * 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 */ diff --git a/code/sdk/middleware/utils/nv/nv_storage_lib/nv_page.c b/code/sdk/middleware/utils/nv/nv_storage_lib/nv_page.c index 917cab0c9..caad15f0f 100755 --- a/code/sdk/middleware/utils/nv/nv_storage_lib/nv_page.c +++ b/code/sdk/middleware/utils/nv/nv_storage_lib/nv_page.c @@ -1,142 +1,142 @@ -/* - * 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; -} +/* + * 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; +} diff --git a/code/sdk/middleware/utils/nv/nv_storage_lib/nv_page.h b/code/sdk/middleware/utils/nv/nv_storage_lib/nv_page.h index f2dfc09d4..f611223c8 100755 --- a/code/sdk/middleware/utils/nv/nv_storage_lib/nv_page.h +++ b/code/sdk/middleware/utils/nv/nv_storage_lib/nv_page.h @@ -1,73 +1,73 @@ -/* - * 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_ */ +/* + * 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_ */ diff --git a/code/sdk/middleware/utils/nv/nv_storage_lib/nv_reset.c b/code/sdk/middleware/utils/nv/nv_storage_lib/nv_reset.c index 90c1ba674..f6e2b4484 100755 --- a/code/sdk/middleware/utils/nv/nv_storage_lib/nv_reset.c +++ b/code/sdk/middleware/utils/nv/nv_storage_lib/nv_reset.c @@ -1,622 +1,622 @@ -/* - * 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; - } -} - +/* + * 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 diff --git a/code/sdk/middleware/utils/nv/nv_storage_lib/nv_reset.h b/code/sdk/middleware/utils/nv/nv_storage_lib/nv_reset.h index e1ed42e9a..ca884f064 100755 --- a/code/sdk/middleware/utils/nv/nv_storage_lib/nv_reset.h +++ b/code/sdk/middleware/utils/nv/nv_storage_lib/nv_reset.h @@ -1,55 +1,55 @@ -/* - * 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_ */ - +/* + * 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_ */ + diff --git a/code/sdk/middleware/utils/nv/nv_storage_lib/nv_rpc.c b/code/sdk/middleware/utils/nv/nv_storage_lib/nv_rpc.c index 5fd5e0fc4..c951ab237 100755 --- a/code/sdk/middleware/utils/nv/nv_storage_lib/nv_rpc.c +++ b/code/sdk/middleware/utils/nv/nv_storage_lib/nv_rpc.c @@ -1,96 +1,96 @@ -/* - * 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 +/* + * 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 diff --git a/code/sdk/middleware/utils/nv/nv_storage_lib/nv_rpc.h b/code/sdk/middleware/utils/nv/nv_storage_lib/nv_rpc.h index af8e6a452..04ef8206d 100755 --- a/code/sdk/middleware/utils/nv/nv_storage_lib/nv_rpc.h +++ b/code/sdk/middleware/utils/nv/nv_storage_lib/nv_rpc.h @@ -1,11 +1,11 @@ -/* - * 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_ */ +/* + * 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_ */ diff --git a/code/sdk/middleware/utils/nv/nv_storage_lib/nv_store.h b/code/sdk/middleware/utils/nv/nv_storage_lib/nv_store.h index 888937a69..32d4e426d 100755 --- a/code/sdk/middleware/utils/nv/nv_storage_lib/nv_store.h +++ b/code/sdk/middleware/utils/nv/nv_storage_lib/nv_store.h @@ -1,58 +1,58 @@ -/* - * 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_ */ +/* + * 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_ */ diff --git a/code/sdk/middleware/utils/nv/nv_storage_lib/nv_task_adapt.h b/code/sdk/middleware/utils/nv/nv_storage_lib/nv_task_adapt.h index dd860bc10..3b7365af5 100755 --- a/code/sdk/middleware/utils/nv/nv_storage_lib/nv_task_adapt.h +++ b/code/sdk/middleware/utils/nv/nv_storage_lib/nv_task_adapt.h @@ -1,173 +1,173 @@ -/* - * 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 */ - +/* + * 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 */ + diff --git a/code/sdk/middleware/utils/nv/nv_storage_lib/nv_update.c b/code/sdk/middleware/utils/nv/nv_storage_lib/nv_update.c index d7d92fef0..f38bae23a 100755 --- a/code/sdk/middleware/utils/nv/nv_storage_lib/nv_update.c +++ b/code/sdk/middleware/utils/nv/nv_storage_lib/nv_update.c @@ -1,1943 +1,1943 @@ -/* - * 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, ¤t_key); - if (res != ERRCODE_SUCC) { - return res; - } - - kv_attributes_t attributes = kv_key_attributes(¤t_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(¤t_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 -} - +/* + * 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, ¤t_key); + if (res != ERRCODE_SUCC) { + return res; + } + + kv_attributes_t attributes = kv_key_attributes(¤t_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(¤t_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 +} + diff --git a/code/sdk/middleware/utils/nv/nv_storage_lib/nv_update.h b/code/sdk/middleware/utils/nv/nv_storage_lib/nv_update.h index b61a463d1..530d623e6 100755 --- a/code/sdk/middleware/utils/nv/nv_storage_lib/nv_update.h +++ b/code/sdk/middleware/utils/nv/nv_storage_lib/nv_update.h @@ -1,201 +1,201 @@ -/* - * 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 +/* + * 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 diff --git a/code/sdk/middleware/utils/nv/nv_storage_lib/nv_upg.c b/code/sdk/middleware/utils/nv/nv_storage_lib/nv_upg.c index 6e027704d..101525cbd 100755 --- a/code/sdk/middleware/utils/nv/nv_storage_lib/nv_upg.c +++ b/code/sdk/middleware/utils/nv/nv_storage_lib/nv_upg.c @@ -1,316 +1,316 @@ -/* - * 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; -} - +/* + * 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; +} + diff --git a/code/sdk/middleware/utils/nv/nv_storage_lib/nv_upg.h b/code/sdk/middleware/utils/nv/nv_storage_lib/nv_upg.h index b1fe2f091..79e0bef0e 100755 --- a/code/sdk/middleware/utils/nv/nv_storage_lib/nv_upg.h +++ b/code/sdk/middleware/utils/nv/nv_storage_lib/nv_upg.h @@ -1,25 +1,25 @@ -/* - * 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 */ - +/* + * 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