From 7744b715b788dfe77f9484751c14302e7844bdbb Mon Sep 17 00:00:00 2001 From: Simon D Hughes Date: Wed, 8 Jun 2016 15:45:12 +0100 Subject: [PATCH 1/2] Integrating configuration-store into mbed-os --- TESTS/cfstore/add_del/add_del.cpp | 378 ++ TESTS/cfstore/close/close.cpp | 321 ++ TESTS/cfstore/create/create.cpp | 760 +++ TESTS/cfstore/example1/example1.cpp | 868 ++++ TESTS/cfstore/example2/example2.cpp | 328 ++ TESTS/cfstore/example3/example3.cpp | 393 ++ TESTS/cfstore/example4/example4.cpp | 278 ++ TESTS/cfstore/example5/example5.cpp | 365 ++ TESTS/cfstore/find/find.cpp | 443 ++ TESTS/cfstore/find2/find2.cpp | 310 ++ TESTS/cfstore/flash/flash.cpp | 752 +++ TESTS/cfstore/flush/flush.cpp | 638 +++ TESTS/cfstore/flush2/flush2.cpp | 333 ++ TESTS/cfstore/init/init.cpp | 223 + TESTS/cfstore/misc/misc.cpp | 460 ++ TESTS/cfstore/open/open.cpp | 702 +++ TESTS/cfstore/read/read.cpp | 265 ++ TESTS/cfstore/write/write.cpp | 272 ++ storage/cfstore/LICENSE | 8 + storage/cfstore/Makefile.scripts | 65 + storage/cfstore/README.md | 112 + storage/cfstore/VERSION | 3 + storage/cfstore/apache-2.0.txt | 13 + storage/cfstore/berkeley.txt | 31 + storage/cfstore/chernov.txt | 25 + .../configuration-store/configuration_store.h | 949 ++++ .../configuration_store_getting_started.md | 219 + .../doc/design/configuration_store_hld.md | 1096 +++++ .../doc/design/configuration_store_lld.md | 17 + ...onfiguration_store_product_requirements.md | 107 + .../doc/design/configuration_store_project.md | 99 + .../configuration_store_requirements.md | 410 ++ .../design/configuration_store_terminology.md | 34 + .../design/configuration_store_test_plan.md | 64 + ...store_hld_seqdiag_find_full_part_async.png | Bin 0 -> 102517 bytes ...fstore_hld_seqdiag_find_full_part_sync.png | Bin 0 -> 80867 bytes .../cfstrore_hld_seqdiag_create_async.png | Bin 0 -> 80397 bytes .../pics/cfstrore_hld_seqdiag_create_sync.png | Bin 0 -> 48422 bytes .../cfstrore_hld_seqdiag_find_full_async.png | Bin 0 -> 91234 bytes .../cfstrore_hld_seqdiag_find_full_sync.png | Bin 0 -> 60262 bytes .../cfstrore_hld_seqdiag_find_part_async.png | Bin 0 -> 87433 bytes .../cfstrore_hld_seqdiag_find_part_sync.png | Bin 0 -> 69455 bytes ...eqdiag_getversion_getcapabilities_sync.png | Bin 0 -> 27141 bytes ...cfstrore_hld_seqdiag_init_uninit_async.png | Bin 0 -> 48620 bytes .../cfstrore_hld_seqdiag_init_uninit_sync.png | Bin 0 -> 28332 bytes .../cfstrore_hld_seqdiag_open_read_async.png | Bin 0 -> 87797 bytes .../cfstrore_hld_seqdiag_open_read_sync.png | Bin 0 -> 56555 bytes .../cfstrore_hld_seqdiag_open_write_async.png | Bin 0 -> 84674 bytes .../cfstrore_hld_seqdiag_open_write_sync.png | Bin 0 -> 53033 bytes ...fstrore_hld_seqdiag_power_control_sync.png | Bin 0 -> 22644 bytes .../configuration_store_hld_api_summary.jpg | Bin 0 -> 295952 bytes .../design/umlet/configuartion_store_hld.uxf | 363 ++ .../project/configuration_store_releases.md | 68 + storage/cfstore/source/cfstore_config.h | 60 + storage/cfstore/source/cfstore_debug.h | 118 + storage/cfstore/source/cfstore_fnmatch.c | 325 ++ storage/cfstore/source/cfstore_fnmatch.h | 56 + storage/cfstore/source/cfstore_list.h | 63 + storage/cfstore/source/cfstore_test.c | 564 +++ storage/cfstore/source/cfstore_test.h | 84 + storage/cfstore/source/cfstore_utest.h | 76 + storage/cfstore/source/cfstore_uvisor.h | 121 + storage/cfstore/source/configuration_store.c | 4098 +++++++++++++++++ storage/cfstore/tatmanjants.txt | 30 + 64 files changed, 17367 insertions(+) create mode 100644 TESTS/cfstore/add_del/add_del.cpp create mode 100644 TESTS/cfstore/close/close.cpp create mode 100644 TESTS/cfstore/create/create.cpp create mode 100644 TESTS/cfstore/example1/example1.cpp create mode 100644 TESTS/cfstore/example2/example2.cpp create mode 100644 TESTS/cfstore/example3/example3.cpp create mode 100644 TESTS/cfstore/example4/example4.cpp create mode 100644 TESTS/cfstore/example5/example5.cpp create mode 100644 TESTS/cfstore/find/find.cpp create mode 100644 TESTS/cfstore/find2/find2.cpp create mode 100644 TESTS/cfstore/flash/flash.cpp create mode 100644 TESTS/cfstore/flush/flush.cpp create mode 100644 TESTS/cfstore/flush2/flush2.cpp create mode 100644 TESTS/cfstore/init/init.cpp create mode 100644 TESTS/cfstore/misc/misc.cpp create mode 100644 TESTS/cfstore/open/open.cpp create mode 100644 TESTS/cfstore/read/read.cpp create mode 100644 TESTS/cfstore/write/write.cpp create mode 100644 storage/cfstore/LICENSE create mode 100644 storage/cfstore/Makefile.scripts create mode 100644 storage/cfstore/README.md create mode 100644 storage/cfstore/VERSION create mode 100644 storage/cfstore/apache-2.0.txt create mode 100644 storage/cfstore/berkeley.txt create mode 100644 storage/cfstore/chernov.txt create mode 100644 storage/cfstore/configuration-store/configuration_store.h create mode 100644 storage/cfstore/doc/design/configuration_store_getting_started.md create mode 100644 storage/cfstore/doc/design/configuration_store_hld.md create mode 100644 storage/cfstore/doc/design/configuration_store_lld.md create mode 100644 storage/cfstore/doc/design/configuration_store_product_requirements.md create mode 100644 storage/cfstore/doc/design/configuration_store_project.md create mode 100644 storage/cfstore/doc/design/configuration_store_requirements.md create mode 100644 storage/cfstore/doc/design/configuration_store_terminology.md create mode 100644 storage/cfstore/doc/design/configuration_store_test_plan.md create mode 100644 storage/cfstore/doc/design/pics/cfstore_hld_seqdiag_find_full_part_async.png create mode 100644 storage/cfstore/doc/design/pics/cfstore_hld_seqdiag_find_full_part_sync.png create mode 100644 storage/cfstore/doc/design/pics/cfstrore_hld_seqdiag_create_async.png create mode 100644 storage/cfstore/doc/design/pics/cfstrore_hld_seqdiag_create_sync.png create mode 100644 storage/cfstore/doc/design/pics/cfstrore_hld_seqdiag_find_full_async.png create mode 100644 storage/cfstore/doc/design/pics/cfstrore_hld_seqdiag_find_full_sync.png create mode 100644 storage/cfstore/doc/design/pics/cfstrore_hld_seqdiag_find_part_async.png create mode 100644 storage/cfstore/doc/design/pics/cfstrore_hld_seqdiag_find_part_sync.png create mode 100644 storage/cfstore/doc/design/pics/cfstrore_hld_seqdiag_getversion_getcapabilities_sync.png create mode 100644 storage/cfstore/doc/design/pics/cfstrore_hld_seqdiag_init_uninit_async.png create mode 100644 storage/cfstore/doc/design/pics/cfstrore_hld_seqdiag_init_uninit_sync.png create mode 100644 storage/cfstore/doc/design/pics/cfstrore_hld_seqdiag_open_read_async.png create mode 100644 storage/cfstore/doc/design/pics/cfstrore_hld_seqdiag_open_read_sync.png create mode 100644 storage/cfstore/doc/design/pics/cfstrore_hld_seqdiag_open_write_async.png create mode 100644 storage/cfstore/doc/design/pics/cfstrore_hld_seqdiag_open_write_sync.png create mode 100644 storage/cfstore/doc/design/pics/cfstrore_hld_seqdiag_power_control_sync.png create mode 100644 storage/cfstore/doc/design/pics/configuration_store_hld_api_summary.jpg create mode 100644 storage/cfstore/doc/design/umlet/configuartion_store_hld.uxf create mode 100644 storage/cfstore/doc/project/configuration_store_releases.md create mode 100644 storage/cfstore/source/cfstore_config.h create mode 100644 storage/cfstore/source/cfstore_debug.h create mode 100644 storage/cfstore/source/cfstore_fnmatch.c create mode 100644 storage/cfstore/source/cfstore_fnmatch.h create mode 100644 storage/cfstore/source/cfstore_list.h create mode 100644 storage/cfstore/source/cfstore_test.c create mode 100644 storage/cfstore/source/cfstore_test.h create mode 100644 storage/cfstore/source/cfstore_utest.h create mode 100644 storage/cfstore/source/cfstore_uvisor.h create mode 100644 storage/cfstore/source/configuration_store.c create mode 100644 storage/cfstore/tatmanjants.txt diff --git a/TESTS/cfstore/add_del/add_del.cpp b/TESTS/cfstore/add_del/add_del.cpp new file mode 100644 index 0000000000..00ab84e7c9 --- /dev/null +++ b/TESTS/cfstore/add_del/add_del.cpp @@ -0,0 +1,378 @@ +/** @file add_del.cpp + * + * mbed Microcontroller Library + * Copyright (c) 2006-2016 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Test cases to add and delete KVs in the CFSTORE. + */ +#if defined __MBED__ && ! defined TOOLCHAIN_GCC_ARM + + +#include +#include +#include +#include + +#ifdef TARGET_LIKE_FRDM_K64F_GCC +#include +#endif + +#include "cfstore_config.h" +#include +#include "cfstore_debug.h" +#include "cfstore_test.h" +#include +#include "utest/utest.h" +#include "unity/unity.h" +#include "greentea-client/test_env.h" +#ifdef YOTTA_CFG_CFSTORE_UVISOR +#include "uvisor-lib/uvisor-lib.h" +#include "cfstore_uvisor.h" +#endif /* YOTTA_CFG_CFSTORE_UVISOR */ + +using namespace utest::v1; + +static control_t cfstore_add_del_test_00(const size_t call_count) +{ + (void) call_count; + printf("Not implemented for ARM toolchain\n"); + return CaseNext; +} + + +utest::v1::status_t greentea_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(100, "default_auto"); + return greentea_test_setup_handler(number_of_cases); +} + +Case cases[] = { + /* 1 2 3 4 5 6 7 */ + /* 1234567890123456789012345678901234567890123456789012345678901234567890 */ + Case("ADD_DEL_test_00", cfstore_add_del_test_00), +}; + + +/* Declare your test specification with a custom setup handler */ +Specification specification(greentea_setup, cases); + +int main() +{ + return !Harness::run(specification); +} + + +#else + + +#include +#include +#include +#include + +#ifdef TARGET_LIKE_FRDM_K64F_GCC +#include +#endif + +#include "cfstore_config.h" +//#include +#include +#include "cfstore_debug.h" +#include "cfstore_test.h" +#include +#include "utest/utest.h" +#include "unity/unity.h" +#include "greentea-client/test_env.h" +#include "cfstore_utest.h" +#ifdef YOTTA_CFG_CFSTORE_UVISOR +#include "uvisor-lib/uvisor-lib.h" +#include "cfstore_uvisor.h" +#endif /* YOTTA_CFG_CFSTORE_UVISOR */ + +using namespace utest::v1; + +static char cfstore_add_del_utest_msg_g[CFSTORE_UTEST_MSG_BUF_SIZE]; + +#ifdef YOTTA_CFG_CFSTORE_UVISOR +/* Create the main box ACL list for the application. + * The main ACL gets inherited by all the other boxes + */ +CFSTORE_UVISOR_MAIN_ACL(cfstore_acl_uvisor_box_add_del_g); + +/* Enable uVisor. */ +UVISOR_SET_MODE_ACL(UVISOR_ENABLED, cfstore_acl_uvisor_box_add_del_g); +#endif /* YOTTA_CFG_CFSTORE_UVISOR */ + +static cfstore_kv_data_t cfstore_add_del_test_07_data[] = { + CFSTORE_INIT_1_TABLE_MID_NODE, + { NULL, NULL}, +}; + + +/* report whether built/configured for flash sync or async mode */ +static control_t cfstore_add_del_test_00(const size_t call_count) +{ + (void) call_count; + ARM_CFSTORE_CAPABILITIES caps = cfstore_driver.GetCapabilities(); + CFSTORE_LOG("INITIALIZING: caps.asynchronous_ops=%lu\n", caps.asynchronous_ops); + return CaseNext; +} + +/** + * @brief test to open() a pre-existing key and try to write it, which should fail + * + * @return status code + * ARM_DRIVER_OK, the test passed successfully + * ret < ARM_DRIVER_OK, the test failed with the return code + * supplying more details + */ +static control_t cfstore_add_del_test_01_end(const size_t call_count) +{ + bool bfound = false; + int32_t ret = ARM_DRIVER_ERROR; + ARM_CFSTORE_SIZE len = 0; + ARM_CFSTORE_DRIVER* drv = &cfstore_driver; + ARM_CFSTORE_KEYDESC kdesc; + ARM_CFSTORE_HANDLE_INIT(hkey); + ARM_CFSTORE_FMODE flags; + + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + (void) call_count; + CFSTORE_LOG("cfstore_add_del_test_07: Start%s", "\n"); + memset(&kdesc, 0, sizeof(kdesc)); + memset(&flags, 0, sizeof(flags)); + + kdesc.drl = ARM_RETENTION_WHILE_DEVICE_ACTIVE; + len = strlen(cfstore_add_del_test_07_data[0].value); + + ret = cfstore_test_create(cfstore_add_del_test_07_data[0].key_name, (char*) cfstore_add_del_test_07_data[0].value, &len, &kdesc); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_add_del_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create KV in store (ret=%" PRId32 ").\n", __func__, ret); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_add_del_utest_msg_g); + + /* now delete KV*/ + ret = drv->Open(cfstore_add_del_test_07_data[0].key_name, flags, hkey); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_add_del_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to Open() (ret=%" PRId32 ").\n", __func__, ret); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_add_del_utest_msg_g); + + if(hkey != NULL){ + ret = drv->Delete(hkey); + drv->Close(hkey); + hkey = NULL; + } + /* check that the KV has been deleted */ + printf("LOG: WARNING: About to look for non-existent key (key_name=%s) (which will generate internal trace reporting errors if debug trace enabled).\n", cfstore_add_del_test_07_data[0].key_name); + ret = cfstore_test_kv_is_found(cfstore_add_del_test_07_data[0].key_name, &bfound); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_add_del_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error failed to delete a key (ret=%" PRId32 ").\n", __func__, ret); + TEST_ASSERT_MESSAGE(ret == ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND, cfstore_add_del_utest_msg_g); + + CFSTORE_TEST_UTEST_MESSAGE(cfstore_add_del_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Test failed: found KV that was previously deleted (key_name=%s)\n", __func__, cfstore_add_del_test_07_data[0].key_name); + TEST_ASSERT_MESSAGE(bfound == false, cfstore_add_del_utest_msg_g); + + ret = drv->Uninitialize(); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_add_del_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Uninitialize() call failed.\n", __func__); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_add_del_utest_msg_g); + return CaseNext; +} + + +static cfstore_kv_data_t cfstore_add_del_test_08_data[] = { + CFSTORE_INIT_1_TABLE_HEAD, + CFSTORE_INIT_1_TABLE_MID_NODE, + CFSTORE_INIT_1_TABLE_TAIL, + { NULL, NULL}, +}; + + +/** + * @brief test to add small number of KVs e.g. 3, and then delete them. + * basic delete test: + * - add key(s) + * - delete key(s) + * - make sure can't find key in cfstore + * + * @return status code + * ARM_DRIVER_OK, the test passed successfully + * ret < ARM_DRIVER_OK, the test failed with the return code + * supplying more details + */ +static control_t cfstore_add_del_test_02_end(const size_t call_count) +{ + bool bResult = true; // We'll do "&=" cumulative checking. + int32_t ret = ARM_DRIVER_ERROR; + ARM_CFSTORE_SIZE len = 0; + ARM_CFSTORE_KEYDESC kdesc; + cfstore_kv_data_t* node = NULL; + ARM_CFSTORE_DRIVER* drv = &cfstore_driver; + + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + (void) call_count; + CFSTORE_LOG("%s: Start\n", __func__); + memset(&kdesc, 0, sizeof(kdesc)); + + /* create */ + kdesc.drl = ARM_RETENTION_WHILE_DEVICE_ACTIVE; + node = cfstore_add_del_test_08_data; + while(node->key_name != NULL) + { + len = strlen(node->value); + ret = cfstore_test_create(node->key_name, (char*) node->value, &len, &kdesc); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_add_del_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create kv (key_name=%s.\n", __func__, node->key_name); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_add_del_utest_msg_g); + CFSTORE_LOG("Created KV successfully (key_name=\"%s\", value=\"%s\")\n", node->key_name, node->value); + node++; + } + + /* test delete all */ + ret = cfstore_test_delete_all(); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_add_del_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to delete all KVs.\n", __func__); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_add_del_utest_msg_g); + + /* check there are no KVs present as expected */ + node = cfstore_add_del_test_08_data; + while(node->key_name != NULL) + { + ret = cfstore_test_kv_is_found(node->key_name, &bResult); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_add_del_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: found key when should not be present.\n", __func__); + TEST_ASSERT_MESSAGE(ret == ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND && bResult == false, cfstore_add_del_utest_msg_g); + CFSTORE_LOG("Found KV successfully (key_name=\"%s\")\n", node->key_name); + node++; + } + ret = drv->Uninitialize(); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_add_del_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Uninitialize() call failed.\n", __func__); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_add_del_utest_msg_g); + return CaseNext; +} + +/** + * @brief add ~50 KVs, and then delete entries at the start, middle and end of sram area + * + * @return status code + * ARM_DRIVER_OK, the test passed successfully + * ret < ARM_DRIVER_OK, the test failed with the return code + * supplying more details + */ +static control_t cfstore_add_del_test_03_end(const size_t call_count) +{ + bool bfound = false; + int32_t ret = ARM_DRIVER_ERROR; + ARM_CFSTORE_FMODE flags; + cfstore_kv_data_t *node; + ARM_CFSTORE_DRIVER* drv = &cfstore_driver; + + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + (void) call_count; + memset(&flags, 0, sizeof(flags)); + + ret = cfstore_test_init_1(); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_add_del_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to initialise cfstore area with entries\n", __func__); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_add_del_utest_msg_g); + + /* delete some keys */ + node = cfstore_add_del_test_08_data; + while(node->key_name != NULL) + { + CFSTORE_DBGLOG("%s:about to delete key (key_name=%s).\n", __func__, node->key_name); + cfstore_test_delete(node->key_name); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_add_del_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error failed to delete a key (ret=%" PRId32 ").\n", __func__, ret); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_add_del_utest_msg_g); + CFSTORE_LOG("Deleted KV successfully (key_name=\"%s\")\n", node->key_name); + node++; + } + /* check the keys have been deleted */ + node = cfstore_add_del_test_08_data; + while(node->key_name != NULL) + { + ret = cfstore_test_kv_is_found(node->key_name, &bfound); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_add_del_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to delete a key (ret=%" PRId32 ").\n", __func__, ret); + TEST_ASSERT_MESSAGE(ret == ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND, cfstore_add_del_utest_msg_g); + + CFSTORE_TEST_UTEST_MESSAGE(cfstore_add_del_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Test failed: found KV that was previously deleted (key_name=%s)\n", __func__, node->key_name); + TEST_ASSERT_MESSAGE(bfound == false, cfstore_add_del_utest_msg_g); + node++; + } + + /* clean up by deleting all remaining KVs. this is not part of the test */ + ret = cfstore_test_delete_all(); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_add_del_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error failed to delete a all KVs (ret=%" PRId32 ").\n", __func__, ret); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_add_del_utest_msg_g); + + ret = drv->Uninitialize(); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_add_del_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to initialize CFSTORE (ret=%" PRId32 ")\n", __func__, ret); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_add_del_utest_msg_g); + return CaseNext; +} + + +/** + * @brief test as per test_09 but using delete_all() on all init_1 data. + * + * @return status code + * ARM_DRIVER_OK, the test passed successfully + * ret < ARM_DRIVER_OK, the test failed with the return code + * supplying more details + */ +static control_t cfstore_add_del_test_04(const size_t call_count) +{ + (void) call_count; + /*todo: implement test */ + CFSTORE_TEST_UTEST_MESSAGE(cfstore_add_del_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Warn: Not implemented\n", __func__); + CFSTORE_LOG("%s: WARN: requires implementation\n", __func__); + TEST_ASSERT_MESSAGE(true, cfstore_add_del_utest_msg_g); + return CaseNext; +} + + +utest::v1::status_t greentea_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(100, "default_auto"); + return greentea_test_setup_handler(number_of_cases); +} + +Case cases[] = { + /* 1 2 3 4 5 6 7 */ + /* 1234567890123456789012345678901234567890123456789012345678901234567890 */ + Case("ADD_DEL_test_00", cfstore_add_del_test_00), + Case("ADD_DEL_test_01_start", cfstore_utest_default_start), + Case("ADD_DEL_test_01_end", cfstore_add_del_test_01_end), + Case("ADD_DEL_test_02_start", cfstore_utest_default_start), + Case("ADD_DEL_test_02_end", cfstore_add_del_test_02_end), + Case("ADD_DEL_test_03_start", cfstore_utest_default_start), + Case("ADD_DEL_test_03_end", cfstore_add_del_test_03_end), + Case("ADD_DEL_test_04", cfstore_add_del_test_04), +}; + + +/* Declare your test specification with a custom setup handler */ +Specification specification(greentea_setup, cases); + +#if defined CFSTORE_CONFIG_MBED_OS_VERSION && CFSTORE_CONFIG_MBED_OS_VERSION == 3 +/* mbedosV3*/ +void app_start(int argc __unused, char** argv __unused) +{ + /* Run the test specification */ + Harness::run(specification); +} +#endif /* CFSTORE_CONFIG_MBED_OS_VERSION == 3 */ + +#if defined CFSTORE_CONFIG_MBED_OS_VERSION && CFSTORE_CONFIG_MBED_OS_VERSION == 4 +/* mbedosV3++*/ +int main() +{ + return !Harness::run(specification); +} +#endif /* CFSTORE_CONFIG_MBED_OS_VERSION == 4 */ + + +#endif // __MBED__ && ! defined TOOLCHAIN_GCC_ARM diff --git a/TESTS/cfstore/close/close.cpp b/TESTS/cfstore/close/close.cpp new file mode 100644 index 0000000000..44a0db38e9 --- /dev/null +++ b/TESTS/cfstore/close/close.cpp @@ -0,0 +1,321 @@ +/* + * @file close.cpp + * + * mbed Microcontroller Library + * Copyright (c) 2006-2016 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Test cases to close KVs in the CFSTORE using the drv->Cpen() interface. + */ +#if defined __MBED__ && ! defined TOOLCHAIN_GCC_ARM + + +#include +#include +#include +#include + +#ifdef TARGET_LIKE_FRDM_K64F_GCC +#include +#endif + +#include "cfstore_config.h" +#include +#include "cfstore_debug.h" +#include "cfstore_test.h" +#include +#include "utest/utest.h" +#include "unity/unity.h" +#include "greentea-client/test_env.h" +#ifdef YOTTA_CFG_CFSTORE_UVISOR +#include "uvisor-lib/uvisor-lib.h" +#include "cfstore_uvisor.h" +#endif /* YOTTA_CFG_CFSTORE_UVISOR */ + +using namespace utest::v1; + +static control_t cfstore_close_test_00(const size_t call_count) +{ + (void) call_count; + printf("Not implemented for ARM toolchain\n"); + return CaseNext; +} + + +utest::v1::status_t greentea_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(100, "default_auto"); + return greentea_test_setup_handler(number_of_cases); +} + +Case cases[] = { + /* 1 2 3 4 5 6 7 */ + /* 1234567890123456789012345678901234567890123456789012345678901234567890 */ + Case("CLOSE_test_00", cfstore_close_test_00), +}; + + +/* Declare your test specification with a custom setup handler */ +Specification specification(greentea_setup, cases); + +int main() +{ + return !Harness::run(specification); +} + + +#else + + +#include +#include +#include + +#ifdef TARGET_LIKE_FRDM_K64F_GCC +#include +#endif + +#include "cfstore_config.h" +//#include +#include +#include +#include "cfstore_test.h" +#include "cfstore_debug.h" +#include "utest/utest.h" +#include "unity/unity.h" +#include "greentea-client/test_env.h" +#include "cfstore_utest.h" +#ifdef YOTTA_CFG_CFSTORE_UVISOR +#include "uvisor-lib/uvisor-lib.h" +#endif /* YOTTA_CFG_CFSTORE_UVISOR */ + +using namespace utest::v1; + +static char cfstore_close_utest_msg_g[CFSTORE_UTEST_MSG_BUF_SIZE]; + +/* Configure secure box. */ +#ifdef YOTTA_CFG_CFSTORE_UVISOR +UVISOR_BOX_NAMESPACE("com.arm.mbed.cfstore.test.close.box1"); +UVISOR_BOX_CONFIG(cfstore_close_box1, UVISOR_BOX_STACK_SIZE); +#endif /* YOTTA_CFG_CFSTORE_UVISOR */ + +/* KV data for test_01 */ +static cfstore_kv_data_t cfstore_close_test_01_kv_data[] = { + { "yotta.hello-world.animal{wobbly-dog}{foot}frontLeft", "first_data_"}, + { "yotta.hello-world.animal{wobbly-dog}{foot}frontLeft", "second_data"}, + { NULL, NULL}, +}; + + +/* report whether built/configured for flash sync or async mode */ +static control_t cfstore_close_test_00(const size_t call_count) +{ + (void) call_count; + ARM_CFSTORE_CAPABILITIES caps = cfstore_driver.GetCapabilities(); + CFSTORE_LOG("INITIALIZING: caps.asynchronous_ops=%lu\n", caps.asynchronous_ops); + return CaseNext; +} + + +/** @brief basic test + * + * @note + * + * The test does the following: + * 01. create a key with handle hkey1 + * 02. write data of hkey + * 03. opens KV with 2nd handle, hkey2 + * 04. read data with hkey2 and make sure its the same as that written with hkey1 + * 05. write new data with hkey2 + * 06. delete hkey2 + * 07. close hkey2 + * 08. read hkey1 and make sure the data is the newly written data i.e. the key hasnt + * been deleted yet + * 09. try to open KV and make sure unable to do so, as KV is deleting + * 10. close hkey1 + * 11. try to open KV and make sure unable to do so because its now been deleted + * 12. create new KV with same key_name to make sure can re-create the key again. + * + * + * @return status code + * ARM_DRIVER_OK, the test passed successfully + * ret < ARM_DRIVER_OK, the test failed with the return code + * supplying more details + */ +static control_t cfstore_close_test_01_end(const size_t call_count) +{ + char read_buf[CFSTORE_KEY_NAME_MAX_LENGTH]; + int32_t ret = ARM_DRIVER_ERROR; + ARM_CFSTORE_SIZE len = 0; + ARM_CFSTORE_DRIVER* drv = &cfstore_driver; + ARM_CFSTORE_KEYDESC kdesc; + ARM_CFSTORE_HANDLE_INIT(hkey1); + ARM_CFSTORE_HANDLE_INIT(hkey2); + cfstore_kv_data_t *node; + ARM_CFSTORE_FMODE flags; + + CFSTORE_DBGLOG("%s:entered\n", __func__); + (void) call_count; + node = &cfstore_close_test_01_kv_data[0]; + memset(&kdesc, 0, sizeof(kdesc)); + memset(&flags, 0, sizeof(flags)); + memset(read_buf, 0, CFSTORE_KEY_NAME_MAX_LENGTH); + + /* step 01 */ + kdesc.drl = ARM_RETENTION_WHILE_DEVICE_ACTIVE; + CFSTORE_DBGLOG("%s:About to create new node (key_name=\"%s\", value=\"%s\")\n", __func__, node->key_name, node->value); + ret = drv->Create(node->key_name, strlen(node->value), &kdesc, hkey1); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_close_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create node (key_name=\"%s\", value=\"%s\")(ret=%" PRId32 ")\n", __func__, node->key_name, node->value, ret); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_close_utest_msg_g); + CFSTORE_DBGLOG("%s:length of KV=%d (key_name=\"%s\", value=\"%s\")\n", __func__, (int) len, node->key_name, node->value); + + /* step 02 */ + len = strlen(node->value); + ret = drv->Write(hkey1, (char*) node->value, &len); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_close_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to write key (key_name=\"%s\", value=\"%s\")(ret=%" PRId32 ")\n", __func__, node->key_name, node->value, ret); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_close_utest_msg_g); + + CFSTORE_TEST_UTEST_MESSAGE(cfstore_close_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to write full value data (key_name=\"%s\", value=\"%s\"), len=%d, (ret=%d)\n", __func__, node->key_name, node->value, (int) len, (int) ret); + TEST_ASSERT_MESSAGE(len == strlen(node->value), cfstore_close_utest_msg_g); + printf("Created KV successfully (key_name=\"%s\", value=\"%s\")\n", node->key_name, node->value); + + /* step 03: Now open second handle while keeping first handle open */ + flags.read = true; + flags.write = true; + ret = drv->Open(node->key_name, flags, hkey2); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_close_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to open node (key_name=\"%s\", value=\"%s\")(ret=%" PRId32 ")\n", __func__, node->key_name, node->value, ret); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_close_utest_msg_g); + len = strlen(node->value) + 1; + printf("Opened KV successfully (key_name=\"%s\", value=\"%s\")\n", node->key_name, node->value); + + /* step 04 */ + ret = drv->Read(hkey2, read_buf, &len); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_close_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to read key (key_name=\"%s\", value=\"%s\")\n", __func__, node->key_name, node->value); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_close_utest_msg_g); + + /* check read data is as expected */ + CFSTORE_TEST_UTEST_MESSAGE(cfstore_close_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: read value data (%s) != KV value data (key_name=\"%s\", value=\"%s\")\n", __func__, read_buf, node->key_name, node->value); + TEST_ASSERT_MESSAGE(strncmp(read_buf, node->value, strlen(node->value)) == 0, cfstore_close_utest_msg_g); + + /* step 05 write new data using hkey2 */ + node = &cfstore_close_test_01_kv_data[1]; + len = strlen(node->value); + ret = drv->Write(hkey2, (char*) node->value, &len); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_close_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to write key with 2nd handle (key_name=\"%s\", value=\"%s\")(ret=%" PRId32 ")\n", __func__, node->key_name, node->value, ret); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_close_utest_msg_g); + + CFSTORE_TEST_UTEST_MESSAGE(cfstore_close_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to write full value data (key_name=\"%s\", value=\"%s\"), len=%d, (ret=%" PRId32 ")\n", __func__, node->key_name, node->value, (int) len, ret); + TEST_ASSERT_MESSAGE(len == strlen(node->value), cfstore_close_utest_msg_g); + printf("Wrote KV successfully with new data (key_name=\"%s\", value=\"%s\")\n", node->key_name, node->value); + + /* step 06 delete hkey2 */ + ret = drv->Delete(hkey2); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_close_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to Delete KV with 2nd handle (key_name=\"%s\", value=\"%s\")(ret=%" PRId32 ")\n", __func__, node->key_name, node->value, ret); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_close_utest_msg_g); + + /* step 07 close hkey2 */ + ret = drv->Close(hkey2); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_close_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to Close KV with 2nd handle (key_name=\"%s\", value=\"%s\")(ret=%" PRId32 ")\n", __func__, node->key_name, node->value, ret); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_close_utest_msg_g); + + /* step 08 read hkey1 for updated data */ + len = strlen(node->value) + 1; + memset(read_buf, 0, len); + ret = drv->Read(hkey1, read_buf, &len); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_close_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to read key with hkey1 (key_name=\"%s\", value=\"%s\")\n", __func__, node->key_name, node->value); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_close_utest_msg_g); + + /* check read data is as expected */ + CFSTORE_TEST_UTEST_MESSAGE(cfstore_close_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: read value data (%s) != KV value data (key_name=\"%s\", value=\"%s\")\n", __func__, read_buf, node->key_name, node->value); + TEST_ASSERT_MESSAGE(strncmp(read_buf, node->value, strlen(node->value)) == 0, cfstore_close_utest_msg_g); + + /* step 09 */ + ret = drv->Open(node->key_name, flags, hkey2); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_close_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Should not be able to open pre-existing key in deleting state (key_name=\"%s\", value=\"%s\")(ret=%" PRId32 ")\n", __func__, node->key_name, node->value, ret); + TEST_ASSERT_MESSAGE(ret == ARM_CFSTORE_DRIVER_ERROR_PREEXISTING_KEY_DELETING || ret == ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND, cfstore_close_utest_msg_g); + + /* step 10 close hkey1 */ + ret = drv->Close(hkey1); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_close_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to Close KV with 1st handle (key_name=\"%s\", value=\"%s\")(ret=%" PRId32 ")\n", __func__, node->key_name, node->value, ret); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_close_utest_msg_g); + + /* step 11 try to open KV and make sure unable to do so because its now been deleted */ + ret = drv->Open(node->key_name, flags, hkey1); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_close_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Should not be able to open key as it should not be present in the CFSTORE (key_name=\"%s\", value=\"%s\")(ret=%" PRId32 ")\n", __func__, node->key_name, node->value, ret); + TEST_ASSERT_MESSAGE(ret == ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND, cfstore_close_utest_msg_g); + + /* step 12. create new KV with same key_name to make sure can re-create the key again. */ + node = &cfstore_close_test_01_kv_data[0]; + len = strlen(node->value); + kdesc.drl = ARM_RETENTION_WHILE_DEVICE_ACTIVE; + CFSTORE_DBGLOG("%s:About to create new node (key_name=\"%s\", value=\"%s\")\n", __func__, node->key_name, node->value); + ret = drv->Create(node->key_name, strlen(node->value), &kdesc, hkey1); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_close_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create node (key_name=\"%s\", value=\"%s\")(ret=%" PRId32 ")\n", __func__, node->key_name, node->value, ret); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_close_utest_msg_g); + CFSTORE_DBGLOG("%s:length of KV=%d (key_name=\"%s\", value=\"%s\")\n", __func__, (int) len, node->key_name, node->value); + + len = strlen(node->value); + ret = drv->Write(hkey1, (char*) node->value, &len); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_close_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to write key (key_name=\"%s\", value=\"%s\")(ret=%" PRId32 ")\n", __func__, node->key_name, node->value, ret); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_close_utest_msg_g); + + CFSTORE_TEST_UTEST_MESSAGE(cfstore_close_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to write full value data (key_name=\"%s\", value=\"%s\"), len=%d, (ret=%" PRId32 ")\n", __func__, node->key_name, node->value, (int) len, ret); + TEST_ASSERT_MESSAGE(len == strlen(node->value), cfstore_close_utest_msg_g); + + printf("Created KV successfully (key_name=\"%s\", value=\"%s\")\n", node->key_name, node->value); + + ret = drv->Uninitialize(); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_close_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Uninitialize() call failed.\n", __func__); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_close_utest_msg_g); + return CaseNext; +} + + +utest::v1::status_t greentea_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(100, "default_auto"); + return greentea_test_setup_handler(number_of_cases); +} + +Case cases[] = { + /* 1 2 3 4 5 6 7 */ + /* 1234567890123456789012345678901234567890123456789012345678901234567890 */ + Case("CLOSE_test_00", cfstore_close_test_00), + Case("CLOSE_test_01_start", cfstore_utest_default_start), + Case("CLOSE_test_01_end", cfstore_close_test_01_end) +}; + + +/* Declare your test specification with a custom setup handler */ +Specification specification(greentea_setup, cases); + +#if defined CFSTORE_CONFIG_MBED_OS_VERSION && CFSTORE_CONFIG_MBED_OS_VERSION == 3 +/* mbedosV3*/ +void app_start(int argc __unused, char** argv __unused) +{ + /* Run the test specification */ + Harness::run(specification); +} +#endif /* CFSTORE_CONFIG_MBED_OS_VERSION == 3 */ + +#if defined CFSTORE_CONFIG_MBED_OS_VERSION && CFSTORE_CONFIG_MBED_OS_VERSION == 4 +/* mbedosV3++*/ +int main() +{ + return !Harness::run(specification); +} +#endif /* CFSTORE_CONFIG_MBED_OS_VERSION == 4 */ + + +#endif // __MBED__ && ! defined TOOLCHAIN_GCC_ARM diff --git a/TESTS/cfstore/create/create.cpp b/TESTS/cfstore/create/create.cpp new file mode 100644 index 0000000000..03fb8603e0 --- /dev/null +++ b/TESTS/cfstore/create/create.cpp @@ -0,0 +1,760 @@ +/** @file create.cpp + * + * mbed Microcontroller Library + * Copyright (c) 2006-2016 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Test cases to create KVs in the CFSTORE using the drv->Create() API call. + */ +#if defined __MBED__ && ! defined TOOLCHAIN_GCC_ARM + + +#include +#include +#include +#include + +#ifdef TARGET_LIKE_FRDM_K64F_GCC +#include +#endif + +#include "cfstore_config.h" +#include +#include "cfstore_debug.h" +#include "cfstore_test.h" +#include +#include "utest/utest.h" +#include "unity/unity.h" +#include "greentea-client/test_env.h" +#ifdef YOTTA_CFG_CFSTORE_UVISOR +#include "uvisor-lib/uvisor-lib.h" +#include "cfstore_uvisor.h" +#endif /* YOTTA_CFG_CFSTORE_UVISOR */ + +using namespace utest::v1; + +static control_t cfstore_create_test_00(const size_t call_count) +{ + (void) call_count; + printf("Not implemented for ARM toolchain\n"); + return CaseNext; +} + + +utest::v1::status_t greentea_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(100, "default_auto"); + return greentea_test_setup_handler(number_of_cases); +} + +Case cases[] = { + /* 1 2 3 4 5 6 7 */ + /* 1234567890123456789012345678901234567890123456789012345678901234567890 */ + Case("CREATE_test_00", cfstore_create_test_00), +}; + + +/* Declare your test specification with a custom setup handler */ +Specification specification(greentea_setup, cases); + +int main() +{ + return !Harness::run(specification); +} + + + +#else + + +#include +#include +#include +#include + +#ifdef TARGET_LIKE_FRDM_K64F_GCC +#include +#endif + +#include "cfstore_config.h" +#include "cfstore_debug.h" +#include "cfstore_test.h" +//#include +#include +#include +#include "utest/utest.h" +#include "unity/unity.h" +#include "greentea-client/test_env.h" +#include "cfstore_utest.h" +#ifdef YOTTA_CFG_CFSTORE_UVISOR +#include "uvisor-lib/uvisor-lib.h" +#endif /* YOTTA_CFG_CFSTORE_UVISOR */ + +using namespace utest::v1; + +#ifdef CFSTORE_DEBUG +#define CFSTORE_CREATE_GREENTEA_TIMEOUT_S 360 +#else +#define CFSTORE_CREATE_GREENTEA_TIMEOUT_S 60 +#endif + +static char cfstore_create_utest_msg_g[CFSTORE_UTEST_MSG_BUF_SIZE]; + +/* Configure secure box. */ +#ifdef YOTTA_CFG_CFSTORE_UVISOR +UVISOR_BOX_NAMESPACE("com.arm.mbed.cfstore.test.create.box1"); +UVISOR_BOX_CONFIG(cfstore_create_box1, UVISOR_BOX_STACK_SIZE); +#endif /* YOTTA_CFG_CFSTORE_UVISOR */ + + +#define CFSTORE_CREATE_TEST_01_TABLE_HEAD_ENTRY_01 { "Lefkada.Vathi.Meganisi.Atokos.Vathi.Ithaki.PeriPigathi.AgiosAndreas.Sami.Kefalonia.AgiaEffimia.AgiaSofia.Fiskardo.Frikes.Kioni.Meganissi.Lefkada", "Penelope"} +#define CFSTORE_CREATE_TEST_01_TABLE_HEAD_ENTRY_02 { "Iolcus.Lemnos.Salmydessus.Cyzicus.Cios.Berbryces.Symplegadese.IsleAres.Colchis.Anenea.Sirens.Scylia.Charybdis.Phaeacia.Triton.Iolcus", "Medea"} +#define CFSTORE_CREATE_TEST_01_TABLE_HEAD_ENTRY_03 { "338.Chaeronea.336.Macedonia.334.Granicus.333.Issus.332.Tyre.331.Gaugamela.330.Persepolis.Philotas.Parmenion.329.Bactria.Oxus.Samarkand.328.Cleitus.327.Roxane.326.Hydaspes.Bucephalus.324.Hephaestion.323.AlexanderDies", "TheGreat"} +#define CFSTORE_CREATE_TEST_01_TABLE_MID_ENTRY_01 { "0123456789abcdef0123456", "abcdefghijklmnopqrstuvwxyz"} +#define CFSTORE_CREATE_TEST_01_TABLE_MID_ENTRY_02 { "0123456789abcdef0123456", "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"} +#define CFSTORE_CREATE_TEST_01_TABLE_MID_ENTRY_03 { "0123456789abcdef0123456", "nopqrstuvwxyz"} +#define CFSTORE_CREATE_TEST_01_TABLE_TAIL_ENTRY_01 { "Time.Will.Explain.It.All", "Aegeus"} +#define CFSTORE_CREATE_TEST_01_TABLE_TAIL_ENTRY_02 { "Cleverness.Is.Not.Wisdom", "Bacchae"} +#define CFSTORE_CREATE_TEST_01_TABLE_TAIL_ENTRY_03 { "Talk.Sense.To.A.Fool.And.He.Calls.You.Foolish", "Bacchae"} +#define CFSTORE_CREATE_TEST_01_TABLE_TAIL_ENTRY_04 { "There.is.in.the.worst.of.fortune.the.best.of.chances.for.a.happy.change", "Iphigenia.in.Tauris"} + +static cfstore_kv_data_t cfstore_create_test_01_data[] = { + CFSTORE_CREATE_TEST_01_TABLE_MID_ENTRY_01, + CFSTORE_CREATE_TEST_01_TABLE_MID_ENTRY_02, + CFSTORE_CREATE_TEST_01_TABLE_MID_ENTRY_03, + { NULL, NULL}, +}; + +/* table 1: to initialise cfstore with CFSTORE_CREATE_TEST_01_TABLE_MID_ENTRY_01 */ +static cfstore_kv_data_t cfstore_create_test_01_data_step_01[] = { + CFSTORE_CREATE_TEST_01_TABLE_HEAD_ENTRY_01, + CFSTORE_CREATE_TEST_01_TABLE_HEAD_ENTRY_02, + CFSTORE_CREATE_TEST_01_TABLE_HEAD_ENTRY_03, + CFSTORE_CREATE_TEST_01_TABLE_MID_ENTRY_01, + CFSTORE_CREATE_TEST_01_TABLE_TAIL_ENTRY_01, + CFSTORE_CREATE_TEST_01_TABLE_TAIL_ENTRY_02, + CFSTORE_CREATE_TEST_01_TABLE_TAIL_ENTRY_03, + CFSTORE_CREATE_TEST_01_TABLE_TAIL_ENTRY_04, + { NULL, NULL}, +}; + +/* table 2: to CFSTORE_CREATE_TEST_01_TABLE_MID_ENTRY_01 grown to CFSTORE_CREATE_TEST_01_TABLE_MID_ENTRY_02 */ +static cfstore_kv_data_t cfstore_create_test_01_data_step_02[] = { + CFSTORE_CREATE_TEST_01_TABLE_HEAD_ENTRY_01, + CFSTORE_CREATE_TEST_01_TABLE_HEAD_ENTRY_02, + CFSTORE_CREATE_TEST_01_TABLE_HEAD_ENTRY_03, + CFSTORE_CREATE_TEST_01_TABLE_MID_ENTRY_02, + CFSTORE_CREATE_TEST_01_TABLE_TAIL_ENTRY_01, + CFSTORE_CREATE_TEST_01_TABLE_TAIL_ENTRY_02, + CFSTORE_CREATE_TEST_01_TABLE_TAIL_ENTRY_03, + CFSTORE_CREATE_TEST_01_TABLE_TAIL_ENTRY_04, + { NULL, NULL}, +}; + +/* table 3: to CFSTORE_CREATE_TEST_01_TABLE_MID_ENTRY_02 shrunk to CFSTORE_CREATE_TEST_01_TABLE_MID_ENTRY_03 */ +static cfstore_kv_data_t cfstore_create_test_01_data_step_03[] = { + CFSTORE_CREATE_TEST_01_TABLE_HEAD_ENTRY_01, + CFSTORE_CREATE_TEST_01_TABLE_HEAD_ENTRY_02, + CFSTORE_CREATE_TEST_01_TABLE_HEAD_ENTRY_03, + CFSTORE_CREATE_TEST_01_TABLE_MID_ENTRY_03, + CFSTORE_CREATE_TEST_01_TABLE_TAIL_ENTRY_01, + CFSTORE_CREATE_TEST_01_TABLE_TAIL_ENTRY_02, + CFSTORE_CREATE_TEST_01_TABLE_TAIL_ENTRY_03, + CFSTORE_CREATE_TEST_01_TABLE_TAIL_ENTRY_04, + { NULL, NULL}, +}; + +/* table 3: CFSTORE_CREATE_TEST_01_TABLE_MID_ENTRY_03 deleted */ +static cfstore_kv_data_t cfstore_create_test_01_data_step_04[] = { + CFSTORE_CREATE_TEST_01_TABLE_HEAD_ENTRY_01, + CFSTORE_CREATE_TEST_01_TABLE_HEAD_ENTRY_02, + CFSTORE_CREATE_TEST_01_TABLE_HEAD_ENTRY_03, + CFSTORE_CREATE_TEST_01_TABLE_TAIL_ENTRY_01, + CFSTORE_CREATE_TEST_01_TABLE_TAIL_ENTRY_02, + CFSTORE_CREATE_TEST_01_TABLE_TAIL_ENTRY_03, + CFSTORE_CREATE_TEST_01_TABLE_TAIL_ENTRY_04, + { NULL, NULL}, +}; + +/* support functions */ + +/* @brief support function for generating value blob data */ +static int32_t cfstore_create_kv_value_gen(char* value, const size_t len) +{ + size_t i = 0; + size_t cpy_size = 0; + + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_create_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: value pointer is null.\n", __func__); + TEST_ASSERT_MESSAGE(value != NULL, cfstore_create_utest_msg_g); + + while(i < len) + { + cpy_size = len - i > CFSTORE_TEST_BYTE_DATA_TABLE_SIZE ? CFSTORE_TEST_BYTE_DATA_TABLE_SIZE : len - i; + memcpy(value + i, cfstore_test_byte_data_table, cpy_size); + i += cpy_size; + } + return ARM_DRIVER_OK; +} + + +static char* CFSTORE_CREATE_KV_CREATE_NO_TAG = NULL; + +/* @brief + * support function to create a KV + * - a kv name is generated with the length name_len + * - a kv value blob is generated with the length value_len + * + * @param name_len the length of the kv_name + * @param name_tag tag to append to name, intended to enable large number of unique strings + * @param value_buf buffer to use for storing the generated value data + * @param value_len the length of the value to generate + */ +static int32_t cfstore_create_kv_create(size_t name_len, char* name_tag, char* value_buf, size_t value_len) +{ + int32_t ret = ARM_DRIVER_OK; + size_t name_len_ex = name_len; + char kv_name[CFSTORE_KEY_NAME_MAX_LENGTH+1]; /* extra char for terminating null */ + ARM_CFSTORE_KEYDESC kdesc; + + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + memset(kv_name, 0, CFSTORE_KEY_NAME_MAX_LENGTH+1); + memset(&kdesc, 0, sizeof(kdesc)); + kdesc.drl = ARM_RETENTION_WHILE_DEVICE_ACTIVE; + + name_len_ex = name_len; + if(name_tag){ + name_len_ex += strlen(name_tag); + } + CFSTORE_TEST_UTEST_MESSAGE(cfstore_create_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: max supported KV name length for testing exceeded.\n", __func__); + TEST_ASSERT_MESSAGE(name_len_ex < CFSTORE_KEY_NAME_MAX_LENGTH+1, cfstore_create_utest_msg_g); + + ret = cfstore_test_kv_name_gen(kv_name, name_len); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_create_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: unable to generate kv_name.\n", __func__); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK , cfstore_create_utest_msg_g); + + /* append name tag */ + if(name_tag){ + strncat(kv_name, name_tag, CFSTORE_KEY_NAME_MAX_LENGTH); + } + + CFSTORE_TEST_UTEST_MESSAGE(cfstore_create_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: kv_name is not the correct length (name_len_ex=%d, expected=%d).\n", __func__, (int) strlen(kv_name), (int) name_len_ex); + TEST_ASSERT_MESSAGE(strlen(kv_name) == name_len_ex, cfstore_create_utest_msg_g); + + ret = cfstore_create_kv_value_gen(value_buf, value_len); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_create_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: unable to generate kv_name.\n", __func__); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK , cfstore_create_utest_msg_g); + + ret = cfstore_test_create(kv_name, value_buf, &value_len, &kdesc); + + if(ret == ARM_CFSTORE_DRIVER_ERROR_OUT_OF_MEMORY){ + CFSTORE_ERRLOG("%s: Error: out of memory\n", __func__); + return ret; + } + + CFSTORE_TEST_UTEST_MESSAGE(cfstore_create_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create KV in store for kv_name_good(ret=%" PRId32 ").\n", __func__, ret); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_create_utest_msg_g); + + return ret; +} + + +/* @brief cfstore_create_test_01() support function change the size of a value blob in the cfstore */ +static int32_t cfstore_create_test_KV_change(const cfstore_kv_data_t* old_node, const cfstore_kv_data_t* new_node ) +{ + int32_t ret = ARM_DRIVER_ERROR; + size_t len = 0; + ARM_CFSTORE_DRIVER* drv = &cfstore_driver; + ARM_CFSTORE_HANDLE_INIT(hkey); + ARM_CFSTORE_FMODE flags; + ARM_CFSTORE_KEYDESC kdesc; + + CFSTORE_DBGLOG("%s:entered\n", __func__); + memset(&flags, 0, sizeof(flags)); + memset(&kdesc, 0, sizeof(kdesc)); + + /* check node key_names are identical */ + if(strncmp(old_node->key_name, new_node->key_name, strlen(old_node->key_name)) != 0){ + CFSTORE_ERRLOG("%s:old and new entries so not have the same key_name (old_key_name=%s, new_key_name=%s).\n", __func__, old_node->key_name, new_node->key_name); + return ret; + } + len = strlen(new_node->value); + /* supply NULL key descriptor to open a pre-existing key for increasing the blob size */ + ret = drv->Create(new_node->key_name, len, NULL, hkey); + if(ret < ARM_DRIVER_OK){ + CFSTORE_ERRLOG("%s:Error: failed to change size of KV (key_name=%s)(ret=%d).\n", __func__, new_node->key_name, (int) ret); + goto out1; + } + len = strlen(new_node->value); + ret = drv->Write(hkey, new_node->value, &len); + if(ret < ARM_DRIVER_OK){ + CFSTORE_ERRLOG("%s:Error: failed to write KV (key_name=%s)(ret=%d).\n", __func__, new_node->key_name, (int) ret); + goto out2; + } + if(len != strlen(new_node->value)){ + CFSTORE_DBGLOG("%s:Failed wrote (%d) rather than the correct number of bytes (%d).\n", __func__, (int) len, (int) strlen(cfstore_create_test_01_data[1].value)); + goto out2; + } +out2: + drv->Close(hkey); +out1: + return ret; +} + +/* report whether built/configured for flash sync or async mode */ +static control_t cfstore_create_test_00(const size_t call_count) +{ + (void) call_count; + CFSTORE_LOG("INITIALIZING: caps.asynchronous_ops=%lu\n", cfstore_driver.GetCapabilities().asynchronous_ops); + return CaseNext; +} + + +/** + * @brief test to change the value blob size of pre-existing key + * + * @notes + * + * The test does the following: + * - creates a cfstore with ~10 entries. + * - for a mid-cfstore entry, grow the value blob size + * - check all the cfstore entries can be read correctly and their + * data agrees with the data supplied upon creation. + * - grow the mid-entry value blob size to be ~double the initial size. + * - check all the cfstore entries can be read correctly and their + * data agrees with the data supplied upon creation. + * + * @return status code + * ARM_DRIVER_OK, the test passed successfully + * ret < ARM_DRIVER_OK, the test failed with the return code + * supplying more details + */ +static control_t cfstore_create_test_01_end(const size_t call_count) +{ + int32_t ret = ARM_DRIVER_ERROR; + ARM_CFSTORE_FMODE flags; + cfstore_kv_data_t* node = NULL; + ARM_CFSTORE_DRIVER* drv = &cfstore_driver; + + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + (void) call_count; + memset(&flags, 0, sizeof(flags)); + + ret = cfstore_test_create_table(cfstore_create_test_01_data_step_01); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_create_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Failed to add cfstore_create_test_01_data_head (ret=%" PRId32 ").\n", __func__, ret); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_create_utest_msg_g); + + /* find cfstore_create_test_01_data[0] and grow the KV MID_ENTRY_01 to MID_ENTRY_02 */ + ret = cfstore_create_test_KV_change(&cfstore_create_test_01_data[0], &cfstore_create_test_01_data[1]); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_create_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Failed to increase size of KV (ret=%" PRId32 ").\n", __func__, ret); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_create_utest_msg_g); + + /* Now check that the KVs are all present and correct */ + node = cfstore_create_test_01_data_step_02; + while(node->key_name != NULL) + { + ret = cfstore_test_check_node_correct(node); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_create_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:node (key_name=\"%s\", value=\"%s\") not correct in cfstore\n", __func__, node->key_name, node->value); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_create_utest_msg_g); + node++; + } + CFSTORE_LOG("KV successfully increased in size and other KVs remained unchanged.%s", "\n"); + /* Shrink the KV from KV MID_ENTRY_02 to MID_ENTRY_03 */ + ret = cfstore_create_test_KV_change(&cfstore_create_test_01_data[1], &cfstore_create_test_01_data[2]); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_create_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Failed to decrease size of KV (ret=%" PRId32 ").\n", __func__, ret); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_create_utest_msg_g); + + /* Now check that the KVs are all present and correct */ + node = cfstore_create_test_01_data_step_03; + while(node->key_name != NULL) + { + ret = cfstore_test_check_node_correct(node); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_create_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:node (key_name=\"%s\", value=\"%s\") not correct in cfstore\n", __func__, node->key_name, node->value); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_create_utest_msg_g); + node++; + } + CFSTORE_LOG("KV successfully decreased in size and other KVs remained unchanged.%s", "\n"); + + /* Delete the KV */ + ret = cfstore_test_delete(cfstore_create_test_01_data[2].key_name); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_create_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:failed to delete node(key_name=\"%s\")\n", __func__, node->key_name); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_create_utest_msg_g); + + /* Now check that the KVs are all present and correct */ + node = cfstore_create_test_01_data_step_04; + while(node->key_name != NULL) + { + ret = cfstore_test_check_node_correct(node); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_create_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:node (key_name=\"%s\", value=\"%s\") not correct in cfstore\n", __func__, node->key_name, node->value); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_create_utest_msg_g); + node++; + } + ret = drv->Uninitialize(); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_create_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Uninitialize() call failed.\n", __func__); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_create_utest_msg_g); + return CaseNext; +} + + +/** + * @brief create the 10 kvs. + * @note + * The amount of data store in the cfstore is as follows: + * - 10 kvs + * - kv name lengths are ~220 => ~ 2200 bytes + * - value blob length is 1x256, 2x256, 3x256, ... 10x256)) = 256(1+2+3+4+..10) = 256*10*11/2 = 14080 + * - kv overhead = 8bytes/kv = 8 * 10 = 80bytes + * - total = (220*10)+256*10*11/2 10*8 = 143800 bytes + * + * + * @return status code + * ARM_DRIVER_OK, the test passed successfully + * ret < ARM_DRIVER_OK, the test failed with the return code + * supplying more details + */ +static int32_t cfstore_create_test_02_core(const size_t call_count) +{ + int32_t ret = ARM_DRIVER_ERROR; + uint32_t i = 0; + uint32_t bytes_stored = 0; + const uint32_t max_num_kvs_create = 10; + const size_t kv_name_min_len = CFSTORE_KEY_NAME_MAX_LENGTH - max_num_kvs_create; + const size_t kv_value_min_len = CFSTORE_TEST_BYTE_DATA_TABLE_SIZE; + const size_t max_value_buf_size = kv_value_min_len * (max_num_kvs_create +1); + char value_buf[max_value_buf_size]; + + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + (void) call_count; + memset(value_buf, 0, max_value_buf_size); + + for(i = 0; i < max_num_kvs_create; i++) + { + memset(value_buf, 0, max_value_buf_size); + ret = cfstore_create_kv_create(kv_name_min_len +i, CFSTORE_CREATE_KV_CREATE_NO_TAG, value_buf, kv_value_min_len * (i+1)); + bytes_stored += kv_name_min_len + i; /* kv_name */ + bytes_stored += kv_value_min_len * (i+1); /* kv value blob */ + bytes_stored += 8; /* kv overhead */ + if(ret == ARM_CFSTORE_DRIVER_ERROR_OUT_OF_MEMORY){ + CFSTORE_ERRLOG("Out of memory on %" PRId32 "-th KV, trying to allocate memory totalling %" PRIu32 ".\n", i, bytes_stored); + break; + } + CFSTORE_DBGLOG("Successfully stored %" PRId32 "-th KV bytes, totalling %" PRIu32 ".\n", i, bytes_stored); + } + ret = cfstore_test_delete_all(); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_create_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to delete_all() attributes to clean up after test (ret=%" PRId32 ").\n", __func__, ret); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_create_utest_msg_g); + return ret; +} + +static control_t cfstore_create_test_02_end(const size_t call_count) +{ + int32_t ret; + ARM_CFSTORE_DRIVER* drv = &cfstore_driver; + + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + (void) call_count; + + ret = cfstore_create_test_02_core(call_count); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_create_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: something went wrong (ret=%" PRId32 ").\n", __func__, ret); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_create_utest_msg_g); + + CFSTORE_TEST_UTEST_MESSAGE(cfstore_create_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Uninitialize() call failed.\n", __func__); + TEST_ASSERT_MESSAGE(drv->Uninitialize() >= ARM_DRIVER_OK, cfstore_create_utest_msg_g); + return CaseNext; +} + + +static control_t cfstore_create_test_03_end(const size_t call_count) +{ + int32_t i = 0; + int32_t ret; + ARM_CFSTORE_DRIVER* drv = &cfstore_driver; + + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + for(i = 0; i < 100; i++) + { + ret = cfstore_create_test_02_core(call_count); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_create_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: something went wrong (ret=%" PRId32 ").\n", __func__, ret); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_create_utest_msg_g); + CFSTORE_LOG("Successfully completed create/destroy loop %" PRId32 ".\n", i); + } + CFSTORE_TEST_UTEST_MESSAGE(cfstore_create_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Uninitialize() call failed.\n", __func__); + TEST_ASSERT_MESSAGE(drv->Uninitialize() >= ARM_DRIVER_OK, cfstore_create_utest_msg_g); + return CaseNext; +} + + +/** + * @brief create the 100 kvs to make the device run out of memory + * @note + * The amount of data store in the cfstore is as follows: + * - total = (220*100)+256*100*101/2 100*8 = 1315600 = 1.315x10^6 + * + * @return status code + * ARM_DRIVER_OK, the test passed successfully + * ret < ARM_DRIVER_OK, the test failed with the return code + * supplying more details + */ +static control_t cfstore_create_test_04_end(const size_t call_count) +{ + int32_t ret = ARM_DRIVER_ERROR; + uint32_t i = 0; + uint32_t bytes_stored = 0; + const uint32_t max_num_kvs_create = 100; + const size_t kv_name_min_len = CFSTORE_KEY_NAME_MAX_LENGTH - max_num_kvs_create; + const size_t kv_value_min_len = CFSTORE_TEST_BYTE_DATA_TABLE_SIZE; + const size_t max_value_buf_size = kv_value_min_len/8 * (max_num_kvs_create +1); + char* value_buf = NULL; + ARM_CFSTORE_DRIVER* drv = &cfstore_driver; + + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + (void) call_count; + value_buf = (char*) malloc(max_value_buf_size); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_create_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: out of memory.\n", __func__); + TEST_ASSERT_MESSAGE(value_buf != NULL, cfstore_create_utest_msg_g); + + for(i = 0; i < max_num_kvs_create; i++) + { + memset(value_buf, 0, max_value_buf_size); + ret = cfstore_create_kv_create(kv_name_min_len +i, CFSTORE_CREATE_KV_CREATE_NO_TAG, value_buf, kv_value_min_len/8 * (i+1)); + bytes_stored += kv_name_min_len + i; /* kv_name */ + bytes_stored += kv_value_min_len/8 * (i+1); /* kv value blob */ + bytes_stored += 8; /* kv overhead */ + if(ret == ARM_CFSTORE_DRIVER_ERROR_OUT_OF_MEMORY){ + CFSTORE_LOG("Out of memory on %" PRId32 "-th KV, trying to allocate memory totalling %" PRIu32 ".\n", i, bytes_stored); + break; + } + CFSTORE_LOG("Successfully stored %" PRId32 "-th KV bytes, totalling %" PRIu32 ".\n", i, bytes_stored); + } + ret = cfstore_test_delete_all(); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_create_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to delete_all() attributes to clean up after test (ret=%" PRId32 ").\n", __func__, ret); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_create_utest_msg_g); + free(value_buf); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_create_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Uninitialize() call failed.\n", __func__); + TEST_ASSERT_MESSAGE(drv->Uninitialize() >= ARM_DRIVER_OK, cfstore_create_utest_msg_g); + return CaseNext; +} + +/** + * @brief create the 500 kvs. + * @note + * The amount of data store in the cfstore is as follows: + * - total = (220*500)+(256/64)*500*501/2 500*8 = 8236000 = 8.236M + * + * @return status code + * ARM_DRIVER_OK, the test passed successfully + * ret < ARM_DRIVER_OK, the test failed with the return code + * supplying more details + */ +static control_t cfstore_create_test_05_end(const size_t call_count) +{ + int32_t ret = ARM_DRIVER_ERROR; + uint32_t i = 0; + uint32_t bytes_stored = 0; + const uint32_t max_num_kvs_create = 200; + const size_t kv_name_tag_len = 3; + const size_t kv_name_min_len = 10; + const size_t kv_value_min_len = CFSTORE_TEST_BYTE_DATA_TABLE_SIZE; + const size_t max_value_buf_size = kv_value_min_len/64 * (max_num_kvs_create+1); + char kv_name_tag_buf[kv_name_tag_len+1]; + char* value_buf = NULL; + ARM_CFSTORE_DRIVER* drv = &cfstore_driver; + + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + (void) call_count; + value_buf = (char*) malloc(max_value_buf_size); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_create_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: out of memory.\n", __func__); + TEST_ASSERT_MESSAGE(value_buf != NULL, cfstore_create_utest_msg_g); + + for(i = 0; i < max_num_kvs_create; i++) + { + memset(value_buf, 0, max_value_buf_size); + snprintf(kv_name_tag_buf, kv_name_tag_len+1, "%0d", (int) i); + ret = cfstore_create_kv_create(kv_name_min_len, kv_name_tag_buf, value_buf, kv_value_min_len/64 * (i+1)); + bytes_stored += kv_name_min_len + i + strlen(kv_name_tag_buf); /* kv_name */ + bytes_stored += kv_value_min_len/64 * (i+1); /* kv value blob */ + bytes_stored += 8; /* kv overhead */ + if(ret == ARM_CFSTORE_DRIVER_ERROR_OUT_OF_MEMORY){ + CFSTORE_LOG("Out of memory on %" PRId32 "-th KV, trying to allocate memory totalling %" PRIu32 ".\n", i, bytes_stored); + break; + } + CFSTORE_LOG("Successfully stored %" PRId32 "-th KV bytes, totalling %" PRIu32 ".\n", i, bytes_stored); + } + ret = cfstore_test_delete_all(); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_create_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to delete_all() attributes to clean up after test.\n", __func__); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_create_utest_msg_g); + free(value_buf); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_create_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Uninitialize() call failed.\n", __func__); + TEST_ASSERT_MESSAGE(drv->Uninitialize() >= ARM_DRIVER_OK, cfstore_create_utest_msg_g); + return CaseNext; +} + + +typedef struct cfstore_create_key_name_validate_t { + const char* key_name; + uint32_t f_allowed : 1; +} cfstore_create_key_name_validate_t; + +cfstore_create_key_name_validate_t cfstore_create_test_06_data[] = { + /* ruler for measuring text strings */ + /* 1 1 1 1 1 1 1 1 1 1 2 2 2 */ + /* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 */ + /* 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 */ + { "", false}, + { "abc.{1}.efg", true }, + { "abc.{1.efg", false }, + { "abc.1}.efg", false }, + { "abc.{{1}}.efg", false }, + { "abc.{}.efg", true }, + { "abc.}1{.efg", false }, + { ".piety.demands.us.to.honour.truth.above.our.friends", false }, + { "basement.medicine.pavement.government.trenchcoat.off.cough.off.kid.did.when.again.alleyway.friend.cap.pen.dollarbills.ten.foot.soot.put.but.anyway.say.May.DA.kid.did.toes.bows.those.hose.nose.clothes.man.blows.{100000000}", false }, + { NULL, false}, +}; + + +/** + * @brief function to test whether a key name can be created or not + * + * @param key_name + * name of the key to create in the store + * @param should_create + * if true, then create KV should succeed, otherwise should fail. + * + * @return status code + * ARM_DRIVER_OK, the test passed successfully + * ret < ARM_DRIVER_OK, the test failed with the return code + * supplying more details + */ +bool cfstore_create_key_name_validate(const char *key_name, bool should_create) +{ + bool bret = false; + char* test_data = (char*) "test_data"; + int32_t ret = ARM_DRIVER_ERROR; + ARM_CFSTORE_SIZE len = 0; + ARM_CFSTORE_KEYDESC kdesc; + + CFSTORE_FENTRYLOG("%s:entered\r\n", __func__); + memset(&kdesc, 0, sizeof(kdesc)); + + /* create */ + kdesc.drl = ARM_RETENTION_WHILE_DEVICE_ACTIVE; + len = strlen(test_data); + ret = cfstore_test_create((const char*) key_name, test_data, &len, &kdesc); + /* dont not use any functions that require finding the created item as they may not work, + * depending on the construction of the test key_name & match strings */ + if(should_create == true) + { + if(ret < ARM_DRIVER_OK){ + CFSTORE_ERRLOG("%s:Error: failed to create kv (key_name=%s.\r\n", __func__, key_name); + return bret; + } + CFSTORE_DBGLOG("%s:Success: Create() behaved as expected.\r\n", __func__); + /* delete using the actual name */ + ret = cfstore_test_delete((const char*) key_name); + if(ret < ARM_DRIVER_OK){ + CFSTORE_ERRLOG("%s:Error: failed to delete kv (key_name=%s)(ret=%d).\r\n", __func__, key_name, (int)ret); + } + bret = true; + } + else + { + if(ret >= ARM_DRIVER_OK){ + CFSTORE_ERRLOG("%s:Error: created kv (key_name=%s) when Create() should have failed.\r\n", __func__, key_name); + return bret; + } + /* the operation failed which was the expected result hence return true*/ + bret = true; + } + return bret; +} + +/** + * @brief check that key names with non-matching braces etc do no get created. + * + * @return status code + * ARM_DRIVER_OK, the test passed successfully + * ret < ARM_DRIVER_OK, the test failed with the return code + * supplying more details + */ +static control_t cfstore_create_test_06_end(const size_t call_count) +{ + bool ret = false; + int32_t ret32 = ARM_DRIVER_ERROR; + ARM_CFSTORE_DRIVER* drv = &cfstore_driver; + cfstore_create_key_name_validate_t* node = cfstore_create_test_06_data; + + (void) call_count; + + while(node->key_name != NULL) + { + ret = cfstore_create_key_name_validate(node->key_name, node->f_allowed); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_create_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: test failed (ret=%d, key_name=%s, f_allowed=%d)\n", __func__, (int) ret, node->key_name, node->f_allowed); + TEST_ASSERT_MESSAGE(ret == true, cfstore_create_utest_msg_g); + node++; + } + + ret32 = drv->Uninitialize(); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_create_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Uninitialize() call failed.\n", __func__); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_create_utest_msg_g); + return CaseNext; +} + +utest::v1::status_t greentea_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(CFSTORE_CREATE_GREENTEA_TIMEOUT_S, "default_auto"); + return greentea_test_setup_handler(number_of_cases); +} + +Case cases[] = { + /* 1 2 3 4 5 6 7 */ + /* 1234567890123456789012345678901234567890123456789012345678901234567890 */ + Case("CREATE_test_00", cfstore_create_test_00), + Case("CREATE_test_01_start", cfstore_utest_default_start), + Case("CREATE_test_01_end", cfstore_create_test_01_end), + Case("CREATE_test_02_start", cfstore_utest_default_start), + Case("CREATE_test_02_end", cfstore_create_test_02_end), + Case("CREATE_test_03_start", cfstore_utest_default_start), + Case("CREATE_test_03_end", cfstore_create_test_03_end), + Case("CREATE_test_04_start", cfstore_utest_default_start), + Case("CREATE_test_04_end", cfstore_create_test_04_end), + Case("CREATE_test_05_start", cfstore_utest_default_start), + Case("CREATE_test_05_end", cfstore_create_test_05_end), + Case("CREATE_test_06_start", cfstore_utest_default_start), + Case("CREATE_test_06_end", cfstore_create_test_06_end), +}; + + +/* Declare your test specification with a custom setup handler */ +Specification specification(greentea_setup, cases); + +#if defined CFSTORE_CONFIG_MBED_OS_VERSION && CFSTORE_CONFIG_MBED_OS_VERSION == 3 +/* mbedosV3*/ +void app_start(int argc __unused, char** argv __unused) +{ + /* Run the test specification */ + Harness::run(specification); +} +#endif /* CFSTORE_CONFIG_MBED_OS_VERSION == 3 */ + +#if defined CFSTORE_CONFIG_MBED_OS_VERSION && CFSTORE_CONFIG_MBED_OS_VERSION == 4 +/* mbedosV3++*/ +int main() +{ + return !Harness::run(specification); +} +#endif /* CFSTORE_CONFIG_MBED_OS_VERSION == 4 */ + + +#endif // __MBED__ && ! defined TOOLCHAIN_GCC_ARM diff --git a/TESTS/cfstore/example1/example1.cpp b/TESTS/cfstore/example1/example1.cpp new file mode 100644 index 0000000000..6792035f55 --- /dev/null +++ b/TESTS/cfstore/example1/example1.cpp @@ -0,0 +1,868 @@ +/** @file example1.cpp + * + * mbed Microcontroller Library + * Copyright (c) 2006-2016 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Test cases to add and delete KVs in the CFSTORE. + */ + + +/* EXAMPLE1 Notes + * ============== + * + * The example test does the following CFSTORE operations: + * - initialises + * - creates a key-value pair (KV). + * - writes the data for the KV + * - closes KV. + * - flushes the KV to flash + * - opens KV for reading. + * - reads KV and checks the value blob was the same as previously written. + * - closes KV. + * - finds a KV (there is only 1 to find). + * - for the KV returned, get the key name. + * - for the KV returned, get the value length. + * - for the KV returned, delete the KV. + * - find another KV (which fails as there are no more keys to find). + * - flushes the updated state to flash to store the removal of the deleted KV. + * - uninitialises + * - stops + * + * This test is coded so as to work in the following modes: + * - flash sync mode i.e. with caps.asynchronous_ops == false + * - flash async mode i.e. with caps.asynchronous_ops == true + * The dual async/sync mode support with the same code is more complicated + * than if the implementation just supported sync mode for example. However, + * it has the benefit of being more versatile. + * + * The test leaves the flash in the same state as at the beginning of the test so + * it can be run a second time on the device without flashing, and the test should + * still work. + * + */ +#if defined __MBED__ && ! defined TOOLCHAIN_GCC_ARM + + +#include +#include +#include +#include + +#ifdef TARGET_LIKE_FRDM_K64F_GCC +#include +#endif + +#include "cfstore_config.h" +#include +#include "cfstore_debug.h" +#include "cfstore_test.h" +#include +#include "utest/utest.h" +#include "unity/unity.h" +#include "greentea-client/test_env.h" +#ifdef YOTTA_CFG_CFSTORE_UVISOR +#include "uvisor-lib/uvisor-lib.h" +#include "cfstore_uvisor.h" +#endif /* YOTTA_CFG_CFSTORE_UVISOR */ + +using namespace utest::v1; + +static control_t cfstore_example1_test_00(const size_t call_count) +{ + (void) call_count; + printf("Not implemented for ARM toolchain\n"); + return CaseNext; +} + + +utest::v1::status_t greentea_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(100, "default_auto"); + return greentea_test_setup_handler(number_of_cases); +} + +Case cases[] = { + /* 1 2 3 4 5 6 7 */ + /* 1234567890123456789012345678901234567890123456789012345678901234567890 */ + Case("EXAMPLE1_test_00", cfstore_example1_test_00), +}; + + +/* Declare your test specification with a custom setup handler */ +Specification specification(greentea_setup, cases); + +int main() +{ + return !Harness::run(specification); +} + + + +#else + + + +#include +#include +#include + +#ifdef TARGET_LIKE_FRDM_K64F_GCC +#include +#endif +#ifndef YOTTA_CONFIGURATION_STORE_EXAMPLE1_VERSION_STRING +/* when built as Configuration-Store example, include greentea support otherwise omit */ +#include "utest/utest.h" +#include "unity/unity.h" +#include "greentea-client/test_env.h" +#else // YOTTA_CONFIGURATION_STORE_EXAMPLE1_VERSION_STRING +// map utest types for building as stand alone example +#define control_t void +#define CaseNext +#endif // YOTTA_CONFIGURATION_STORE_EXAMPLE1_VERSION_STRING + +#include +#include +#include "cfstore_config.h" +#include +#ifdef YOTTA_CFG_CONFIG_UVISOR +#include "uvisor-lib/uvisor-lib.h" +#endif /* YOTTA_CFG_CONFIG_UVISOR */ + + +#ifndef YOTTA_CONFIGURATION_STORE_EXAMPLE1_VERSION_STRING +using namespace utest::v1; +#endif + + +#define CFSTORE_EX1_TEST_ASSERT(Expr) if (!(Expr)) { printf("%s:%u: assertion failure\r\n", __FUNCTION__, __LINE__); while (1) ;} +#define CFSTORE_EX1_TEST_ASSERT_EQUAL(expected, actual) if ((expected) != (actual)) {printf("%s:%u: assertion failure\r\n", __FUNCTION__, __LINE__); while (1) ;} +#define CFSTORE_EX1_TEST_ASSERT_NOT_EQUAL(expected, actual) if ((expected) == (actual)) {printf("%s:%u: assertion failure\r\n", __FUNCTION__, __LINE__); while (1) ;} + +#define CFSTORE_EX1_TEST_ASSERT_MSG(Expr, _fmt, ...) \ + do \ + { \ + if (!(Expr)) \ + { \ + printf(_fmt, __VA_ARGS__); \ + while (1) ; \ + } \ + }while(0); + +#define CFSTORE_EX1_LOG(_fmt, ...) \ + do \ + { \ + printf(_fmt, __VA_ARGS__); \ + }while(0); + + +const char* cfstore_ex_opcode_str[] = +{ + "UNDEFINED", + "CFSTORE_OPCODE_CLOSE", + "CFSTORE_OPCODE_CREATE", + "CFSTORE_OPCODE_DELETE", + "CFSTORE_OPCODE_FIND", + "CFSTORE_OPCODE_FLUSH", + "CFSTORE_OPCODE_GET_KEY_NAME", + "CFSTORE_OPCODE_GET_STATUS", + "CFSTORE_OPCODE_GET_VALUE_LEN", + "CFSTORE_OPCODE_INITIALIZE", + "CFSTORE_OPCODE_OPEN", + "CFSTORE_OPCODE_POWER_CONTROL", + "CFSTORE_OPCODE_READ", + "CFSTORE_OPCODE_RSEEK", + "CFSTORE_OPCODE_UNINITIALIZE", + "CFSTORE_OPCODE_WRITE", + "CFSTORE_OPCODE_MAX" +}; + +bool cfstore_example1_done = false; +const char* cfstore_ex_kv_name = "basement.medicine.pavement.government.trenchcoat.off.cough.off.kid.did.when.again.alleyway.friend.cap.pen.dollarbills.ten.foot.soot.put.but.anyway.say.May.DA.kid.did.toes.bows.those.hose.nose.clothes.man.blows.well.well"; +const char* cfstore_ex_kv_value = "TheRollingStone"; +#define CFSTORE_EX1_RSEEK_OFFSET 10 /* offset to S of Stone */ + +typedef enum cfstore_ex_state_t { + CFSTORE_EX_STATE_INITIALIZING = 1, + CFSTORE_EX_STATE_INIT_DONE, + CFSTORE_EX_STATE_CREATING, + CFSTORE_EX_STATE_CREATE_DONE, + CFSTORE_EX_STATE_WRITING, + CFSTORE_EX_STATE_WRITE_DONE, + CFSTORE_EX_STATE_CLOSING1, + CFSTORE_EX_STATE_CLOSE_DONE1, + CFSTORE_EX_STATE_FLUSHING1, + CFSTORE_EX_STATE_FLUSH_DONE1, + CFSTORE_EX_STATE_OPENING, + CFSTORE_EX_STATE_OPEN_DONE, + CFSTORE_EX_STATE_READING1, + CFSTORE_EX_STATE_READ_DONE1, + CFSTORE_EX_STATE_RSEEKING, + CFSTORE_EX_STATE_RSEEK_DONE, + CFSTORE_EX_STATE_READING2, + CFSTORE_EX_STATE_READ_DONE2, + CFSTORE_EX_STATE_CLOSING2, + CFSTORE_EX_STATE_CLOSE_DONE2, + CFSTORE_EX_STATE_FINDING1, + CFSTORE_EX_STATE_FIND_DONE1, + CFSTORE_EX_STATE_GETTING_KEY_NAME, + CFSTORE_EX_STATE_GET_KEY_NAME_DONE, + CFSTORE_EX_STATE_GETTING_VALUE_LEN, + CFSTORE_EX_STATE_GET_VALUE_LEN_DONE, + CFSTORE_EX_STATE_DELETING, + CFSTORE_EX_STATE_DELETE_DONE, + CFSTORE_EX_STATE_FINDING2, + CFSTORE_EX_STATE_FIND_DONE2, + CFSTORE_EX_STATE_FLUSHING2, + CFSTORE_EX_STATE_FLUSH_DONE2, + CFSTORE_EX_STATE_UNINITIALIZING, + CFSTORE_EX_STATE_UNINIT_DONE +} cfstore_ex_state_t; + +typedef struct cfstore_example1_ctx_t +{ + ARM_CFSTORE_CAPABILITIES caps;; + uint8_t hkey[CFSTORE_HANDLE_BUFSIZE]; + uint8_t hkey_next_buf[CFSTORE_HANDLE_BUFSIZE]; + uint8_t hkey_prev_buf[CFSTORE_HANDLE_BUFSIZE]; + ARM_CFSTORE_HANDLE hkey_next; + ARM_CFSTORE_HANDLE hkey_prev; + cfstore_ex_state_t state; + ARM_CFSTORE_SIZE len; + ARM_CFSTORE_KEYDESC kdesc; + ARM_CFSTORE_FMODE flags; + char value[CFSTORE_KEY_NAME_MAX_LENGTH+1]; + /* callback attributes*/ + int32_t callback_status; + ARM_CFSTORE_HANDLE callback_handle; +} cfstore_example1_ctx_t; + +static cfstore_example1_ctx_t cfstore_example1_ctx_g; + +extern ARM_CFSTORE_DRIVER cfstore_driver; +ARM_CFSTORE_DRIVER *cfstore_drv = &cfstore_driver; + +/* forward declarations */ +static void cfstore_ex_fms_update(cfstore_example1_ctx_t* ctx); + + +static void cfstore_ex_callback(int32_t status, ARM_CFSTORE_OPCODE cmd_code, void *client_context, ARM_CFSTORE_HANDLE handle) +{ + (void) handle; + + cfstore_example1_ctx_t* ctx = (cfstore_example1_ctx_t*) client_context; + + /* CFSTORE_EX1_LOG("%s:entered: status=%d, cmd_code=%d (%s) handle=%p\r\n", __func__, (int) status, (int) cmd_code, cfstore_ex_opcode_str[cmd_code], handle); */ + switch(cmd_code) + { + case CFSTORE_OPCODE_INITIALIZE: + ctx->state = CFSTORE_EX_STATE_INIT_DONE; + break; + case CFSTORE_OPCODE_CREATE: + ctx->state = CFSTORE_EX_STATE_CREATE_DONE; + break; + case CFSTORE_OPCODE_WRITE: + ctx->state = CFSTORE_EX_STATE_WRITE_DONE; + break; + case CFSTORE_OPCODE_CLOSE: + switch(ctx->state) + { + case(CFSTORE_EX_STATE_CLOSING1): + ctx->state = CFSTORE_EX_STATE_CLOSE_DONE1; + break; + case(CFSTORE_EX_STATE_CLOSING2): + ctx->state = CFSTORE_EX_STATE_CLOSE_DONE2; + break; + default: + CFSTORE_EX1_TEST_ASSERT_MSG(false, "%s:Error: unknown Close() error (line=%u)\r\n", __func__, __LINE__); + break; + } + break; + case CFSTORE_OPCODE_FLUSH: + switch(ctx->state) + { + case(CFSTORE_EX_STATE_FLUSHING1): + ctx->state = CFSTORE_EX_STATE_FLUSH_DONE1; + break; + case(CFSTORE_EX_STATE_FLUSHING2): + ctx->state = CFSTORE_EX_STATE_FLUSH_DONE2; + break; + default: + CFSTORE_EX1_TEST_ASSERT_MSG(false, "%s:Error: unknown Find() error (line=%u)\r\n", __func__, __LINE__); + break; + } + break; + case CFSTORE_OPCODE_OPEN: + ctx->state = CFSTORE_EX_STATE_OPEN_DONE; + break; + case CFSTORE_OPCODE_FIND: + switch(ctx->state) + { + case(CFSTORE_EX_STATE_FINDING1): + ctx->state = CFSTORE_EX_STATE_FIND_DONE1; + break; + case(CFSTORE_EX_STATE_FINDING2): + ctx->state = CFSTORE_EX_STATE_FIND_DONE2; + break; + default: + CFSTORE_EX1_TEST_ASSERT_MSG(false, "%s:Error: unknown Find() error (line=%u)\r\n", __func__, __LINE__); + break; + } + break; + case CFSTORE_OPCODE_GET_KEY_NAME: + ctx->state = CFSTORE_EX_STATE_GET_KEY_NAME_DONE; + break; + case CFSTORE_OPCODE_GET_VALUE_LEN: + ctx->state = CFSTORE_EX_STATE_GET_VALUE_LEN_DONE; + break; + case CFSTORE_OPCODE_READ: + switch(ctx->state) + { + case(CFSTORE_EX_STATE_READING1): + ctx->state = CFSTORE_EX_STATE_READ_DONE1; + break; + case(CFSTORE_EX_STATE_READING2): + ctx->state = CFSTORE_EX_STATE_READ_DONE2; + break; + default: + CFSTORE_EX1_TEST_ASSERT_MSG(false, "%s:Error: unknown Read() error (line=%u)\r\n", __func__, __LINE__); + break; + } + break; + case CFSTORE_OPCODE_RSEEK: + ctx->state = CFSTORE_EX_STATE_RSEEK_DONE; + break; + case CFSTORE_OPCODE_DELETE: + ctx->state = CFSTORE_EX_STATE_DELETE_DONE; + break; + case CFSTORE_OPCODE_UNINITIALIZE: + ctx->state = CFSTORE_EX_STATE_UNINIT_DONE; + break; + case CFSTORE_OPCODE_GET_STATUS: + case CFSTORE_OPCODE_POWER_CONTROL: + default: + CFSTORE_EX1_TEST_ASSERT_MSG(false, "%s:Error: received asynchronous notification for opcode=%d (%s)\r\b", __func__, cmd_code, cmd_code < CFSTORE_OPCODE_MAX ? cfstore_ex_opcode_str[cmd_code] : "unknown"); + break; + } + ctx->callback_status = status; + ctx->callback_handle = handle; + cfstore_ex_fms_update(ctx); + return; +} + +static void cfstore_ex_fms_update(cfstore_example1_ctx_t* ctx) +{ + int32_t ret; + + switch (ctx->state) + { + case CFSTORE_EX_STATE_INITIALIZING: + CFSTORE_EX1_LOG("INITIALIZING%s", "\r\n"); + // note that cfstore_ex_callback() for cmd_code==CFSTORE_OPCODE_INITIALIZE can be invoked before Initialize() has returned + ret = cfstore_drv->Initialize(cfstore_ex_callback, ctx); + CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Initialize() should return ret >= 0 for async/synch modes(ret=%ld)\r\n", __func__, ret); + if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == false) { + ctx->state = CFSTORE_EX_STATE_INIT_DONE; + break; + } else if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == true) { + // await pending notification of completion. + break; + } + CFSTORE_EX1_TEST_ASSERT_MSG(false, "%s:Error: unknown error (line=%u)\r\n", __func__, __LINE__); + break; + + case CFSTORE_EX_STATE_INIT_DONE: + CFSTORE_EX1_LOG("INIT_DONE%s", "\r\n"); + CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_status >= ARM_DRIVER_OK, "%s:Error: Initialize() completion failed (status=%ld)\r\n", __func__, ctx->callback_status); + CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_handle == NULL, "%s:Error: the cfstore_ex_callback(cmd_code==CFSTORE_OPCODE_INITIALIZE) received non-NULL handle (%p)\r\n", __func__, ctx->callback_handle); + ctx->state = CFSTORE_EX_STATE_CREATING; + // intentional fall-through + + case CFSTORE_EX_STATE_CREATING: + CFSTORE_EX1_LOG("CREATING%s", "\r\n"); + memset(&ctx->kdesc, 0, sizeof(ARM_CFSTORE_KEYDESC)); + ctx->kdesc.drl = ARM_RETENTION_NVM; + ctx->len = strlen(cfstore_ex_kv_value); + // note that cfstore_ex_callback() for cmd_code==CFSTORE_OPCODE_CREATE can be invoked before Create() has returned + ret = cfstore_drv->Create(cfstore_ex_kv_name, ctx->len, &ctx->kdesc, ctx->hkey); + CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Create() failed (ret=%ld)\r\n", __func__, ret); + if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == false) { + ctx->state = CFSTORE_EX_STATE_CREATE_DONE; + break; + } else if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == true) { + // await pending notification of completion. + break; + } + CFSTORE_EX1_TEST_ASSERT_MSG(false, "%s:Error: unknown error (line=%u)\r\n", __func__, __LINE__); + break; + + case CFSTORE_EX_STATE_CREATE_DONE: + CFSTORE_EX1_LOG("CREATE_DONE%s", "\r\n"); + CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_status >= ARM_DRIVER_OK, "%s:Error: Create() completion failed (status=%ld)\r\n", __func__, ctx->callback_status); + CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_handle == ctx->hkey, "%s:Error: the cfstore_ex_callback(cmd_code==CFSTORE_OPCODE_CREATE) received handle (%p) is not the hkey supplied to Create()(%p)\r\n", __func__, ctx->callback_handle, ctx->hkey); + ctx->state = CFSTORE_EX_STATE_WRITING; + // intentional fall-through + + case CFSTORE_EX_STATE_WRITING: + CFSTORE_EX1_LOG("WRITING%s", "\r\n"); + ctx->len = strlen(cfstore_ex_kv_value); + // note that cfstore_ex_callback() for cmd_code==CFSTORE_OPCODE_WRITE can be invoked before Write() has returned + ret = cfstore_drv->Write(ctx->hkey, cfstore_ex_kv_value, &ctx->len); + CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Write() failed (ret=%ld)\r\n", __func__, ret); + if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == false) { + ctx->state = CFSTORE_EX_STATE_WRITE_DONE; + break; + } else if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == true) { + // await pending notification of completion. + break; + } + CFSTORE_EX1_TEST_ASSERT_MSG(false, "%s:Error: unknown error (line=%u)\r\n", __func__, __LINE__); + break; + + case CFSTORE_EX_STATE_WRITE_DONE: + CFSTORE_EX1_LOG("WRITE_DONE%s", "\r\n"); + CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_status >= ARM_DRIVER_OK, "%s:Error: Write() completion failed (status=%ld)\r\n", __func__, ctx->callback_status); + CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_status == (int32_t) strlen(cfstore_ex_kv_value), "%s:Error: Write() number of octets written (i.e. completion status (%ld)) != strlen(ctx->value)(%ld)\r\n", __func__, ctx->callback_status, (int32_t) strlen(cfstore_ex_kv_value)); + CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_status == (int32_t) ctx->len, "%s:Error: Write() number of octets written (i.e. completion status (%ld)) != updated value of len parameter (%ld)\r\n", __func__, ctx->callback_status, (int32_t) ctx->len); + CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_handle == ctx->hkey, "%s:Error: the cfstore_ex_callback(cmd_code==CFSTORE_OPCODE_WRITE) received handle (%p) is not the hkey supplied to Write()(%p)\r\n", __func__, ctx->callback_handle, ctx->hkey); + ctx->state = CFSTORE_EX_STATE_CLOSING1; + // intentional fall-through + + case CFSTORE_EX_STATE_CLOSING1: + CFSTORE_EX1_LOG("CLOSING1%s", "\r\n"); + // note that cfstore_ex_callback() for cmd_code==CFSTORE_OPCODE_CLOSE can be invoked before Close() has returned + ret = cfstore_drv->Close(ctx->hkey); + CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Close() failed (ret=%ld)\r\n", __func__, ret); + if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == false) { + ctx->state = CFSTORE_EX_STATE_CLOSE_DONE1; + break; + } else if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == true) { + // await pending notification of completion. + break; + } + CFSTORE_EX1_TEST_ASSERT_MSG(false, "%s:Error: unknown error (line=%u)\r\n", __func__, __LINE__); + break; + + case CFSTORE_EX_STATE_CLOSE_DONE1: + CFSTORE_EX1_LOG("CLOSE_DONE1%s", "\r\n"); + CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_status >= ARM_DRIVER_OK, "%s:Error: Close() completion failed (status=%ld)\r\n", __func__, ctx->callback_status); + CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_handle == NULL, "%s:Error: the cfstore_ex_callback(cmd_code==CFSTORE_OPCODE_CLOSE) received non-NULL handle (%p)\r\n", __func__, ctx->callback_handle); + ctx->state = CFSTORE_EX_STATE_FLUSHING1; + // intentional fall-through + + case CFSTORE_EX_STATE_FLUSHING1: + CFSTORE_EX1_LOG("FLUSHING1%s", "\r\n"); + // note that cfstore_ex_callback() for cmd_code==CFSTORE_OPCODE_FLUSH can be invoked before Flush() has returned + ret = cfstore_drv->Flush(); + CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Flush() failed (ret=%ld)\r\n", __func__, ret); + if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == false) { + ctx->state = CFSTORE_EX_STATE_FLUSH_DONE1; + break; + } else if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == true) { + // await pending notification of completion. + break; + } + CFSTORE_EX1_TEST_ASSERT_MSG(false, "%s:Error: unknown error (line=%u)\r\n", __func__, __LINE__); + break; + + case CFSTORE_EX_STATE_FLUSH_DONE1: + CFSTORE_EX1_LOG("FLUSH_DONE1%s", "\r\n"); + CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_status >= ARM_DRIVER_OK, "%s:Error: Flush() completion failed (status=%ld)\r\n", __func__, ctx->callback_status); + CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_handle == NULL, "%s:Error: the cfstore_ex_callback(cmd_code==CFSTORE_OPCODE_FLUSH) received non-NULL handle (%p)\r\n", __func__, ctx->callback_handle); + ctx->state = CFSTORE_EX_STATE_OPENING; + // intentional fall-through + + case CFSTORE_EX_STATE_OPENING: + CFSTORE_EX1_LOG("OPENING%s", "\r\n"); + memset(&ctx->flags, 0, sizeof(ctx->flags)); + memset(&ctx->hkey, 0, CFSTORE_HANDLE_BUFSIZE); + // note that cfstore_ex_callback() for cmd_code==CFSTORE_OPCODE_OPEN can be invoked before Open() has returned + ret = cfstore_drv->Open(cfstore_ex_kv_name, ctx->flags, ctx->hkey); + CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Open() failed (ret=%ld)\r\n", __func__, ret); + if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == false) { + ctx->state = CFSTORE_EX_STATE_OPEN_DONE; + break; + } else if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == true) { + // await pending notification of completion. + break; + } + CFSTORE_EX1_TEST_ASSERT_MSG(false, "%s:Error: unknown error (line=%u)\r\n", __func__, __LINE__); + break; + + case CFSTORE_EX_STATE_OPEN_DONE: + CFSTORE_EX1_LOG("OPEN_DONE%s", "\r\n"); + CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_status >= ARM_DRIVER_OK, "%s:Error: Open() completion failed (status=%ld)\r\n", __func__, ctx->callback_status); + CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_handle == ctx->hkey, "%s:Error: the cfstore_ex_callback(cmd_code==CFSTORE_OPCODE_OPEN) received handle (%p) is not the hkey supplied to Open()(%p)\r\n", __func__, ctx->callback_handle, ctx->hkey); + ctx->state = CFSTORE_EX_STATE_READING1; + // intentional fall-through + + case CFSTORE_EX_STATE_READING1: + CFSTORE_EX1_LOG("READING1%s", "\r\n"); + ctx->len = CFSTORE_KEY_NAME_MAX_LENGTH; + memset(ctx->value, 0, CFSTORE_KEY_NAME_MAX_LENGTH+1); + // note that cfstore_ex_callback() for cmd_code==CFSTORE_OPCODE_READ can be invoked before Read() has returned + ret = cfstore_drv->Read(ctx->hkey, ctx->value, &ctx->len); + CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Read() failed (ret=%ld)\r\n", __func__, ret); + if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == false) { + ctx->state = CFSTORE_EX_STATE_READ_DONE1; + break; + } else if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == true) { + // await pending notification of completion. + break; + } + CFSTORE_EX1_TEST_ASSERT_MSG(false, "%s:Error: unknown error (line=%u)\r\n", __func__, __LINE__); + break; + + case CFSTORE_EX_STATE_READ_DONE1: + CFSTORE_EX1_LOG("READ_DONE1%s", "\r\n"); + CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_status >= ARM_DRIVER_OK, "%s:Error: Read() completion failed (status=%ld)\r\n", __func__, ctx->callback_status); + CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_status == (int32_t) strlen(cfstore_ex_kv_value), "%s:Error: Read() number of octets read (i.e. completion status (%ld)) != strlen(ctx->value)(%ld)\r\n", __func__, ctx->callback_status, (int32_t) strlen(cfstore_ex_kv_value)); + CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_status == (int32_t) ctx->len, "%s:Error: Read() number of octets read (i.e. completion status (%ld)) != updated value of len parameter (%ld)\r\n", __func__, ctx->callback_status, (int32_t) ctx->len); + CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_handle == ctx->hkey, "%s:Error: the cfstore_ex_callback(cmd_code==CFSTORE_OPCODE_READ) received handle (%p) is not the hkey supplied to Read()(%p)\r\n", __func__, ctx->callback_handle, ctx->hkey); + CFSTORE_EX1_TEST_ASSERT_MSG(strncmp(ctx->value, cfstore_ex_kv_value, strlen(cfstore_ex_kv_value)) == 0, "%s:Error: the read value (%s) is not as expected (%s)\r\n", __func__, ctx->value, cfstore_ex_kv_value); + ctx->state = CFSTORE_EX_STATE_RSEEKING; + // intentional fall-through + + case CFSTORE_EX_STATE_RSEEKING: + CFSTORE_EX1_LOG("RSEEKING%s", "\r\n"); + // note that cfstore_ex_callback() for cmd_code==CFSTORE_OPCODE_READ can be invoked before Read() has returned + ret = cfstore_drv->Rseek(ctx->hkey, CFSTORE_EX1_RSEEK_OFFSET); + CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Rseek() failed (ret=%ld)\r\n", __func__, ret); + if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == false) { + ctx->state = CFSTORE_EX_STATE_RSEEK_DONE; + break; + } else if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == true) { + // await pending notification of completion. + break; + } + CFSTORE_EX1_TEST_ASSERT_MSG(false, "%s:Error: unknown error (line=%u)\r\n", __func__, __LINE__); + break; + + case CFSTORE_EX_STATE_RSEEK_DONE: + CFSTORE_EX1_LOG("RSEEK_DONE%s", "\r\n"); + CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_status >= ARM_DRIVER_OK, "%s:Error: Read() completion failed (status=%ld)\r\n", __func__, ctx->callback_status); + CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_handle == ctx->hkey, "%s:Error: the cfstore_ex_callback(cmd_code==CFSTORE_OPCODE_RSEEK) received handle (%p) is not the hkey supplied to Read()(%p)\r\n", __func__, ctx->callback_handle, ctx->hkey); + ctx->state = CFSTORE_EX_STATE_READING2; + // intentional fall-through + + case CFSTORE_EX_STATE_READING2: + CFSTORE_EX1_LOG("READING2%s", "\r\n"); + ctx->len = CFSTORE_KEY_NAME_MAX_LENGTH; + memset(ctx->value, 0, CFSTORE_KEY_NAME_MAX_LENGTH+1); + // note that cfstore_ex_callback() for cmd_code==CFSTORE_OPCODE_READ can be invoked before Read() has returned + ret = cfstore_drv->Read(ctx->hkey, ctx->value, &ctx->len); + CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Read() failed (ret=%ld)\r\n", __func__, ret); + if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == false) { + ctx->state = CFSTORE_EX_STATE_READ_DONE2; + break; + } else if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == true) { + // await pending notification of completion. + break; + } + CFSTORE_EX1_TEST_ASSERT_MSG(false, "%s:Error: unknown error (line=%u)\r\n", __func__, __LINE__); + break; + + case CFSTORE_EX_STATE_READ_DONE2: + CFSTORE_EX1_LOG("READ_DONE2%s", "\r\n"); + CFSTORE_EX1_LOG("%s: value=%s\r\n", __func__, ctx->value); + CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_status >= ARM_DRIVER_OK, "%s:Error: Read() completion failed (status=%ld)\r\n", __func__, ctx->callback_status); + CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_status == (int32_t) strlen(&cfstore_ex_kv_value[CFSTORE_EX1_RSEEK_OFFSET]), "%s:Error: Read() number of octets read (i.e. completion status (%ld)) != strlen(ctx->value)(%ld)\r\n", __func__, ctx->callback_status, (int32_t) strlen(&cfstore_ex_kv_value[CFSTORE_EX1_RSEEK_OFFSET])); + CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_status == (int32_t) ctx->len, "%s:Error: Read() number of octets read (i.e. completion status (%ld)) != updated value of len parameter (%ld)\r\n", __func__, ctx->callback_status, (int32_t) ctx->len); + CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_handle == ctx->hkey, "%s:Error: the cfstore_ex_callback(cmd_code==CFSTORE_OPCODE_READ) received handle (%p) is not the hkey supplied to Read()(%p)\r\n", __func__, ctx->callback_handle, ctx->hkey); + CFSTORE_EX1_TEST_ASSERT_MSG(strncmp(ctx->value, &cfstore_ex_kv_value[CFSTORE_EX1_RSEEK_OFFSET], strlen(&cfstore_ex_kv_value[CFSTORE_EX1_RSEEK_OFFSET])) == 0, "%s:Error: the read value (%s) is not as expected (%s)\r\n", __func__, ctx->value, &cfstore_ex_kv_value[CFSTORE_EX1_RSEEK_OFFSET]); + ctx->state = CFSTORE_EX_STATE_CLOSING2; + // intentional fall-through + + case CFSTORE_EX_STATE_CLOSING2: + CFSTORE_EX1_LOG("CLOSING2%s", "\r\n"); + // note that cfstore_ex_callback() for cmd_code==CFSTORE_OPCODE_CLOSE can be invoked before Close() has returned + ret = cfstore_drv->Close(ctx->hkey); + CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Close() failed (ret=%ld)\r\n", __func__, ret); + if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == false) { + ctx->state = CFSTORE_EX_STATE_CLOSE_DONE2; + break; + } else if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == true) { + // await pending notification of completion. + break; + } + CFSTORE_EX1_TEST_ASSERT_MSG(false, "%s:Error: unknown error (line=%u)\r\n", __func__, __LINE__); + break; + + case CFSTORE_EX_STATE_CLOSE_DONE2: + CFSTORE_EX1_LOG("CLOSE_DONE2%s", "\r\n"); + CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_status >= ARM_DRIVER_OK, "%s:Error: Close() completion failed (status=%ld)\r\n", __func__, ctx->callback_status); + CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_handle == NULL, "%s:Error: the cfstore_ex_callback(cmd_code==CFSTORE_OPCODE_CLOSE) received non-NULL handle (%p)\r\n", __func__, ctx->callback_handle); + ctx->state = CFSTORE_EX_STATE_FINDING1; + // intentional fall-through + + case CFSTORE_EX_STATE_FINDING1: + CFSTORE_EX1_LOG("FINDING1%s", "\r\n"); + // note that cfstore_ex_callback() for cmd_code==CFSTORE_OPCODE_FIND can be invoked before Find() has returned + ret = cfstore_drv->Find("*", ctx->hkey_next, ctx->hkey_prev); + CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Find() failed (ret=%ld)\r\n", __func__, ret); + if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == false) { + ctx->state = CFSTORE_EX_STATE_FIND_DONE1; + break; + } else if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == true) { + // await pending notification of completion. + break; + } + CFSTORE_EX1_TEST_ASSERT_MSG(false, "%s:Error: unknown error (line=%u)\r\n", __func__, __LINE__); + break; + + case CFSTORE_EX_STATE_FIND_DONE1: + CFSTORE_EX1_LOG("FIND_DONE1%s", "\r\n"); + CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_status == ARM_DRIVER_OK, "%s:Error: Find() completion failed (status=%ld)\r\n", __func__, ctx->callback_status); + CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_handle == ctx->hkey_prev, "%s:Error: the cfstore_ex_callback(cmd_code==CFSTORE_OPCODE_FIND) received handle (%p) is not the hkey supplied to Find()(%p)\r\n", __func__, ctx->callback_handle, ctx->hkey_prev); + ctx->state = CFSTORE_EX_STATE_GETTING_KEY_NAME; + // intentional fall-through + + case CFSTORE_EX_STATE_GETTING_KEY_NAME: + CFSTORE_EX1_LOG("GETTING_KEY_NAME%s", "\r\n"); + ctx->len = CFSTORE_KEY_NAME_MAX_LENGTH; + memset(ctx->value, 0, CFSTORE_KEY_NAME_MAX_LENGTH+1); + // note that cfstore_ex_callback() for cmd_code==CFSTORE_OPCODE_GET_KEY_NAME can be invoked before GetKeyName() has returned + ret = cfstore_drv->GetKeyName(ctx->hkey_prev, ctx->value, (uint8_t*) &ctx->len); + CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: GetKeyName() failed (ret=%ld)\r\n", __func__, ret); + if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == false) { + ctx->state = CFSTORE_EX_STATE_GET_KEY_NAME_DONE; + break; + } else if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == true) { + // await pending notification of completion. + break; + } + CFSTORE_EX1_TEST_ASSERT_MSG(false, "%s:Error: unknown error (line=%u)\r\n", __func__, __LINE__); + break; + + case CFSTORE_EX_STATE_GET_KEY_NAME_DONE: + CFSTORE_EX1_LOG("GET_KEY_NAME_DONE%s", "\r\n"); + CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_status >= ARM_DRIVER_OK, "%s:Error: GetKeyName() completion failed (status=%ld)\r\n", __func__, ctx->callback_status); + CFSTORE_EX1_TEST_ASSERT_MSG( ((int32_t) ctx->len == ((int32_t) strlen(cfstore_ex_kv_name)+1)), "%s:Error: GetKeyName() updated value of len parameter (%ld) != strlen(cfstore_ex_kv_name) (%ld) (\r\n", __func__, (int32_t) ctx->len, (int32_t) strlen(cfstore_ex_kv_name)); + CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_handle == ctx->hkey_prev, "%s:Error: the cfstore_ex_callback(cmd_code==CFSTORE_OPCODE_GET_KEY_NAME) received handle (%p) is not the hkey supplied to GetKeyName()(%p)\r\n", __func__, ctx->callback_handle, ctx->hkey_prev); + CFSTORE_EX1_TEST_ASSERT_MSG(strncmp(ctx->value, cfstore_ex_kv_name, strlen(cfstore_ex_kv_name)) == 0, "%s:Error: the key name (%s) is not as expected (%s)\r\n", __func__, ctx->value, cfstore_ex_kv_name); + ctx->state = CFSTORE_EX_STATE_GETTING_VALUE_LEN; + // intentional fall-through + + case CFSTORE_EX_STATE_GETTING_VALUE_LEN: + CFSTORE_EX1_LOG("GETTING_VALUE_LEN%s", "\r\n"); + ctx->len = CFSTORE_KEY_NAME_MAX_LENGTH; + // note that cfstore_ex_callback() for cmd_code==CFSTORE_OPCODE_GET_VALUE_LEN can be invoked before GetValueLen() has returned + ret = cfstore_drv->GetValueLen(ctx->hkey_prev, &ctx->len); + CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: GetValueLen() failed (ret=%ld)\r\n", __func__, ret); + if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == false) { + ctx->state = CFSTORE_EX_STATE_GET_VALUE_LEN_DONE; + break; + } else if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == true) { + // await pending notification of completion. + break; + } + CFSTORE_EX1_TEST_ASSERT_MSG(false, "%s:Error: unknown error (line=%u)\r\n", __func__, __LINE__); + break; + + case CFSTORE_EX_STATE_GET_VALUE_LEN_DONE: + CFSTORE_EX1_LOG("GET_VALUE_LEN_DONE%s", "\r\n"); + CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_status >= ARM_DRIVER_OK, "%s:Error: GetValueLen() completion failed (status=%ld)\r\n", __func__, ctx->callback_status); + CFSTORE_EX1_TEST_ASSERT_MSG((int32_t) ctx->len == (int32_t) strlen(cfstore_ex_kv_value), "%s:Error: GetValueLen() updated value of len parameter (%ld) != strlen(cfstore_ex_kv_value)(%ld) \r\n", __func__, (int32_t) ctx->len, (int32_t) strlen(cfstore_ex_kv_value)); + CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_handle == ctx->hkey_prev, "%s:Error: the cfstore_ex_callback(cmd_code==CFSTORE_OPCODE_GET_VALUE_LEN) received handle (%p) is not the hkey supplied to GetValueLen()(%p)\r\n", __func__, ctx->callback_handle, ctx->hkey_prev); + ctx->state = CFSTORE_EX_STATE_DELETING; + // intentional fall-through + + case CFSTORE_EX_STATE_DELETING: + CFSTORE_EX1_LOG("DELETING%s", "\r\n"); + // note that cfstore_ex_callback() for cmd_code==CFSTORE_OPCODE_DELETE can be invoked before Delete() has returned + ret = cfstore_drv->Delete(ctx->callback_handle); + CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Close() failed (ret=%ld)\r\n", __func__, ret); + if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == false) { + ctx->state = CFSTORE_EX_STATE_DELETE_DONE; + break; + } else if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == true) { + // await pending notification of completion. + break; + } + CFSTORE_EX1_TEST_ASSERT_MSG(false, "%s:Error: unknown error (line=%u)\r\n", __func__, __LINE__); + break; + + case CFSTORE_EX_STATE_DELETE_DONE: + CFSTORE_EX1_LOG("DELETE_DONE%s", "\r\n"); + CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_status >= ARM_DRIVER_OK, "%s:Error: Delete() completion failed (status=%ld)\r\n", __func__, ctx->callback_status); + CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_handle == NULL, "%s:Error: the cfstore_ex_callback(cmd_code==CFSTORE_OPCODE_DELETE) received non-NULL handle (%p)\r\n", __func__, ctx->callback_handle); + CFSTORE_HANDLE_SWAP(ctx->hkey_prev, ctx->hkey_next); + ctx->state = CFSTORE_EX_STATE_FINDING2; + // intentional fall-through + + case CFSTORE_EX_STATE_FINDING2: + CFSTORE_EX1_LOG("FINDING2%s", "\r\n"); + // note that cfstore_ex_callback() for cmd_code==CFSTORE_OPCODE_FIND can be invoked before Find() has returned + ret = cfstore_drv->Find("*", ctx->hkey_next, ctx->hkey_prev); + CFSTORE_EX1_TEST_ASSERT_MSG(ret == ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND, "%s:Error: Find() failed to return expected value of ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND (ret=%ld)\r\n", __func__, ret); + if(ret == ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND && ctx->caps.asynchronous_ops == false) { + ctx->state = CFSTORE_EX_STATE_FIND_DONE2; + break; + } else if(ret == ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND && ctx->caps.asynchronous_ops == true) { + // await pending notification of completion. + break; + } + CFSTORE_EX1_TEST_ASSERT_MSG(false, "%s:Error: unknown error (line=%u)\r\n", __func__, __LINE__); + break; + + case CFSTORE_EX_STATE_FIND_DONE2: + CFSTORE_EX1_LOG("FIND_DONE2%s", "\r\n"); + CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_status == ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND, "%s:Error: Find() completion should have been ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND (status=%ld)\r\n", __func__, ctx->callback_status); + ctx->state = CFSTORE_EX_STATE_FLUSHING2; + // intentional fall-through + + case CFSTORE_EX_STATE_FLUSHING2: + CFSTORE_EX1_LOG("FLUSHING2%s", "\r\n"); + // note that cfstore_ex_callback() for cmd_code==CFSTORE_OPCODE_FLUSH can be invoked before Flush() has returned + ret = cfstore_drv->Flush(); + CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error:2: Flush() failed (ret=%ld)\r\n", __func__, ret); + if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == false) { + ctx->state = CFSTORE_EX_STATE_FLUSH_DONE2; + break; + } else if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == true) { + // await pending notification of completion. + break; + } + CFSTORE_EX1_TEST_ASSERT_MSG(false, "%s:Error: unknown error (line=%u)\r\n", __func__, __LINE__); + break; + + case CFSTORE_EX_STATE_FLUSH_DONE2: + CFSTORE_EX1_LOG("FLUSH_DONE2%s", "\r\n"); + CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_status >= ARM_DRIVER_OK, "%s:Error: Flush() completion failed (status=%ld)\r\n", __func__, ctx->callback_status); + CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_handle == NULL, "%s:Error: the cfstore_ex_callback(cmd_code==CFSTORE_OPCODE_FLUSH) received non-NULL handle (%p)\r\n", __func__, ctx->callback_handle); + ctx->state = CFSTORE_EX_STATE_UNINITIALIZING; + // intentional fall-through + + case CFSTORE_EX_STATE_UNINITIALIZING: + CFSTORE_EX1_LOG("UNINITIALIZING%s", "\r\n"); + ret = cfstore_drv->Uninitialize(); + CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Uninitialize() should return ret >= 0 for async/synch modes(ret=%ld)\r\n", __func__, ret); + if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == false) { + ctx->state = CFSTORE_EX_STATE_UNINIT_DONE; + break; + } else if(ret >= ARM_DRIVER_OK && ctx->caps.asynchronous_ops == true) { + // await pending notification of completion. + break; + } + CFSTORE_EX1_TEST_ASSERT_MSG(false, "%s:Error: unknown error (line=%u)\r\n", __func__, __LINE__); + break; + + case CFSTORE_EX_STATE_UNINIT_DONE: + CFSTORE_EX1_LOG("UNINIT_DONE%s", "\r\n"); + CFSTORE_EX1_TEST_ASSERT_MSG(ctx->callback_handle == NULL, "%s:Error: the cfstore_ex_callback(cmd_code==CFSTORE_OPCODE_UNINITIALIZE) received non-NULL handle (%p)\r\n", __func__, ctx->callback_handle); + cfstore_example1_done = true; + CFSTORE_EX1_LOG("***************%s", "\r\n"); + CFSTORE_EX1_LOG("*** SUCCESS ***%s", "\r\n"); + CFSTORE_EX1_LOG("***************%s", "\r\n"); + break; + } +} + +static control_t cfstore_example1_app_start(const size_t call_count) +{ + cfstore_example1_ctx_t* ctx = &cfstore_example1_ctx_g; + + (void) call_count; + + /* initialise the context */ + memset(ctx, 0, sizeof(cfstore_example1_ctx_t)); + cfstore_example1_done = false; + ctx->hkey_next = ctx->hkey_next_buf; + ctx->hkey_prev = ctx->hkey_prev_buf; + ctx->callback_status = ARM_DRIVER_ERROR; + ctx->state = CFSTORE_EX_STATE_INITIALIZING; + ctx->caps = cfstore_drv->GetCapabilities(); + CFSTORE_EX1_LOG("%s:INITIALIZING: caps.asynchronous_ops=%lu\n", __func__, ctx->caps.asynchronous_ops); + cfstore_ex_fms_update(ctx); + + /* main application worker loop */ + while (!cfstore_example1_done) + { + // do some work + CFSTORE_EX1_LOG("%s: going to sleep!\r\n", __func__); + +#if defined CFSTORE_CONFIG_MBED_OS_VERSION && CFSTORE_CONFIG_MBED_OS_VERSION == 3 + __WFE(); +#endif /* CFSTORE_CONFIG_MBED_OS_VERSION == 3 */ + +#if defined CFSTORE_CONFIG_MBED_OS_VERSION && CFSTORE_CONFIG_MBED_OS_VERSION == 4 + /* mbedosV3++ + * todo: port __WFE() + */ +#endif /* CFSTORE_CONFIG_MBED_OS_VERSION == 4 */ + CFSTORE_EX1_LOG("%s: woke up!\r\n", __func__); + } + return CaseNext; +} + +#ifndef YOTTA_CONFIGURATION_STORE_EXAMPLE1_VERSION_STRING +/* when built as Configuration-Store example, include greentea support otherwise omit */ + +/* report whether built/configured for flash sync or async mode */ +static control_t cfstore_example1_test_00(const size_t call_count) +{ + (void) call_count; + CFSTORE_EX1_LOG("INITIALIZING: caps.asynchronous_ops=%lu\n", cfstore_driver.GetCapabilities().asynchronous_ops); + return CaseNext; +} + +utest::v1::status_t greentea_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(100, "default_auto"); + return greentea_test_setup_handler(number_of_cases); +} + +Case cases[] = { + /* 1 2 3 4 5 6 7 */ + /* 1234567890123456789012345678901234567890123456789012345678901234567890 */ + Case("EXAMPLE1_test_00", cfstore_example1_test_00), + Case("EXAMPLE1_test_01_start", cfstore_example1_app_start), +}; + + +/* Declare your test specification with a custom setup handler */ +Specification specification(greentea_setup, cases); + +#if defined CFSTORE_CONFIG_MBED_OS_VERSION && CFSTORE_CONFIG_MBED_OS_VERSION == 3 +/* mbedosV3*/ +void app_start(int argc __unused, char** argv __unused) +{ + /* Run the test specification */ + Harness::run(specification); +} +#endif /* CFSTORE_CONFIG_MBED_OS_VERSION == 3 */ + +#if defined CFSTORE_CONFIG_MBED_OS_VERSION && CFSTORE_CONFIG_MBED_OS_VERSION == 4 +/* mbedosV3++*/ +int main() +{ + return !Harness::run(specification); +} +#endif /* CFSTORE_CONFIG_MBED_OS_VERSION == 4 */ + + +#else // YOTTA_CONFIGURATION_STORE_EXAMPLE1_VERSION_STRING + +// stand alone Configuration-Store-Example +void app_start(int argc __unused, char** argv __unused) +{ + cfstore_example1_app_start(0); +} + + + +#endif // YOTTA_CONFIGURATION_STORE_EXAMPLE1_VERSION_STRING + + +#endif // __MBED__ && ! defined TOOLCHAIN_GCC_ARM diff --git a/TESTS/cfstore/example2/example2.cpp b/TESTS/cfstore/example2/example2.cpp new file mode 100644 index 0000000000..18523686f9 --- /dev/null +++ b/TESTS/cfstore/example2/example2.cpp @@ -0,0 +1,328 @@ +/** @file example2.cpp + * + * mbed Microcontroller Library + * Copyright (c) 2006-2016 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + + +/* Overview of test: + * - initialises cfstore + * - creates a key called "com.arm.mbed.spv.assets.asset2.payload" with value blob length = 15 = strlen("Grumpy old man")+1. + * - writes the data for the key to be "Grumpy old man" + * - closes kv. + * - opens kv for reading/writing + * - reads the value blob and checks its == "Grumpy old man" + * - writes the first 11 chars of the value blob to be "Grumpy man" plus a NULL; + * - reads the value blob back and checks its as expected + * + * This test is coded so as to work in the following modes: + * - flash sync mode i.e. with caps.asynchronous_ops == false + * - flash async mode i.e. with caps.asynchronous_ops == true + */ +#if defined __MBED__ && ! defined TOOLCHAIN_GCC_ARM + + +#include +#include +#include +#include + +#ifdef TARGET_LIKE_FRDM_K64F_GCC +#include +#endif + +#include "cfstore_config.h" +#include +#include "cfstore_debug.h" +#include "cfstore_test.h" +#include +#include "utest/utest.h" +#include "unity/unity.h" +#include "greentea-client/test_env.h" +#ifdef YOTTA_CFG_CFSTORE_UVISOR +#include "uvisor-lib/uvisor-lib.h" +#include "cfstore_uvisor.h" +#endif /* YOTTA_CFG_CFSTORE_UVISOR */ + +using namespace utest::v1; + +static control_t cfstore_example2_test_00(const size_t call_count) +{ + (void) call_count; + printf("Not implemented for ARM toolchain\n"); + return CaseNext; +} + + +utest::v1::status_t greentea_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(100, "default_auto"); + return greentea_test_setup_handler(number_of_cases); +} + +Case cases[] = { + /* 1 2 3 4 5 6 7 */ + /* 1234567890123456789012345678901234567890123456789012345678901234567890 */ + Case("EXAMPLE2_test_00", cfstore_example2_test_00), +}; + + +/* Declare your test specification with a custom setup handler */ +Specification specification(greentea_setup, cases); + +int main() +{ + return !Harness::run(specification); +} + + + +#else + + +#include +#include +#include +#include +#include + +#ifdef TARGET_LIKE_FRDM_K64F_GCC +#include +#endif + +#include "cfstore_config.h" +#include "cfstore_test.h" +#include "cfstore_debug.h" +//#include +#include +#include +#include "utest/utest.h" +#include "unity/unity.h" +#include "greentea-client/test_env.h" +#ifdef YOTTA_CFG_CONFIG_UVISOR +#include "uvisor-lib/uvisor-lib.h" +#endif /* YOTTA_CFG_CONFIG_UVISOR */ + + +using namespace utest::v1; + +static char cfstore_example2_utest_msg_g[CFSTORE_UTEST_MSG_BUF_SIZE]; + +/* defines */ +#define PvMemSet memset +#define PvStrLen strlen + +/* report whether built/configured for flash sync or async mode */ +static control_t cfstore_example2_test_00(const size_t call_count) +{ + (void) call_count; + CFSTORE_LOG("INITIALIZING: caps.asynchronous_ops=%lu\n", cfstore_driver.GetCapabilities().asynchronous_ops); + return CaseNext; +} + +ARM_CFSTORE_DRIVER *drv = &cfstore_driver; +static int32_t CreateKeyValueStore( + const char *keyName, + const char *data, + ARM_CFSTORE_SIZE *dataLength, + ARM_CFSTORE_KEYDESC *keyDesc) +{ + int32_t cfsStatus = ARM_DRIVER_ERROR; + ARM_CFSTORE_SIZE valueLength = 0; + ARM_CFSTORE_HANDLE_INIT(hkey); + + valueLength = *dataLength; + cfsStatus = drv->Create(keyName, valueLength, keyDesc, hkey); + TEST_ASSERT_EQUAL(ARM_DRIVER_OK, cfsStatus); + + valueLength = *dataLength; + cfsStatus = drv->Write(hkey, data, &valueLength); + /* + * (1) Note the following: + * - if cfsStatus > 0 then Write() has completed synchronously and returned the number of bytes written (irrespective of the caps.asynchronous_ops attribute). + * - if cfsStatus == ARM_DRIVER_OK then: + * - if caps.asynchronous_ops == true then the operation will be completed with registered client callback passed to Initialize(). + * - if caps.asynchronous_ops == false then the operation has completed synchronously and no bytes were written. + * - if cfsStatus < ARM_DRIVER_OK then an error has occurred + */ + CFSTORE_TEST_UTEST_MESSAGE(cfstore_example2_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to write key (rc=%" PRId32 ")\n", __func__, cfsStatus); + TEST_ASSERT_MESSAGE(cfsStatus >= ARM_DRIVER_OK, cfstore_example2_utest_msg_g); + + CFSTORE_TEST_UTEST_MESSAGE(cfstore_example2_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%sError: valueLength(%" PRId32 ") does not match the expected dataLength(%" PRId32 ")\n", __func__, (int32_t) valueLength, (int32_t) *dataLength); + TEST_ASSERT_MESSAGE(*dataLength == valueLength, cfstore_example2_utest_msg_g); + + CFSTORE_TEST_UTEST_MESSAGE(cfstore_example2_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%sError: Write() return value cfsStatus(%" PRId32 ") does not match the expected dataLength(%" PRId32 ")\n", __func__, cfsStatus, (int32_t) *dataLength); + TEST_ASSERT_MESSAGE((int32_t) *dataLength == cfsStatus, cfstore_example2_utest_msg_g); + + drv->Close(hkey); + /* CreateKeyValueStore() returns what was returned from Write(). See (1) above for description. */ + return cfsStatus; +} + +static control_t cfstore_example2_test_01(const size_t call_count) +{ + int32_t cfsStatus; + ARM_CFSTORE_HANDLE_INIT(hkey); + ARM_CFSTORE_HANDLE_INIT(updatedKeyH); + ARM_CFSTORE_FMODE flags; + ARM_CFSTORE_KEYDESC kdesc; + ARM_CFSTORE_SIZE valueLen; + char* ptr = NULL; + + const char key[] = "com.arm.mbed.spv.assets.asset2.payload"; + const char value[] = "Grumpy old man"; + + (void) call_count; + + // It must not exceed the value_len field specified when the Key-Value pair was created + const char newDataToWrite[] = "Grumpy man"; + + char readBuf[CFSTORE_KEY_NAME_MAX_LENGTH + 1]; + ARM_CFSTORE_SIZE len = 0; + + // Write a key-value pair + + PvMemSet(&kdesc, 0, sizeof(kdesc)); + PvMemSet(&flags, 0, sizeof(flags)); + PvMemSet(readBuf, 0, CFSTORE_KEY_NAME_MAX_LENGTH + 1); + + kdesc.drl = ARM_RETENTION_WHILE_DEVICE_ACTIVE; + /* The length supplied to Write() is the number of octets to store in the blob. + * Specifying the following value for valueLen will store the terminating null to + * a string, for example. + */ + valueLen = PvStrLen(value) + 1; + + cfsStatus = drv->Initialize(NULL, NULL); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_example2_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Initialize() failed (cfsStatus=%" PRId32 ")\n", __func__, cfsStatus); + TEST_ASSERT_MESSAGE(cfsStatus >= ARM_DRIVER_OK, cfstore_example2_utest_msg_g); + + cfsStatus = CreateKeyValueStore(key, value, &valueLen, &kdesc); + + /* CreateKeyValueStore() returns the number of characters written, which can vary between 0 and the supplied arg valueLen + * - in the case that this example is compiled for flash mode sync, CreateKeyValueStore(), on success should always return valueLen + * - in the case that this example is compiled for flash mode async, CreateKeyValueStore() on success may return a value 0 to valueLen + * with async notification of the completed transaction. + */ + CFSTORE_TEST_UTEST_MESSAGE(cfstore_example2_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%sError: valueLen(%" PRId32 ") does not match the expected returned value from CreateKeyValueStore(%" PRId32 ")\n", __func__, (int32_t) valueLen, cfsStatus); + TEST_ASSERT_MESSAGE(cfsStatus == (int32_t) valueLen, cfstore_example2_utest_msg_g); + + // Read key-value pair with 'Write' permission + + flags.read = true; + flags.write = true; + cfsStatus = drv->Open(key, flags, hkey); + TEST_ASSERT_EQUAL(ARM_DRIVER_OK, cfsStatus); + + len = sizeof(readBuf); + cfsStatus = drv->Read(hkey, readBuf, &len); + /* Read() returns the number of characters read, which can vary between 0 and the size of the value blob, and the size of the supplied buffer */ + CFSTORE_TEST_UTEST_MESSAGE(cfstore_example2_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Read() returned value (%" PRId32 ") does not match the created length of the value blob(%" PRId32 ")\n", __func__, cfsStatus, (int32_t) PvStrLen(value) + 1); + TEST_ASSERT_MESSAGE(cfsStatus == (int32_t) (PvStrLen(value) + 1), cfstore_example2_utest_msg_g); + + CFSTORE_TEST_UTEST_MESSAGE(cfstore_example2_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Read() returned len value (%" PRId32 ") does not match the created length of the value blob(%" PRId32 ")\n", __func__, (int32_t) len, (int32_t) PvStrLen(value) + 1); + TEST_ASSERT_MESSAGE(len == PvStrLen(value) + 1, cfstore_example2_utest_msg_g); + + /* Note: + * - original data = "Grumpy old man", which is 14+1 chars inc NULL + * - New data = "Grumpy man" which is 10+1 chars inc NULL + * - when the key "com.arm.mbed.spv.assets.asset2.payload"; was created, it was created with a value blob size of 14+1=15 chars. + * - The new data is shorter that the old data so it will be accommodated in the value blob + * - The size of the value blob will stay the same. + */ + // Update the value and value length + /* note len set to sizeof(newDataToWrite) which includes the terminating null of the string */ + len = sizeof(newDataToWrite); + cfsStatus = drv->Write(hkey, newDataToWrite, &len); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_example2_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Write() returned cfsStatus value (%" PRId32 ") does not match the length of new data written(%" PRId32 ")\n", __func__, cfsStatus, (int32_t) sizeof(newDataToWrite)); + TEST_ASSERT_MESSAGE(cfsStatus == (int32_t) sizeof(newDataToWrite), cfstore_example2_utest_msg_g); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_example2_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Write() returned len (%" PRId32 ") does not match the length of new data written(%" PRId32 ")\n", __func__, (int32_t) len, (int32_t) sizeof(newDataToWrite)); + TEST_ASSERT_MESSAGE((int32_t) len == (int32_t) sizeof(newDataToWrite), cfstore_example2_utest_msg_g); + + drv->Close(hkey); + + // Check that the value was updated + flags.write = false; + cfsStatus = drv->Open(key, flags, updatedKeyH); + TEST_ASSERT_EQUAL(ARM_DRIVER_OK, cfsStatus); + + len = CFSTORE_KEY_NAME_MAX_LENGTH; + PvMemSet(readBuf, 0, len); + cfsStatus = drv->Read(updatedKeyH, readBuf, &len); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_example2_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Read() returned value (%" PRId32 ") does not match the created length of the value blob(%" PRId32 ")\n", __func__, cfsStatus, (int32_t) PvStrLen(value) + 1); + TEST_ASSERT_MESSAGE(cfsStatus == (int32_t) (PvStrLen(value) + 1), cfstore_example2_utest_msg_g); + + CFSTORE_TEST_UTEST_MESSAGE(cfstore_example2_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Read() returned len value (%" PRId32 ") does not match the created length of the value blob(%" PRId32 ")\n", __func__, (int32_t) len, (int32_t) PvStrLen(value) + 1); + TEST_ASSERT_MESSAGE(len == (PvStrLen(value) + 1), cfstore_example2_utest_msg_g); + + /* convert any terminating nulls to '=' */ + while( (ptr = (char*) memchr(readBuf, 0, (PvStrLen(value) + 1))) != NULL) + { + *ptr = '='; + } + /* check the data is as expected */ + CFSTORE_TEST_UTEST_MESSAGE(cfstore_example2_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Read() returned unexpected string (%s) where nulls have been converted to '=' chars\n", __func__, readBuf); + TEST_ASSERT_MESSAGE(strncmp(readBuf, "Grumpy man=man=", (PvStrLen(value) + 1)) == 0, cfstore_example2_utest_msg_g); + + CFSTORE_LOG("Success: New value of KV (%s) value blob (with nulls converted to '=') = (%s)\n", key, readBuf); + + drv->Close(updatedKeyH); + + cfsStatus = drv->Uninitialize(); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_example2_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Uninitialize() failed (cfsStatus=%" PRId32 ")\n", __func__, cfsStatus); + TEST_ASSERT_MESSAGE(cfsStatus >= ARM_DRIVER_OK, cfstore_example2_utest_msg_g); + + return CaseNext; +} + + + +utest::v1::status_t greentea_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(400, "default_auto"); + return greentea_test_setup_handler(number_of_cases); +} + +Case cases[] = { + /* 1 2 3 4 5 6 7 */ + /* 1234567890123456789012345678901234567890123456789012345678901234567890 */ + Case("EXAMPLE2_test_00", cfstore_example2_test_00), + Case("EXAMPLE2_test_01", cfstore_example2_test_01), +}; + + +/* Declare your test specification with a custom setup handler */ +Specification specification(greentea_setup, cases); + +#if defined CFSTORE_CONFIG_MBED_OS_VERSION && CFSTORE_CONFIG_MBED_OS_VERSION == 3 +/* mbedosV3*/ +void app_start(int argc __unused, char** argv __unused) +{ + /* Run the test specification */ + Harness::run(specification); +} +#endif /* CFSTORE_CONFIG_MBED_OS_VERSION == 3 */ + +#if defined CFSTORE_CONFIG_MBED_OS_VERSION && CFSTORE_CONFIG_MBED_OS_VERSION == 4 +/* mbedosV3++*/ +int main() +{ + return !Harness::run(specification); +} +#endif /* CFSTORE_CONFIG_MBED_OS_VERSION == 4 */ + + +#endif // __MBED__ && ! defined TOOLCHAIN_GCC_ARM diff --git a/TESTS/cfstore/example3/example3.cpp b/TESTS/cfstore/example3/example3.cpp new file mode 100644 index 0000000000..4b7d3dc195 --- /dev/null +++ b/TESTS/cfstore/example3/example3.cpp @@ -0,0 +1,393 @@ +/** @file example3.cpp + * + * mbed Microcontroller Library + * Copyright (c) 2006-2016 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Test cases to add and delete KVs in the CFSTORE. + */ + + +/* Notes + * ===== + * + * The flash-journal synchronous mode example test does the following CFSTORE operations: + * - initialises + * - creates a key-value pair (KV). + * - writes the data for the KV + * - closes KV. + * - flushes the KV to flash + * - opens KV for reading. + * - reads KV and checks the value blob was the same as previously written. + * - closes KV. + * - finds a KV (there is only 1 to find). + * - for the KV returned, get the key name. + * - for the KV returned, get the value length. + * - for the KV returned, delete the KV. + * - find another KV (which fails as there are no more keys to find). + * - flushes the updated state to flash to store the removal of the deleted KV. + * - uninitialises + * - stops + * + * This test is coded so as to work only in flash journal sync mode + * i.e. with caps.asynchronous_ops == false + * + * The test leaves the flash in the same state as at the beginning of the test so + * it can be run a second time on the device without flashing, and the test should + * still work. + */ +#if defined __MBED__ && ! defined TOOLCHAIN_GCC_ARM + + +#include +#include +#include +#include + +#ifdef TARGET_LIKE_FRDM_K64F_GCC +#include +#endif + +#include "cfstore_config.h" +#include +#include "cfstore_debug.h" +#include "cfstore_test.h" +#include +#include "utest/utest.h" +#include "unity/unity.h" +#include "greentea-client/test_env.h" +#ifdef YOTTA_CFG_CFSTORE_UVISOR +#include "uvisor-lib/uvisor-lib.h" +#include "cfstore_uvisor.h" +#endif /* YOTTA_CFG_CFSTORE_UVISOR */ + +using namespace utest::v1; + +static control_t cfstore_example3_test_00(const size_t call_count) +{ + (void) call_count; + printf("Not implemented for ARM toolchain\n"); + return CaseNext; +} + + +utest::v1::status_t greentea_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(100, "default_auto"); + return greentea_test_setup_handler(number_of_cases); +} + +Case cases[] = { + /* 1 2 3 4 5 6 7 */ + /* 1234567890123456789012345678901234567890123456789012345678901234567890 */ + Case("EXAMPLE3_test_00", cfstore_example3_test_00), +}; + + +/* Declare your test specification with a custom setup handler */ +Specification specification(greentea_setup, cases); + +int main() +{ + return !Harness::run(specification); +} + + + +#else + + +#include +#include +#include + +#ifdef TARGET_LIKE_FRDM_K64F_GCC +#include +#endif +#ifndef YOTTA_CONFIGURATION_STORE_EXAMPLE3_VERSION_STRING +/* when built as Configuration-Store example, include greentea support otherwise omit */ +#include "utest/utest.h" +#include "unity/unity.h" +#include "greentea-client/test_env.h" +#else // YOTTA_CONFIGURATION_STORE_EXAMPLE3_VERSION_STRING +// map utest types for building as stand alone example +#define control_t void +#define CaseNext +#endif // YOTTA_CONFIGURATION_STORE_EXAMPLE3_VERSION_STRING + +#include +#include +#include "cfstore_config.h" +#include +#ifdef YOTTA_CFG_CONFIG_UVISOR +#include "uvisor-lib/uvisor-lib.h" +#endif /* YOTTA_CFG_CONFIG_UVISOR */ + + +#ifndef YOTTA_CONFIGURATION_STORE_EXAMPLE3_VERSION_STRING +using namespace utest::v1; +#endif + + +#define CFSTORE_EX1_TEST_ASSERT(Expr) if (!(Expr)) { printf("%s:%u: assertion failure\r\n", __FUNCTION__, __LINE__); while (1) ;} +#define CFSTORE_EX1_TEST_ASSERT_EQUAL(expected, actual) if ((expected) != (actual)) {printf("%s:%u: assertion failure\r\n", __FUNCTION__, __LINE__); while (1) ;} +#define CFSTORE_EX1_TEST_ASSERT_NOT_EQUAL(expected, actual) if ((expected) == (actual)) {printf("%s:%u: assertion failure\r\n", __FUNCTION__, __LINE__); while (1) ;} + +#define CFSTORE_EX1_TEST_ASSERT_MSG(Expr, _fmt, ...) \ + do \ + { \ + if (!(Expr)) \ + { \ + printf(_fmt, __VA_ARGS__); \ + while (1) ; \ + } \ + }while(0); + +#define CFSTORE_EX1_LOG(_fmt, ...) \ + do \ + { \ + printf(_fmt, __VA_ARGS__); \ + }while(0); + + +const char* cfstore_ex3_opcode_str[] = +{ + "UNDEFINED", + "CFSTORE_OPCODE_CLOSE", + "CFSTORE_OPCODE_CREATE", + "CFSTORE_OPCODE_DELETE", + "CFSTORE_OPCODE_FIND", + "CFSTORE_OPCODE_FLUSH", + "CFSTORE_OPCODE_GET_KEY_NAME", + "CFSTORE_OPCODE_GET_STATUS", + "CFSTORE_OPCODE_GET_VALUE_LEN", + "CFSTORE_OPCODE_INITIALIZE", + "CFSTORE_OPCODE_OPEN", + "CFSTORE_OPCODE_POWER_CONTROL", + "CFSTORE_OPCODE_READ", + "CFSTORE_OPCODE_RSEEK", + "CFSTORE_OPCODE_UNINITIALIZE", + "CFSTORE_OPCODE_WRITE", + "CFSTORE_OPCODE_MAX" +}; + +const char* cfstore_ex3_kv_name = "basement.medicine.pavement.government.trenchcoat.off.cough.off.kid.did.when.again.alleyway.friend.cap.pen.dollarbills.ten.foot.soot.put.but.anyway.say.May.DA.kid.did.toes.bows.those.hose.nose.clothes.man.blows.well.well"; +const char* cfstore_ex3_kv_value = "TheRollingStone"; +#define CFSTORE_EX1_RSEEK_OFFSET 10 /* offset to S of Stone */ + +typedef struct cfstore_example3_ctx_t +{ + ARM_CFSTORE_CAPABILITIES caps;; + uint8_t hkey[CFSTORE_HANDLE_BUFSIZE]; + uint8_t hkey_next_buf[CFSTORE_HANDLE_BUFSIZE]; + uint8_t hkey_prev_buf[CFSTORE_HANDLE_BUFSIZE]; + ARM_CFSTORE_HANDLE hkey_next; + ARM_CFSTORE_HANDLE hkey_prev; + ARM_CFSTORE_SIZE len; + ARM_CFSTORE_KEYDESC kdesc; + ARM_CFSTORE_FMODE flags; + char value[CFSTORE_KEY_NAME_MAX_LENGTH+1]; +} cfstore_example3_ctx_t; + +static cfstore_example3_ctx_t cfstore_example3_ctx_g; + +extern ARM_CFSTORE_DRIVER cfstore_driver; +ARM_CFSTORE_DRIVER *cfstore_drv = &cfstore_driver; + + +static void cfstore_ex3_test_01(cfstore_example3_ctx_t* ctx) +{ + int32_t ret; + + CFSTORE_EX1_LOG("INITIALIZING%s", "\r\n"); + ret = cfstore_drv->Initialize(NULL, NULL); + CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Initialize() should return ret >= 0 for async/synch modes(ret=%ld)\r\n", __func__, ret); + + CFSTORE_EX1_LOG("CREATING%s", "\r\n"); + memset(&ctx->kdesc, 0, sizeof(ARM_CFSTORE_KEYDESC)); + ctx->kdesc.drl = ARM_RETENTION_NVM; + ctx->len = strlen(cfstore_ex3_kv_value); + ret = cfstore_drv->Create(cfstore_ex3_kv_name, ctx->len, &ctx->kdesc, ctx->hkey); + CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Create() failed (ret=%ld)\r\n", __func__, ret); + + CFSTORE_EX1_LOG("WRITING%s", "\r\n"); + ctx->len = strlen(cfstore_ex3_kv_value); + ret = cfstore_drv->Write(ctx->hkey, cfstore_ex3_kv_value, &ctx->len); + CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Write() failed (ret=%ld)\r\n", __func__, ret); + + CFSTORE_EX1_TEST_ASSERT_MSG(ret == (int32_t) strlen(cfstore_ex3_kv_value), "%s:Error: Write() number of octets written (i.e. completion status (%ld)) != strlen(ctx->value)(%ld)\r\n", __func__, ret, (int32_t) strlen(cfstore_ex3_kv_value)); + CFSTORE_EX1_TEST_ASSERT_MSG(ret == (int32_t) ctx->len, "%s:Error: Write() number of octets written (i.e. completion status (%ld)) != updated value of len parameter (%ld)\r\n", __func__, ret, (int32_t) ctx->len); + + CFSTORE_EX1_LOG("CLOSING1%s", "\r\n"); + ret = cfstore_drv->Close(ctx->hkey); + CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Close() failed (ret=%ld)\r\n", __func__, ret); + + CFSTORE_EX1_LOG("FLUSHING1%s", "\r\n"); + ret = cfstore_drv->Flush(); + CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Flush() failed (ret=%ld)\r\n", __func__, ret); + + CFSTORE_EX1_LOG("OPENING%s", "\r\n"); + memset(&ctx->flags, 0, sizeof(ctx->flags)); + memset(&ctx->hkey, 0, CFSTORE_HANDLE_BUFSIZE); + ret = cfstore_drv->Open(cfstore_ex3_kv_name, ctx->flags, ctx->hkey); + CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Open() failed (ret=%ld)\r\n", __func__, ret); + + CFSTORE_EX1_LOG("READING1%s", "\r\n"); + ctx->len = CFSTORE_KEY_NAME_MAX_LENGTH; + memset(ctx->value, 0, CFSTORE_KEY_NAME_MAX_LENGTH+1); + ret = cfstore_drv->Read(ctx->hkey, ctx->value, &ctx->len); + CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Read() failed (ret=%ld)\r\n", __func__, ret); + + CFSTORE_EX1_TEST_ASSERT_MSG(ret == (int32_t) strlen(cfstore_ex3_kv_value), "%s:Error: Read() number of octets read (i.e. completion status (%ld)) != strlen(ctx->value)(%ld)\r\n", __func__, ret, (int32_t) strlen(cfstore_ex3_kv_value)); + CFSTORE_EX1_TEST_ASSERT_MSG(ret == (int32_t) ctx->len, "%s:Error: Read() number of octets read (i.e. completion status (%ld)) != updated value of len parameter (%ld)\r\n", __func__, ret, (int32_t) ctx->len); + CFSTORE_EX1_TEST_ASSERT_MSG(strncmp(ctx->value, cfstore_ex3_kv_value, strlen(cfstore_ex3_kv_value)) == 0, "%s:Error: the read value (%s) is not as expected (%s)\r\n", __func__, ctx->value, cfstore_ex3_kv_value); + + CFSTORE_EX1_LOG("RSEEKING%s", "\r\n"); + ret = cfstore_drv->Rseek(ctx->hkey, CFSTORE_EX1_RSEEK_OFFSET); + CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Rseek() failed (ret=%ld)\r\n", __func__, ret); + + CFSTORE_EX1_LOG("READING2%s", "\r\n"); + ctx->len = CFSTORE_KEY_NAME_MAX_LENGTH; + memset(ctx->value, 0, CFSTORE_KEY_NAME_MAX_LENGTH+1); + ret = cfstore_drv->Read(ctx->hkey, ctx->value, &ctx->len); + CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Read() failed (ret=%ld)\r\n", __func__, ret); + CFSTORE_EX1_TEST_ASSERT_MSG(ret == (int32_t) strlen(&cfstore_ex3_kv_value[CFSTORE_EX1_RSEEK_OFFSET]), "%s:Error: Read() number of octets read (i.e. completion status (%ld)) != strlen(ctx->value)(%ld)\r\n", __func__, ret, (int32_t) strlen(&cfstore_ex3_kv_value[CFSTORE_EX1_RSEEK_OFFSET])); + CFSTORE_EX1_TEST_ASSERT_MSG(ret == (int32_t) ctx->len, "%s:Error: Read() number of octets read (i.e. completion status (%ld)) != updated value of len parameter (%ld)\r\n", __func__, ret, (int32_t) ctx->len); + CFSTORE_EX1_TEST_ASSERT_MSG(strncmp(ctx->value, &cfstore_ex3_kv_value[CFSTORE_EX1_RSEEK_OFFSET], strlen(&cfstore_ex3_kv_value[CFSTORE_EX1_RSEEK_OFFSET])) == 0, "%s:Error: the read value (%s) is not as expected (%s)\r\n", __func__, ctx->value, &cfstore_ex3_kv_value[CFSTORE_EX1_RSEEK_OFFSET]); + + CFSTORE_EX1_LOG("CLOSING2%s", "\r\n"); + ret = cfstore_drv->Close(ctx->hkey); + CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Close() failed (ret=%ld)\r\n", __func__, ret); + + CFSTORE_EX1_LOG("FINDING1%s", "\r\n"); + ret = cfstore_drv->Find("*", ctx->hkey_next, ctx->hkey_prev); + CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Find() failed (ret=%ld)\r\n", __func__, ret); + + CFSTORE_EX1_LOG("GETTING_KEY_NAME%s", "\r\n"); + ctx->len = CFSTORE_KEY_NAME_MAX_LENGTH; + memset(ctx->value, 0, CFSTORE_KEY_NAME_MAX_LENGTH+1); + ret = cfstore_drv->GetKeyName(ctx->hkey_prev, ctx->value, (uint8_t*) &ctx->len); + CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: GetKeyName() failed (ret=%ld)\r\n", __func__, ret); + CFSTORE_EX1_TEST_ASSERT_MSG( ((int32_t) ctx->len == ((int32_t) strlen(cfstore_ex3_kv_name)+1)), "%s:Error: GetKeyName() updated value of len parameter (%ld) != strlen(cfstore_ex3_kv_name) (%ld) (\r\n", __func__, (int32_t) ctx->len, (int32_t) strlen(cfstore_ex3_kv_name)); + CFSTORE_EX1_TEST_ASSERT_MSG(strncmp(ctx->value, cfstore_ex3_kv_name, strlen(cfstore_ex3_kv_name)) == 0, "%s:Error: the key name (%s) is not as expected (%s)\r\n", __func__, ctx->value, cfstore_ex3_kv_name); + + CFSTORE_EX1_LOG("GETTING_VALUE_LEN%s", "\r\n"); + ctx->len = CFSTORE_KEY_NAME_MAX_LENGTH; + ret = cfstore_drv->GetValueLen(ctx->hkey_prev, &ctx->len); + CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: GetValueLen() failed (ret=%ld)\r\n", __func__, ret); + CFSTORE_EX1_TEST_ASSERT_MSG((int32_t) ctx->len == (int32_t) strlen(cfstore_ex3_kv_value), "%s:Error: GetValueLen() updated value of len parameter (%ld) != strlen(cfstore_ex3_kv_value)(%ld) \r\n", __func__, (int32_t) ctx->len, (int32_t) strlen(cfstore_ex3_kv_value)); + + CFSTORE_EX1_LOG("DELETING%s", "\r\n"); + ret = cfstore_drv->Delete(ctx->hkey_prev); + CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Close() failed (ret=%ld)\r\n", __func__, ret); + CFSTORE_HANDLE_SWAP(ctx->hkey_prev, ctx->hkey_next); + + CFSTORE_EX1_LOG("FINDING2%s", "\r\n"); + ret = cfstore_drv->Find("*", ctx->hkey_next, ctx->hkey_prev); + CFSTORE_EX1_TEST_ASSERT_MSG(ret == ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND, "%s:Error: Find() failed to return expected value of ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND (ret=%ld)\r\n", __func__, ret); + + CFSTORE_EX1_LOG("FLUSHING2%s", "\r\n"); + ret = cfstore_drv->Flush(); + CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error:2: Flush() failed (ret=%ld)\r\n", __func__, ret); + + CFSTORE_EX1_LOG("UNINITIALIZING%s", "\r\n"); + ret = cfstore_drv->Uninitialize(); + CFSTORE_EX1_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Uninitialize() should return ret >= 0 for synch mode(ret=%ld)\r\n", __func__, ret); + CFSTORE_EX1_LOG("***************%s", "\r\n"); + CFSTORE_EX1_LOG("*** SUCCESS ***%s", "\r\n"); + CFSTORE_EX1_LOG("***************%s", "\r\n"); + return; +} + +static control_t cfstore_example3_app_start(const size_t call_count) +{ + cfstore_example3_ctx_t* ctx = &cfstore_example3_ctx_g; + + (void) call_count; + + /* initialise the context */ + memset(ctx, 0, sizeof(cfstore_example3_ctx_t)); + ctx->hkey_next = ctx->hkey_next_buf; + ctx->hkey_prev = ctx->hkey_prev_buf; + ctx->caps = cfstore_drv->GetCapabilities(); + CFSTORE_EX1_LOG("%s:INITIALIZING: caps.asynchronous_ops=%lu\n", __func__, ctx->caps.asynchronous_ops); + if(ctx->caps.asynchronous_ops == true){ + /* This is a sync mode only test. If this test is not built for sync mode, then skip testing return true + * This means the test will conveniently pass when run in CI as part of async mode testing */ + CFSTORE_EX1_LOG("*** Skipping test as binary built for flash journal async mode, and this test is sync-only%s", "\n"); + return CaseNext; + } + cfstore_ex3_test_01(ctx); + return CaseNext; +} + +#ifndef YOTTA_CONFIGURATION_STORE_EXAMPLE3_VERSION_STRING +/* when built as Configuration-Store example, include greentea support otherwise omit */ + +/* report whether built/configured for flash sync or async mode */ +static control_t cfstore_example3_test_00(const size_t call_count) +{ + (void) call_count; + CFSTORE_EX1_LOG("INITIALIZING: caps.asynchronous_ops=%lu\n", cfstore_driver.GetCapabilities().asynchronous_ops); + return CaseNext; +} + +utest::v1::status_t greentea_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(100, "default_auto"); + return greentea_test_setup_handler(number_of_cases); +} + +Case cases[] = { + /* 1 2 3 4 5 6 7 */ + /* 1234567890123456789012345678901234567890123456789012345678901234567890 */ + Case("EXAMPLE3_test_00", cfstore_example3_test_00), + Case("EXAMPLE3_test_01_start", cfstore_example3_app_start), +}; + + +/* Declare your test specification with a custom setup handler */ +Specification specification(greentea_setup, cases); + +#if defined CFSTORE_CONFIG_MBED_OS_VERSION && CFSTORE_CONFIG_MBED_OS_VERSION == 3 +/* mbedosV3*/ +void app_start(int argc __unused, char** argv __unused) +{ + /* Run the test specification */ + Harness::run(specification); +} +#endif /* CFSTORE_CONFIG_MBED_OS_VERSION == 3 */ + +#if defined CFSTORE_CONFIG_MBED_OS_VERSION && CFSTORE_CONFIG_MBED_OS_VERSION == 4 +/* mbedosV3++*/ +int main() +{ + return !Harness::run(specification); +} +#endif /* CFSTORE_CONFIG_MBED_OS_VERSION == 4 */ + +#else // YOTTA_CONFIGURATION_STORE_EXAMPLE3_VERSION_STRING + +// stand alone Configuration-Store-Example +void app_start(int argc __unused, char** argv __unused) +{ + cfstore_example3_app_start(0); +} + + + +#endif // YOTTA_CONFIGURATION_STORE_EXAMPLE3_VERSION_STRING + + +#endif // __MBED__ && ! defined TOOLCHAIN_GCC_ARM diff --git a/TESTS/cfstore/example4/example4.cpp b/TESTS/cfstore/example4/example4.cpp new file mode 100644 index 0000000000..6ffbd11bf6 --- /dev/null +++ b/TESTS/cfstore/example4/example4.cpp @@ -0,0 +1,278 @@ +/** @file example3.cpp + * + * mbed Microcontroller Library + * Copyright (c) 2006-2016 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Test cases to add and delete KVs in the CFSTORE. + */ +#if defined __MBED__ && ! defined TOOLCHAIN_GCC_ARM + + +#include +#include +#include +#include + +#ifdef TARGET_LIKE_FRDM_K64F_GCC +#include +#endif + +#include "cfstore_config.h" +#include +#include "cfstore_debug.h" +#include "cfstore_test.h" +#include +#include "utest/utest.h" +#include "unity/unity.h" +#include "greentea-client/test_env.h" +#ifdef YOTTA_CFG_CFSTORE_UVISOR +#include "uvisor-lib/uvisor-lib.h" +#include "cfstore_uvisor.h" +#endif /* YOTTA_CFG_CFSTORE_UVISOR */ + +using namespace utest::v1; + +static control_t cfstore_example4_test_00(const size_t call_count) +{ + (void) call_count; + printf("Not implemented for ARM toolchain\n"); + return CaseNext; +} + + +utest::v1::status_t greentea_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(100, "default_auto"); + return greentea_test_setup_handler(number_of_cases); +} + +Case cases[] = { + /* 1 2 3 4 5 6 7 */ + /* 1234567890123456789012345678901234567890123456789012345678901234567890 */ + Case("EXAMPLE4_test_00", cfstore_example4_test_00), +}; + + +/* Declare your test specification with a custom setup handler */ +Specification specification(greentea_setup, cases); + +int main() +{ + return !Harness::run(specification); +} + + + +#else + + +#include +#include +#include +#include +#include + +#ifdef TARGET_LIKE_FRDM_K64F_GCC +#include +#endif + +#include "cfstore_config.h" +#include "cfstore_test.h" +#include "cfstore_debug.h" +//#include +#include +#include +#include "utest/utest.h" +#include "unity/unity.h" +#include "greentea-client/test_env.h" +#ifdef YOTTA_CFG_CONFIG_UVISOR +#include "uvisor-lib/uvisor-lib.h" +#endif /* YOTTA_CFG_CONFIG_UVISOR */ + + +using namespace utest::v1; + +static char cfstore_example4_utest_msg_g[CFSTORE_UTEST_MSG_BUF_SIZE]; + +/* Notes + * Test case created from Issue 10 code supplied by Motti Gondabi. The code: + * - creates a KV + * - writes the KV + * - closes the KV + * - flushes the KV + * - opens the KV. + * - deletes the KV. + * - flushes empty configuration store. + * + * The test case makes sure that the implementation can flush an empty configuration store + * without causing errors. This has only been possible since flash-journal-strategy-sequential + * v0.4.0. + */ + +/* defines */ +#define PvMemSet memset +#define PvStrLen strlen +#define PvKeyValue_t cfstore_kv_data_t + +ARM_CFSTORE_DRIVER *gCfStoreDriver = &cfstore_driver; + +static const PvKeyValue_t testDataKeyValue[] = { + { "com.arm.mbed.spv.assets.dtls", "This Is my DTLS Secret" }, + { "com.arm.mbed.spv.assets.asset1.payload", "The Rolling Stone" }, + { "com.arm.mbed.spv.assets.asset2.payload", "Grumpy old man" }, + { "com.arm.mbed.spv.assets.asset3.payload", "Delete this asset payload" }, +}; + + +static control_t cfstore_example4_test_00(const size_t call_count) +{ + ARM_CFSTORE_CAPABILITIES caps;; + + (void) call_count; + + /* initialise the context */ + caps = gCfStoreDriver->GetCapabilities(); + CFSTORE_LOG("%s:INITIALIZING: caps.asynchronous_ops=%lu\n", __func__, caps.asynchronous_ops); + if(caps.asynchronous_ops == true){ + /* This is a sync mode only test. If this test is not built for sync mode, then skip testing return true + * This means the test will conveniently pass when run in CI as part of async mode testing */ + CFSTORE_LOG("*** Skipping test as binary built for flash journal async mode, and this test is sync-only%s", "\n"); + return CaseNext; + } + return CaseNext; +} + + +static int32_t CreateKeyValueStore( + const char *keyName, + const char *data, + ARM_CFSTORE_SIZE *dataLength, + ARM_CFSTORE_KEYDESC *keyDesc) +{ + int32_t cfsStatus = ARM_DRIVER_ERROR; + ARM_CFSTORE_SIZE valueLength = 0; + ARM_CFSTORE_HANDLE_INIT(hkey); + + valueLength = *dataLength; + cfsStatus = gCfStoreDriver->Create(keyName, valueLength, keyDesc, hkey); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_example4_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Create() failed (cfsStatus=%" PRId32 ")\n", __func__, cfsStatus); + TEST_ASSERT_MESSAGE(cfsStatus >= ARM_DRIVER_OK, cfstore_example4_utest_msg_g); + + valueLength = *dataLength; + cfsStatus = gCfStoreDriver->Write(hkey, data, &valueLength); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_example4_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Write() failed (cfsStatus=%" PRId32 ")\n", __func__, cfsStatus); + TEST_ASSERT_MESSAGE(cfsStatus >= ARM_DRIVER_OK, cfstore_example4_utest_msg_g); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_example4_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: valueLength != *dataLength\n", __func__); + TEST_ASSERT_MESSAGE(valueLength == *dataLength, cfstore_example4_utest_msg_g); + + cfsStatus = gCfStoreDriver->Close(hkey); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_example4_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Close() failed (cfsStatus=%" PRId32 ")\n", __func__, cfsStatus); + TEST_ASSERT_MESSAGE(cfsStatus >= ARM_DRIVER_OK, cfstore_example4_utest_msg_g); + + cfsStatus = gCfStoreDriver->Flush(); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_example4_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Flush() failed (cfsStatus=%" PRId32 ")\n", __func__, cfsStatus); + TEST_ASSERT_MESSAGE(cfsStatus >= ARM_DRIVER_OK, cfstore_example4_utest_msg_g); + + return ARM_DRIVER_OK; +} + + +// main test. +static control_t cfstore_example4_test_01(const size_t call_count) +{ + int32_t cfsStatus = ARM_DRIVER_ERROR; + ARM_CFSTORE_KEYDESC kdesc; + ARM_CFSTORE_SIZE valueLen; + ARM_CFSTORE_FMODE flags; + ARM_CFSTORE_HANDLE_INIT(hkey); + + (void) call_count; + PvMemSet(&kdesc, 0, sizeof(kdesc)); + + kdesc.drl = ARM_RETENTION_NVM; + valueLen = PvStrLen(testDataKeyValue[0].value); + + cfsStatus = gCfStoreDriver->Initialize(NULL, NULL); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_example4_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Initialize() failed (cfsStatus=%" PRId32 ")\n", __func__, cfsStatus); + TEST_ASSERT_MESSAGE(cfsStatus >= ARM_DRIVER_OK, cfstore_example4_utest_msg_g); + + cfsStatus = CreateKeyValueStore(testDataKeyValue[0].key_name, testDataKeyValue[0].value, &valueLen, &kdesc); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_example4_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: CreateKeyValueStore() failed (cfsStatus=%" PRId32 ")\n", __func__, cfsStatus); + TEST_ASSERT_MESSAGE(cfsStatus >= ARM_DRIVER_OK, cfstore_example4_utest_msg_g); + + PvMemSet(&flags, 0, sizeof(flags)); + + cfsStatus = gCfStoreDriver->Open(testDataKeyValue[0].key_name, flags, hkey); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_example4_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Open() failed (cfsStatus=%" PRId32 ")\n", __func__, cfsStatus); + TEST_ASSERT_MESSAGE(cfsStatus >= ARM_DRIVER_OK, cfstore_example4_utest_msg_g); + + cfsStatus = gCfStoreDriver->Delete(hkey); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_example4_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Delete() failed (cfsStatus=%" PRId32 ")\n", __func__, cfsStatus); + TEST_ASSERT_MESSAGE(cfsStatus >= ARM_DRIVER_OK, cfstore_example4_utest_msg_g); + + cfsStatus = gCfStoreDriver->Close(hkey); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_example4_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Close() failed (cfsStatus=%" PRId32 ")\n", __func__, cfsStatus); + TEST_ASSERT_MESSAGE(cfsStatus >= ARM_DRIVER_OK, cfstore_example4_utest_msg_g); + + cfsStatus = gCfStoreDriver->Flush(); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_example4_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Flush() failed (cfsStatus=%" PRId32 ")\n", __func__, cfsStatus); + TEST_ASSERT_MESSAGE(cfsStatus >= ARM_DRIVER_OK, cfstore_example4_utest_msg_g); + + cfsStatus = gCfStoreDriver->Uninitialize(); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_example4_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Uninitialize() failed (cfsStatus=%" PRId32 ")\n", __func__, cfsStatus); + TEST_ASSERT_MESSAGE(cfsStatus >= ARM_DRIVER_OK, cfstore_example4_utest_msg_g); + + return CaseNext; +} + + +utest::v1::status_t greentea_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(400, "default_auto"); + return greentea_test_setup_handler(number_of_cases); +} + +Case cases[] = { + /* 1 2 3 4 5 6 7 */ + /* 1234567890123456789012345678901234567890123456789012345678901234567890 */ + Case("EXAMPLE4_test_00", cfstore_example4_test_00), +#if defined YOTTA_CFG_CONFIG_HARDWARE_MTD_ASYNC_OPS && YOTTA_CFG_CONFIG_HARDWARE_MTD_ASYNC_OPS == 0 + Case("EXAMPLE4_test_01", cfstore_example4_test_01), +#endif // YOTTA_CFG_CONFIG_HARDWARE_MTD_ASYNC_OPS +}; + + +/* Declare your test specification with a custom setup handler */ +Specification specification(greentea_setup, cases); + +#if defined CFSTORE_CONFIG_MBED_OS_VERSION && CFSTORE_CONFIG_MBED_OS_VERSION == 3 +/* mbedosV3*/ +void app_start(int argc __unused, char** argv __unused) +{ + /* Run the test specification */ + Harness::run(specification); +} +#endif /* CFSTORE_CONFIG_MBED_OS_VERSION == 3 */ + +#if defined CFSTORE_CONFIG_MBED_OS_VERSION && CFSTORE_CONFIG_MBED_OS_VERSION == 4 +/* mbedosV3++*/ +int main() +{ + return !Harness::run(specification); +} +#endif /* CFSTORE_CONFIG_MBED_OS_VERSION == 4 */ + + +#endif // __MBED__ && ! defined TOOLCHAIN_GCC_ARM diff --git a/TESTS/cfstore/example5/example5.cpp b/TESTS/cfstore/example5/example5.cpp new file mode 100644 index 0000000000..9e234c2ef6 --- /dev/null +++ b/TESTS/cfstore/example5/example5.cpp @@ -0,0 +1,365 @@ +/** @file EXAMPLE5.cpp + * + * mbed Microcontroller Library + * Copyright (c) 2006-2016 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Test cases to add and delete KVs in the CFSTORE. + */ + + +/* Notes + * ===== + * + * The flash-journal synchronous mode example test does the following CFSTORE operations: + * - initialises + * - creates a key-value pair (KV). + * - writes the data for the KV + * - closes KV. + * - flushes the KV to flash + * - flushes the KV to flash again + * - uninitialises + * - initialises + * - opens KV for reading. + * - deletes KV + * - closes KV. + * - flushes the updated state to flash to store the removal of the deleted KV. + * - uninitialises + * - stops + * + * This test is coded so as to work only in flash journal sync mode + * i.e. with caps.asynchronous_ops == false + * + * The test leaves the flash in the same state as at the beginning of the test so + * it can be run a second time on the device without flashing, and the test should + * still work. + */ + +#if defined __MBED__ && ! defined TOOLCHAIN_GCC_ARM + + +#include +#include +#include +#include + +#ifdef TARGET_LIKE_FRDM_K64F_GCC +#include +#endif + +#include "cfstore_config.h" +#include +#include "cfstore_debug.h" +#include "cfstore_test.h" +#include +#include "utest/utest.h" +#include "unity/unity.h" +#include "greentea-client/test_env.h" +#ifdef YOTTA_CFG_CFSTORE_UVISOR +#include "uvisor-lib/uvisor-lib.h" +#include "cfstore_uvisor.h" +#endif /* YOTTA_CFG_CFSTORE_UVISOR */ + +using namespace utest::v1; + +static control_t cfstore_example5_test_00(const size_t call_count) +{ + (void) call_count; + printf("Not implemented for ARM toolchain\n"); + return CaseNext; +} + + +utest::v1::status_t greentea_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(100, "default_auto"); + return greentea_test_setup_handler(number_of_cases); +} + +Case cases[] = { + /* 1 2 3 4 5 6 7 */ + /* 1234567890123456789012345678901234567890123456789012345678901234567890 */ + Case("EXAMPLE5_test_00", cfstore_example5_test_00), +}; + + +/* Declare your test specification with a custom setup handler */ +Specification specification(greentea_setup, cases); + +int main() +{ + return !Harness::run(specification); +} + + +#else + + +#include +#include +#include +#include + +#ifdef TARGET_LIKE_FRDM_K64F_GCC +#include +#endif + +//#include +#include + +#ifndef YOTTA_CONFIGURATION_STORE_EXAMPLE5_VERSION_STRING +/* when built as Configuration-Store example, include greentea support otherwise omit */ +#include "utest/utest.h" +#include "unity/unity.h" +#include "greentea-client/test_env.h" +#else // YOTTA_CONFIGURATION_STORE_EXAMPLE5_VERSION_STRING +// map utest types for building as stand alone example +#define control_t void +#define CaseNext +#endif // YOTTA_CONFIGURATION_STORE_EXAMPLE5_VERSION_STRING + +#include "cfstore_config.h" +#include + + +#ifndef YOTTA_CONFIGURATION_STORE_EXAMPLE5_VERSION_STRING +using namespace utest::v1; +#endif + + +#define CFSTORE_EX5_TEST_ASSERT(Expr) if (!(Expr)) { printf("%s:%u: assertion failure\r\n", __FUNCTION__, __LINE__); while (1) ;} +#define CFSTORE_EX5_TEST_ASSERT_EQUAL(expected, actual) if ((expected) != (actual)) {printf("%s:%u: assertion failure\r\n", __FUNCTION__, __LINE__); while (1) ;} +#define CFSTORE_EX5_TEST_ASSERT_NOT_EQUAL(expected, actual) if ((expected) == (actual)) {printf("%s:%u: assertion failure\r\n", __FUNCTION__, __LINE__); while (1) ;} + +#define CFSTORE_EX5_TEST_ASSERT_MSG(Expr, _fmt, ...) \ + do \ + { \ + if (!(Expr)) \ + { \ + printf(_fmt, __VA_ARGS__); \ + while (1) ; \ + } \ + }while(0); + +#define CFSTORE_EX5_LOG(_fmt, ...) \ + do \ + { \ + printf(_fmt, __VA_ARGS__); \ + }while(0); + + +const char* cfstore_ex5_opcode_str[] = +{ + "UNDEFINED", + "CFSTORE_OPCODE_CLOSE", + "CFSTORE_OPCODE_CREATE", + "CFSTORE_OPCODE_DELETE", + "CFSTORE_OPCODE_FIND", + "CFSTORE_OPCODE_FLUSH", + "CFSTORE_OPCODE_GET_KEY_NAME", + "CFSTORE_OPCODE_GET_STATUS", + "CFSTORE_OPCODE_GET_VALUE_LEN", + "CFSTORE_OPCODE_INITIALIZE", + "CFSTORE_OPCODE_OPEN", + "CFSTORE_OPCODE_POWER_CONTROL", + "CFSTORE_OPCODE_READ", + "CFSTORE_OPCODE_RSEEK", + "CFSTORE_OPCODE_UNINITIALIZE", + "CFSTORE_OPCODE_WRITE", + "CFSTORE_OPCODE_MAX" +}; + +const char* cfstore_ex5_kv_name = "basement.medicine.pavement.government.trenchcoat.off.cough.off.kid.did.when.again.alleyway.friend.cap.pen.dollarbills.ten.foot.soot.put.but.anyway.say.May.DA.kid.did.toes.bows.those.hose.nose.clothes.man.blows.well.well"; +const char* cfstore_ex5_kv_value = "TheRollingStone"; +#define CFSTORE_EX5_RSEEK_OFFSET 10 /* offset to S of Stone */ + +typedef struct cfstore_EXAMPLE5_ctx_t +{ + ARM_CFSTORE_CAPABILITIES caps;; + uint8_t hkey[CFSTORE_HANDLE_BUFSIZE]; + uint8_t hkey_next_buf[CFSTORE_HANDLE_BUFSIZE]; + uint8_t hkey_prev_buf[CFSTORE_HANDLE_BUFSIZE]; + ARM_CFSTORE_HANDLE hkey_next; + ARM_CFSTORE_HANDLE hkey_prev; + ARM_CFSTORE_SIZE len; + ARM_CFSTORE_KEYDESC kdesc; + ARM_CFSTORE_FMODE flags; + char value[CFSTORE_KEY_NAME_MAX_LENGTH+1]; +} cfstore_EXAMPLE5_ctx_t; + +static cfstore_EXAMPLE5_ctx_t cfstore_EXAMPLE5_ctx_g; + +extern ARM_CFSTORE_DRIVER cfstore_driver; +ARM_CFSTORE_DRIVER *cfstore_drv = &cfstore_driver; + + +static void cfstore_ex5_test_01(cfstore_EXAMPLE5_ctx_t* ctx) +{ + int32_t ret; + + CFSTORE_EX5_LOG("INITIALIZING1%s", "\r\n"); + ret = cfstore_drv->Initialize(NULL, NULL); + CFSTORE_EX5_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Initialize() should return ret >= 0 for async/synch modes(ret=%ld)\r\n", __func__, ret); + + CFSTORE_EX5_LOG("CREATING%s", "\r\n"); + memset(&ctx->kdesc, 0, sizeof(ARM_CFSTORE_KEYDESC)); + ctx->kdesc.drl = ARM_RETENTION_NVM; + ctx->len = strlen(cfstore_ex5_kv_value); + ret = cfstore_drv->Create(cfstore_ex5_kv_name, ctx->len, &ctx->kdesc, ctx->hkey); + CFSTORE_EX5_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Create() failed (ret=%ld)\r\n", __func__, ret); + + CFSTORE_EX5_LOG("WRITING%s", "\r\n"); + ctx->len = strlen(cfstore_ex5_kv_value); + ret = cfstore_drv->Write(ctx->hkey, cfstore_ex5_kv_value, &ctx->len); + CFSTORE_EX5_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Write() failed (ret=%ld)\r\n", __func__, ret); + + CFSTORE_EX5_TEST_ASSERT_MSG(ret == (int32_t) strlen(cfstore_ex5_kv_value), "%s:Error: Write() number of octets written (i.e. completion status (%ld)) != strlen(ctx->value)(%ld)\r\n", __func__, ret, (int32_t) strlen(cfstore_ex5_kv_value)); + CFSTORE_EX5_TEST_ASSERT_MSG(ret == (int32_t) ctx->len, "%s:Error: Write() number of octets written (i.e. completion status (%ld)) != updated value of len parameter (%ld)\r\n", __func__, ret, (int32_t) ctx->len); + + CFSTORE_EX5_LOG("CLOSING1%s", "\r\n"); + ret = cfstore_drv->Close(ctx->hkey); + CFSTORE_EX5_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Close() failed (ret=%ld)\r\n", __func__, ret); + + CFSTORE_EX5_LOG("FLUSHING1%s", "\r\n"); + ret = cfstore_drv->Flush(); + CFSTORE_EX5_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Flush() failed (ret=%ld)\r\n", __func__, ret); + + /* commenting out the 2nd flush() means the test works.*/ + //CFSTORE_EX5_LOG("FLUSHING2%s", "\r\n"); + //ret = cfstore_drv->Flush(); + //CFSTORE_EX5_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Flush() failed (ret=%ld)\r\n", __func__, ret); + + /* todo: re-instate when Flush() really persists to flash on mbedOSv3+++. + * currently in the supported sram version Uninitialize() clears the sram + CFSTORE_EX5_LOG("UNINITIALIZING1%s", "\r\n"); + ret = cfstore_drv->Uninitialize(); + CFSTORE_EX5_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Uninitialize() should return ret >= 0 for synch mode(ret=%ld)\r\n", __func__, ret); + + CFSTORE_EX5_LOG("INITIALIZING2%s", "\r\n"); + ret = cfstore_drv->Initialize(NULL, NULL); + CFSTORE_EX5_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Initialize() should return ret >= 0 for async/synch modes(ret=%ld)\r\n", __func__, ret); + */ + + CFSTORE_EX5_LOG("OPENING%s", "\r\n"); + memset(&ctx->flags, 0, sizeof(ctx->flags)); + memset(&ctx->hkey, 0, CFSTORE_HANDLE_BUFSIZE); + ret = cfstore_drv->Open(cfstore_ex5_kv_name, ctx->flags, ctx->hkey); + CFSTORE_EX5_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Open() failed (ret=%ld)\r\n", __func__, ret); + + CFSTORE_EX5_LOG("DELETE1%s", "\r\n"); + ctx->len = CFSTORE_KEY_NAME_MAX_LENGTH; + memset(ctx->value, 0, CFSTORE_KEY_NAME_MAX_LENGTH + 1); + ret = cfstore_drv->Delete(ctx->hkey); + CFSTORE_EX5_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Delete() failed (ret=%ld)\r\n", __func__, ret); + + CFSTORE_EX5_LOG("CLOSING2%s", "\r\n"); + ret = cfstore_drv->Close(ctx->hkey); + CFSTORE_EX5_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Close() failed (ret=%ld)\r\n", __func__, ret); + + CFSTORE_EX5_LOG("FLUSHING3%s", "\r\n"); + ret = cfstore_drv->Flush(); + CFSTORE_EX5_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Flush() failed (ret=%ld)\r\n", __func__, ret); + + CFSTORE_EX5_LOG("OPEN2 %s", "\r\n"); + memset(&ctx->flags, 0, sizeof(ctx->flags)); + memset(&ctx->hkey, 0, CFSTORE_HANDLE_BUFSIZE); + ret = cfstore_drv->Open(cfstore_ex5_kv_name, ctx->flags, ctx->hkey); + CFSTORE_EX5_TEST_ASSERT_MSG(ret == ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND, "%s:Error: Find() failed to return expected value of ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND (ret=%ld)\r\n", __func__, ret); + + CFSTORE_EX5_LOG("FLUSHING2%s", "\r\n"); + ret = cfstore_drv->Flush(); + CFSTORE_EX5_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error:2: Flush() failed (ret=%ld)\r\n", __func__, ret); + + CFSTORE_EX5_LOG("UNINITIALIZING3%s", "\r\n"); + ret = cfstore_drv->Uninitialize(); + CFSTORE_EX5_TEST_ASSERT_MSG(ret >= ARM_DRIVER_OK, "%s:Error: Uninitialize() should return ret >= 0 for synch mode(ret=%ld)\r\n", __func__, ret); + CFSTORE_EX5_LOG("***************%s", "\r\n"); + CFSTORE_EX5_LOG("*** SUCCESS ***%s", "\r\n"); + CFSTORE_EX5_LOG("***************%s", "\r\n"); + return; +} + +static control_t cfstore_EXAMPLE5_app_start(const size_t call_count) +{ + cfstore_EXAMPLE5_ctx_t* ctx = &cfstore_EXAMPLE5_ctx_g; + + (void) call_count; + + /* initialise the context */ + memset(ctx, 0, sizeof(cfstore_EXAMPLE5_ctx_t)); + ctx->hkey_next = ctx->hkey_next_buf; + ctx->hkey_prev = ctx->hkey_prev_buf; + ctx->caps = cfstore_drv->GetCapabilities(); + CFSTORE_EX5_LOG("%s:INITIALIZING: caps.asynchronous_ops=%lu\n", __func__, ctx->caps.asynchronous_ops); + if(ctx->caps.asynchronous_ops == true){ + /* This is a sync mode only test. If this test is not built for sync mode, then skip testing return true + * This means the test will conveniently pass when run in CI as part of async mode testing */ + CFSTORE_EX5_LOG("*** Skipping test as binary built for flash journal async mode, and this test is sync-only%s", "\n"); + return CaseNext; + } + cfstore_ex5_test_01(ctx); + return CaseNext; +} + +#ifndef YOTTA_CONFIGURATION_STORE_EXAMPLE5_VERSION_STRING +/* when built as Configuration-Store example, include greentea support otherwise omit */ + +utest::v1::status_t greentea_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(100, "default_auto"); + return greentea_test_setup_handler(number_of_cases); +} + +Case cases[] = { + /* 1 2 3 4 5 6 7 */ + /* 1234567890123456789012345678901234567890123456789012345678901234567890 */ + Case("EXAMPLE5_test_01_start", cfstore_EXAMPLE5_app_start), +}; + + +/* Declare your test specification with a custom setup handler */ +Specification specification(greentea_setup, cases); + + +#if defined CFSTORE_CONFIG_MBED_OS_VERSION && CFSTORE_CONFIG_MBED_OS_VERSION == 3 +/* mbedosV3*/ +void app_start(int argc __unused, char** argv __unused) +{ + /* Run the test specification */ + Harness::run(specification); +} +#endif /* CFSTORE_CONFIG_MBED_OS_VERSION == 3 */ + +#if defined CFSTORE_CONFIG_MBED_OS_VERSION && CFSTORE_CONFIG_MBED_OS_VERSION == 4 +/* mbedosV3++*/ +int main() +{ + return !Harness::run(specification); +} +#endif /* CFSTORE_CONFIG_MBED_OS_VERSION == 4 */ + + +#else // YOTTA_CONFIGURATION_STORE_EXAMPLE5_VERSION_STRING + +// stand alone Configuration-Store-Example +void app_start(int argc __unused, char** argv __unused) +{ + cfstore_EXAMPLE5_app_start(0); +} + + +#endif // YOTTA_CONFIGURATION_STORE_EXAMPLE5_VERSION_STRING + + +#endif // __MBED__ && ! defined TOOLCHAIN_GCC_ARM diff --git a/TESTS/cfstore/find/find.cpp b/TESTS/cfstore/find/find.cpp new file mode 100644 index 0000000000..b8b58a926c --- /dev/null +++ b/TESTS/cfstore/find/find.cpp @@ -0,0 +1,443 @@ +/** @file find.cpp + * + * mbed Microcontroller Library + * Copyright (c) 2006-2016 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Test cases to find KVs in the CFSTORE using the drv->Find() interface. + */ +#if defined __MBED__ && ! defined TOOLCHAIN_GCC_ARM + + +#include +#include +#include +#include + +#ifdef TARGET_LIKE_FRDM_K64F_GCC +#include +#endif + +#include "cfstore_config.h" +#include +#include "cfstore_debug.h" +#include "cfstore_test.h" +#include +#include "utest/utest.h" +#include "unity/unity.h" +#include "greentea-client/test_env.h" +#ifdef YOTTA_CFG_CFSTORE_UVISOR +#include "uvisor-lib/uvisor-lib.h" +#include "cfstore_uvisor.h" +#endif /* YOTTA_CFG_CFSTORE_UVISOR */ + +using namespace utest::v1; + +static control_t cfstore_find_test_00(const size_t call_count) +{ + (void) call_count; + printf("Not implemented for ARM toolchain\n"); + return CaseNext; +} + + +utest::v1::status_t greentea_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(100, "default_auto"); + return greentea_test_setup_handler(number_of_cases); +} + +Case cases[] = { + /* 1 2 3 4 5 6 7 */ + /* 1234567890123456789012345678901234567890123456789012345678901234567890 */ + Case("FIND_test_00", cfstore_find_test_00), +}; + + +/* Declare your test specification with a custom setup handler */ +Specification specification(greentea_setup, cases); + +int main() +{ + return !Harness::run(specification); +} + + + +#else + + +#include +#include +#include +#include +#include + +#ifdef TARGET_LIKE_FRDM_K64F_GCC +#include +#endif + +#include "cfstore_config.h" +#include "cfstore_test.h" +#include "cfstore_debug.h" +//#include +#include +#include +#include "utest/utest.h" +#include "unity/unity.h" +#include "greentea-client/test_env.h" +#include "cfstore_utest.h" +#ifdef YOTTA_CFG_CFSTORE_UVISOR +#include "uvisor-lib/uvisor-lib.h" +#endif /* YOTTA_CFG_CFSTORE_UVISOR */ + +using namespace utest::v1; + +static char cfstore_find_utest_msg_g[CFSTORE_UTEST_MSG_BUF_SIZE]; + +/* Configure secure box. */ +#ifdef YOTTA_CFG_CFSTORE_UVISOR +UVISOR_BOX_NAMESPACE("com.arm.mbed.cfstore.test.find.box1"); +UVISOR_BOX_CONFIG(cfstore_find_box1, UVISOR_BOX_STACK_SIZE); +#endif /* YOTTA_CFG_CFSTORE_UVISOR */ + + +/* report whether built/configured for flash sync or async mode */ +static control_t cfstore_find_test_00(const size_t call_count) +{ + (void) call_count; + CFSTORE_LOG("INITIALIZING: caps.asynchronous_ops=%lu\n", cfstore_driver.GetCapabilities().asynchronous_ops); + return CaseNext; +} + +/** + * @brief test to call cfstore_find() with a key_name string that exceeds + * the maximum length + * @return status code + * ARM_DRIVER_OK, the test passed successfully + * ret < ARM_DRIVER_OK, the test failed with the return code + * supplying more details + */ +static control_t cfstore_find_test_01(const size_t call_count) +{ + (void) call_count; + /*todo: implement test */ + CFSTORE_TEST_UTEST_MESSAGE(cfstore_find_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Warn: Not implemented\n", __func__); + CFSTORE_LOG("%s: WARN: requires implementation\n", __func__); + TEST_ASSERT_MESSAGE(true, cfstore_find_utest_msg_g); + return CaseNext; +} + + +/** + * @brief test to call cfstore_find() with key_name that in includes + * illegal characters + * - the character can be at the beginning of the key_name + * - the character can be at the end of the key_name + * - the character can be somewhere within the key_name string + * + * @return status code + * ARM_DRIVER_OK, the test passed successfully + * ret < ARM_DRIVER_OK, the test failed with the return code + * supplying more details + */ +static control_t cfstore_find_test_02(const size_t call_count) +{ + /*todo: implement test + * + * specify the allowable characters in a set. + * e.g. "0123456789ABCDEFGHIJKLMNOPQRSTUVQXYZabcdefghijklmnopqrstuvwxyz.[]*" + * and use this set as the sell of allowable character codes. + * All other 0-255 values for character codes should not be found in the key_name string + * but the function should be tested for what happens in that case. + * + * Some code may be common here with other functions requiring a key_name e.g. cfstore_find( + */ + (void) call_count; + /*todo: implement test */ + CFSTORE_TEST_UTEST_MESSAGE(cfstore_find_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Warn: Not implemented\n", __func__); + CFSTORE_LOG("%s: WARN: requires implementation\n", __func__); + TEST_ASSERT_MESSAGE(true, cfstore_find_utest_msg_g); + return CaseNext; +} + + + +static control_t cfstore_find_test_03_end(const size_t call_count) +{ + char* read_buf = NULL; + const uint8_t key_name_max_len = CFSTORE_KEY_NAME_MAX_LENGTH+1; + char key_name_buf[key_name_max_len]; + int32_t ret = ARM_DRIVER_ERROR; + ARM_CFSTORE_SIZE len = 0; + ARM_CFSTORE_SIZE max_len = 0; + cfstore_kv_data_t* node; + cfstore_kv_data_t* client_node = cfstore_test_init_1_data; + ARM_CFSTORE_DRIVER* drv = &cfstore_driver; + ARM_CFSTORE_KEYDESC kdesc; + ARM_CFSTORE_HANDLE_INIT(prev); + ARM_CFSTORE_HANDLE_INIT(next); + + CFSTORE_DBGLOG("%s:entered\r\n", __func__); + (void) call_count; + memset(&kdesc, 0, sizeof(kdesc)); + memset(key_name_buf, 0, CFSTORE_KEY_NAME_MAX_LENGTH+1); + + /*scan for max length of value blob*/ + node = client_node; + while(node->key_name != NULL) + { + len = strlen(node->value); + if(len > max_len){ + max_len = len; + } + node++; + } + max_len++; /* space for a terminating null, if required */ + read_buf = (char*) malloc(max_len); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_find_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Failed to allocated read buffer \r\n", __func__); + TEST_ASSERT_MESSAGE(read_buf != NULL, cfstore_find_utest_msg_g); + + ret = cfstore_test_init_1(); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_find_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to initialise cfstore area with entries\r\n", __func__); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_find_utest_msg_g); + + /* now find and read back the key values */ + ret = ARM_DRIVER_ERROR; + node = client_node; + while(node->key_name != NULL) + { + CFSTORE_DBGLOG("%s:About to find node (key_name=\"%s\", value=\"%s\")\r\n", __func__, node->key_name, node->value); + ret = drv->Find(node->key_name, prev, next); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_find_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Failed to find node (key_name=\"%s\", value=\"%s\")\r\n", __func__, node->key_name, node->value); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_find_utest_msg_g); + + CFSTORE_TEST_UTEST_MESSAGE(cfstore_find_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Find failed to return valid key handle\r\n", __func__); + TEST_ASSERT_MESSAGE(next != NULL, cfstore_find_utest_msg_g); + + ret = drv->GetValueLen(next, &len); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_find_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to write key (key_name=\"%s\", value=\"%s\")\r\n", __func__, node->key_name, node->value); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_find_utest_msg_g); + + if(len > 0) { + ret = drv->Read(next, read_buf, &len); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_find_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to read value (key_name=\"%s\", value=\"%s\")\r\n", __func__, node->key_name, node->value); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_find_utest_msg_g); + + /* check read data is as expected */ + CFSTORE_TEST_UTEST_MESSAGE(cfstore_find_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Read value data (%s) != KV value data (key_name=\"%s\", value=\"%s\")\r\n", __func__, read_buf, node->key_name, node->value); + TEST_ASSERT_MESSAGE(strncmp(read_buf, node->value, strlen(node->value)) == 0, cfstore_find_utest_msg_g); + + } + read_buf[len] = '\0'; + printf("Successfully found KV and read value data (key_name=\"%s\", value=\"%s\")\r\n", node->key_name, read_buf); + memset(read_buf, 0, len); + drv->Close(next); + node++; + } + + ret = drv->Uninitialize(); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_find_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Uninitialize() call failed.\n", __func__); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_find_utest_msg_g); + return CaseNext; +} + + +static cfstore_kv_data_t cfstore_find_test_04_kv_data[] = { + { "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", "abcdefghjklmnopqrstuvwxyzabcdefghjklmnopqrstuvwxyzabcdefghjklmnopqrstuvwxyzabcdefghjklmnopqrstuvwxyzabcdefghjklmnopqrstuvwxyzabcdefghjklmnopqrstuvwxyzabcdefghjklmnopqrstuvwxyzabcdefghjklmnopqrstuvwxyzabcdefghjklmnopqrstuvwxyz"}, + { NULL, NULL}, +}; + +/** + * @brief TODO: write test that uses cfstore_find_test_04_kv_data to grow {key, value} + * from 1 char to 221 chars long. + * + * @return status code + * ARM_DRIVER_OK, the test passed successfully + * ret < ARM_DRIVER_OK, the test failed with the return code + * supplying more details + */ +static control_t cfstore_find_test_04(const size_t call_count) +{ + /*todo: implement test + * + * */ + (void) cfstore_find_test_04_kv_data; + (void) call_count; + /*todo: implement test */ + CFSTORE_TEST_UTEST_MESSAGE(cfstore_find_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Warn: Not implemented\n", __func__); + CFSTORE_LOG("%s: WARN: requires implementation\n", __func__); + TEST_ASSERT_MESSAGE(true, cfstore_find_utest_msg_g); + return CaseNext; +} + + +/** + * @brief function to test whether a key name is valid, can be added to the + * cfstore and found by a wildcard string + * + * @param key_name + * name of the key to create in the store + * @param match + * string to use to try and find key_name in the cfstore + * @param should_find + * if true, then 'match' should find 'key_name' in the store + * if false, then 'match' should not find 'key_name' in the store + * + * @return status code + * ARM_DRIVER_OK, the test passed successfully + * ret < ARM_DRIVER_OK, the test failed with the return code + * supplying more details + */ +bool cfstore_find_key_name_validate(const char *key_name, const char *match, bool should_find) +{ + bool bret = true; + bool btest_status = false; + char* test_data = (char*) "test_data"; + int32_t ret = ARM_DRIVER_ERROR; + ARM_CFSTORE_SIZE len = 0; + ARM_CFSTORE_KEYDESC kdesc; + + CFSTORE_FENTRYLOG("%s:entered\r\n", __func__); + memset(&kdesc, 0, sizeof(kdesc)); + + /* create */ + kdesc.drl = ARM_RETENTION_WHILE_DEVICE_ACTIVE; + len = strlen(test_data); + ret = cfstore_test_create((const char*) key_name, test_data, &len, &kdesc); + if(ret < ARM_DRIVER_OK){ + CFSTORE_ERRLOG("%s:Error: failed to create kv (key_name=%s.\r\n", "cfstore_find_test_05_ex", key_name); + return ret; + } + ret = cfstore_test_kv_is_found(match, &bret); + if(ret < ARM_DRIVER_OK && ret != ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND){ + CFSTORE_ERRLOG("%s:Error: cfstore_test_kv_is_found() failed.\r\n", "cfstore_find_test_05_ex"); + return ret; + } + /* dont not use any functions that require finding the created item as they may not work, + * depending on the construction of the test key_name & match strings */ + if(should_find == bret) + { + CFSTORE_DBGLOG("%s:Success: Find() behaved as expected.\r\n", "cfstore_find_test_05_ex"); + btest_status = true; + } + else + { + CFSTORE_ERRLOG("cfstore_find_test_05_ex: Failed match on %s vs. %s\n", key_name, match); + } + /*delete using the actual name */ + ret = cfstore_test_delete((const char*) key_name); + if(ret < ARM_DRIVER_OK){ + CFSTORE_ERRLOG("%s:Error: failed to delete kv (key_name=%s)(ret=%d).\r\n", "cfstore_find_test_05_ex", key_name, (int)ret); + } + return btest_status; +} + + +typedef struct cfstore_find_key_name_validate_t { + const char* key_name; + const char* match; + uint32_t f_allowed : 1; +} cfstore_find_key_name_validate_t; + +cfstore_find_key_name_validate_t cfstore_find_test_05_data[] = { + { "yotta.hello-world.animal{wobbly-dog}{foot}backLeft", "yotta.hello-world.animal{*}{foot}backLeft", true}, + { "yotta.hello-world.animal{wobbly-dog}{foot}backLeft", "yotta.hello-world.animal{wobbly-dog}{*}backLeft", true}, + { "yotta.hello-world.animal{wobbly-dog}{foot}backLeft", "yotta.hello-world.animal{wobbly-dog}{*}*", true}, + { "yotta.hello-world.animal{1}{foot}backLeft", "yotta.hello-world.animal{?}{foot}backLeft", false}, + { "xyz", "xyz", true}, + { "xyzijkXYZ", "XYZ", false}, + { "xyzijkXYZ", "*XYZ", true}, + { "xyzijkXYZ", "xyz*XYZ", true}, + { "xyzijkXYZ", "*yz*XYZ", true}, + { "xyzijkXYZ", "*ijk*", true}, + { NULL, NULL, false}, +}; + + +/** + * @brief test whether a key name in the above table are valid, can be added to the + * cfstore and found by a wildcard string + * + * @return status code + * ARM_DRIVER_OK, the test passed successfully + * ret < ARM_DRIVER_OK, the test failed with the return code + * supplying more details + */ +static control_t cfstore_find_test_05_end(const size_t call_count) +{ + bool ret = false; + int32_t ret32 = ARM_DRIVER_ERROR; + ARM_CFSTORE_DRIVER* drv = &cfstore_driver; + cfstore_find_key_name_validate_t* node = cfstore_find_test_05_data; + + (void) call_count; + + while(node->key_name != NULL) + { + ret = cfstore_find_key_name_validate(node->key_name, node->match, node->f_allowed); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_find_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: test failed (ret=%d)\n", __func__, (int) ret); + TEST_ASSERT_MESSAGE(ret == true, cfstore_find_utest_msg_g); + node++; + } + + ret32 = drv->Uninitialize(); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_find_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Uninitialize() call failed.\n", __func__); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_find_utest_msg_g); + return CaseNext; +} + + +utest::v1::status_t greentea_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(400, "default_auto"); + return greentea_test_setup_handler(number_of_cases); +} + +Case cases[] = { + /* 1 2 3 4 5 6 7 */ + /* 1234567890123456789012345678901234567890123456789012345678901234567890 */ + Case("FIND_test_00", cfstore_find_test_00), + Case("FIND_test_01", cfstore_find_test_01), + Case("FIND_test_02", cfstore_find_test_02), + Case("FIND_test_03_start", cfstore_utest_default_start), + Case("FIND_test_03_end", cfstore_find_test_03_end), + Case("FIND_test_04", cfstore_find_test_04), + Case("FIND_test_05_start", cfstore_utest_default_start), + Case("FIND_test_05_end", cfstore_find_test_05_end), +}; + + +/* Declare your test specification with a custom setup handler */ +Specification specification(greentea_setup, cases); + +#if defined CFSTORE_CONFIG_MBED_OS_VERSION && CFSTORE_CONFIG_MBED_OS_VERSION == 3 +/* mbedosV3*/ +void app_start(int argc __unused, char** argv __unused) +{ + /* Run the test specification */ + Harness::run(specification); +} +#endif /* CFSTORE_CONFIG_MBED_OS_VERSION == 3 */ + +#if defined CFSTORE_CONFIG_MBED_OS_VERSION && CFSTORE_CONFIG_MBED_OS_VERSION == 4 +/* mbedosV3++*/ +int main() +{ + return !Harness::run(specification); +} +#endif /* CFSTORE_CONFIG_MBED_OS_VERSION == 4 */ + + +#endif // __MBED__ && ! defined TOOLCHAIN_GCC_ARM diff --git a/TESTS/cfstore/find2/find2.cpp b/TESTS/cfstore/find2/find2.cpp new file mode 100644 index 0000000000..e0e02fcf5d --- /dev/null +++ b/TESTS/cfstore/find2/find2.cpp @@ -0,0 +1,310 @@ +/** @file find.cpp + * + * mbed Microcontroller Library + * Copyright (c) 2006-2016 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Test cases to find KVs in the CFSTORE using the drv->Find() interface. + */ +#if defined __MBED__ && ! defined TOOLCHAIN_GCC_ARM + + +#include +#include +#include +#include + +#ifdef TARGET_LIKE_FRDM_K64F_GCC +#include +#endif + +#include "cfstore_config.h" +#include +#include "cfstore_debug.h" +#include "cfstore_test.h" +#include +#include "utest/utest.h" +#include "unity/unity.h" +#include "greentea-client/test_env.h" +#ifdef YOTTA_CFG_CFSTORE_UVISOR +#include "uvisor-lib/uvisor-lib.h" +#include "cfstore_uvisor.h" +#endif /* YOTTA_CFG_CFSTORE_UVISOR */ + +using namespace utest::v1; + +static control_t cfstore_find2_test_00(const size_t call_count) +{ + (void) call_count; + printf("Not implemented for ARM toolchain\n"); + return CaseNext; +} + + +utest::v1::status_t greentea_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(100, "default_auto"); + return greentea_test_setup_handler(number_of_cases); +} + +Case cases[] = { + /* 1 2 3 4 5 6 7 */ + /* 1234567890123456789012345678901234567890123456789012345678901234567890 */ + Case("FIND2_test_00", cfstore_find2_test_00), +}; + + +/* Declare your test specification with a custom setup handler */ +Specification specification(greentea_setup, cases); + +int main() +{ + return !Harness::run(specification); +} + + + +#else + + +#include +#include +#include +#include +#include + +#ifdef TARGET_LIKE_FRDM_K64F_GCC +#include +#endif + +#include "cfstore_config.h" +#include "cfstore_test.h" +#include "cfstore_debug.h" +//#include +#include +#include +#include "utest/utest.h" +#include "unity/unity.h" +#include "greentea-client/test_env.h" +#ifdef YOTTA_CFG_CFSTORE_UVISOR +#include "uvisor-lib/uvisor-lib.h" +#endif /* YOTTA_CFG_CFSTORE_UVISOR */ + +using namespace utest::v1; + +static char cfstore_find2_utest_msg_g[CFSTORE_UTEST_MSG_BUF_SIZE]; + +/* Configure secure box. */ +#ifdef YOTTA_CFG_CFSTORE_UVISOR +UVISOR_BOX_NAMESPACE("com.arm.mbed.cfstore.test.find2.box1"); +UVISOR_BOX_CONFIG(cfstore_find2_box1, UVISOR_BOX_STACK_SIZE); +#endif /* YOTTA_CFG_CFSTORE_UVISOR */ + + +extern ARM_CFSTORE_DRIVER cfstore_driver; + +#ifdef TARGET_LIKE_FRDM_K64F_GCC +#define CFSTORE_FIND_MBED_HOSTTEST_TIMEOUT 60 +#endif + +void cfstore_find2_callback(int32_t status, ARM_CFSTORE_OPCODE cmd_code, void *client_context, ARM_CFSTORE_HANDLE handle) +{ + (void) status; + (void) cmd_code; + (void) client_context; + (void) handle; + return; +} + +/* report whether built/configured for flash sync or async mode */ +static control_t cfstore_find2_test_00(const size_t call_count) +{ + (void) call_count; + CFSTORE_LOG("INITIALIZING: caps.asynchronous_ops=%lu\n", cfstore_driver.GetCapabilities().asynchronous_ops); + return CaseNext; +} + + +static control_t cfstore_find2_test_01(const size_t call_count) +{ + char keyBuffer[128] = "com.arm.mbed.manifest-manager.root.AQAAAAAAAAA-.manifest"; + int32_t rc; + ARM_CFSTORE_HANDLE_INIT(hkey); + ARM_CFSTORE_HANDLE_INIT(prev); + + // Initialize the config store + (void) call_count; + cfstore_driver.Initialize(cfstore_find2_callback, NULL); + cfstore_driver.PowerControl(ARM_POWER_FULL); + + // Find the target key + rc = cfstore_driver.Find(keyBuffer, prev, hkey); + + // If the target key was not found + if (rc == ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND) { + ARM_CFSTORE_KEYDESC kdesc = { + .acl = { + .perm_owner_read = 1, + .perm_owner_write = 1, + .perm_owner_execute = 0, + .perm_other_read = 1, + .perm_other_write = 0, + .perm_other_execute = 0, + /* added initialisers */ + .reserved = 0 + }, .drl = ARM_RETENTION_WHILE_DEVICE_ACTIVE, + .security = { + .acls = 1, + .rollback_protection = 0, + .tamper_proof = 0, + .internal_flash = 0, + /* added initialisers */ + .reserved1 = 0, + .software_attacks = 0, + .board_level_attacks = 0, + .chip_level_attacks = 0, + .side_channel_attacks = 0, + .reserved2 = 0 + }, + .flags = { + .continuous = 0, + .lazy_flush = 1, + .flush_on_close = 1, + .read = 0, + .write = 1, + .execute = 0, + .storage_detect = 1, + /* added initialisers */ + .reserved = 0 + } + }; + + // Create the target key + rc = cfstore_driver.Create(keyBuffer, 191, &kdesc, hkey); + } + return CaseNext; +} + + +/* fixed version of brendans code */ +#define CFSTORE_FIND2_TEST_02_VALUE_SIZE 191 +static control_t cfstore_find2_test_02(const size_t call_count) +{ + char keyBuffer[128] = "com.arm.mbed.manifest-manager.root.AQAAAAAAAAA-.manifest"; + + int32_t rc; + ARM_CFSTORE_HANDLE_INIT(hkey); + ARM_CFSTORE_HANDLE_INIT(prev); + ARM_CFSTORE_SIZE length; + char value[CFSTORE_FIND2_TEST_02_VALUE_SIZE]; + + // Initialize the config store + (void) call_count; + cfstore_driver.Initialize(NULL, NULL); /* non-null client_callback not supported for MBED_V_0_1_x */ + cfstore_driver.PowerControl(ARM_POWER_FULL); + memset(value, 0, 191); + + // Find the target key + rc = cfstore_driver.Find(keyBuffer, prev, hkey); + + // If the target key was not found + if (rc == ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND) { + ARM_CFSTORE_KEYDESC kdesc = { + .acl = { + .perm_owner_read = 1, + .perm_owner_write = 1, + .perm_owner_execute = 0, + .perm_other_read = 1, + .perm_other_write = 0, + .perm_other_execute = 0, + .reserved = 0 + }, .drl = ARM_RETENTION_WHILE_DEVICE_ACTIVE, /* DATA_RETENTION_NVM not supported for MBED_V_0_1_x */ + .security = { + .acls = 0, /* protection against internal software attacks using ACLs not supported for MBED_V_0_1_x */ + .rollback_protection = 0, + .tamper_proof = 0, + .internal_flash = 0, + .reserved1 = 0, + .software_attacks = 0, + .board_level_attacks = 0, + .chip_level_attacks = 0, + .side_channel_attacks = 0, + .reserved2 = 0 + }, + .flags = { + .continuous = 0, + .lazy_flush = 0, /* lazy flush not supported for MBED_V_0_1_x */ + .flush_on_close = 0, /* flush on close not supported for MBED_V_0_1_x */ + .read = 0, + .write = 1, + .execute = 0, + .storage_detect = 0, /* storage detect supported for MBED_V_0_1_x */ + /* added initialisers */ + .reserved = 0 + + } + }; + + // Create the target key + rc = cfstore_driver.Create(keyBuffer, 191, &kdesc, hkey); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_find2_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%sError: failed to create key\n", __func__); + TEST_ASSERT_MESSAGE(rc >= ARM_DRIVER_OK, cfstore_find2_utest_msg_g); + + strncpy(value, "MyValueData", CFSTORE_FIND2_TEST_02_VALUE_SIZE); + length = strlen(value); + rc = cfstore_driver.Write(hkey, value, &length); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_find2_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%sError: failed to write key\n", __func__); + TEST_ASSERT_MESSAGE(rc >= ARM_DRIVER_OK, cfstore_find2_utest_msg_g); + printf("Success!\n"); + } + return CaseNext; +} + +utest::v1::status_t greentea_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(400, "default_auto"); + return greentea_test_setup_handler(number_of_cases); +} + +Case cases[] = { + /* 1 2 3 4 5 6 7 */ + /* 1234567890123456789012345678901234567890123456789012345678901234567890 */ + Case("FIND2_test_00", cfstore_find2_test_00), + Case("FIND2_test_01", cfstore_find2_test_01), + Case("FIND2_test_02", cfstore_find2_test_02), +}; + + +/* Declare your test specification with a custom setup handler */ +Specification specification(greentea_setup, cases); + +#if defined CFSTORE_CONFIG_MBED_OS_VERSION && CFSTORE_CONFIG_MBED_OS_VERSION == 3 +/* mbedosV3*/ +void app_start(int argc __unused, char** argv __unused) +{ + /* Run the test specification */ + Harness::run(specification); +} +#endif /* CFSTORE_CONFIG_MBED_OS_VERSION == 3 */ + +#if defined CFSTORE_CONFIG_MBED_OS_VERSION && CFSTORE_CONFIG_MBED_OS_VERSION == 4 +/* mbedosV3++*/ +int main() +{ + return !Harness::run(specification); +} +#endif /* CFSTORE_CONFIG_MBED_OS_VERSION == 4 */ + + +#endif // __MBED__ && ! defined TOOLCHAIN_GCC_ARM diff --git a/TESTS/cfstore/flash/flash.cpp b/TESTS/cfstore/flash/flash.cpp new file mode 100644 index 0000000000..1f2dc7c6d6 --- /dev/null +++ b/TESTS/cfstore/flash/flash.cpp @@ -0,0 +1,752 @@ +/* @file flush.cpp + * + * mbed Microcontroller Library + * Copyright (c) 2006-2016 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Test cases to flush KVs in the CFSTORE using the drv->Flush() interface. + */ +#if defined __MBED__ && ! defined TOOLCHAIN_GCC_ARM + + +#include +#include +#include +#include + +#ifdef TARGET_LIKE_FRDM_K64F_GCC +#include +#endif + +#include "cfstore_config.h" +#include +#include "cfstore_debug.h" +#include "cfstore_test.h" +#include +#include "utest/utest.h" +#include "unity/unity.h" +#include "greentea-client/test_env.h" +#ifdef YOTTA_CFG_CFSTORE_UVISOR +#include "uvisor-lib/uvisor-lib.h" +#include "cfstore_uvisor.h" +#endif /* YOTTA_CFG_CFSTORE_UVISOR */ + +using namespace utest::v1; + +static control_t cfstore_flash_test_00(const size_t call_count) +{ + (void) call_count; + printf("Not implemented for ARM toolchain\n"); + return CaseNext; +} + + +utest::v1::status_t greentea_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(100, "default_auto"); + return greentea_test_setup_handler(number_of_cases); +} + +Case cases[] = { + /* 1 2 3 4 5 6 7 */ + /* 1234567890123456789012345678901234567890123456789012345678901234567890 */ + Case("FLASH_test_00", cfstore_flash_test_00), +}; + + +/* Declare your test specification with a custom setup handler */ +Specification specification(greentea_setup, cases); + +int main() +{ + return !Harness::run(specification); +} + + +#else + + + +#include +#include +#include +#include + +#if defined CFSTORE_CONFIG_BACKEND_FLASH_ENABLED && CFSTORE_CONFIG_BACKEND_FLASH_ENABLED == 1 +#include +#include +#endif /* CFSTORE_CONFIG_BACKEND_FLASH_ENABLED */ +#include "cfstore_config.h" +#include "cfstore_test.h" +#include "cfstore_debug.h" +//#include +#include +#include +#include "utest/utest.h" +#include "unity/unity.h" +#include "greentea-client/test_env.h" +#ifdef YOTTA_CFG_CFSTORE_UVISOR +#include "uvisor-lib/uvisor-lib.h" +#endif /* YOTTA_CFG_CFSTORE_UVISOR */ + +using namespace utest::v1; + +/* Configure secure box. */ +#ifdef YOTTA_CFG_CFSTORE_UVISOR +UVISOR_BOX_NAMESPACE("com.arm.mbed.cfstore.test.flash.box1"); +UVISOR_BOX_CONFIG(cfstore_flash_box1, UVISOR_BOX_STACK_SIZE); +#endif /* YOTTA_CFG_CFSTORE_UVISOR */ + + + +/* shared code common to both sync and async test cases */ + +/* + * Defines + * + */ +#define CFSTORE_FREE free +#define CFSTORE_MALLOC malloc +#define CFSTORE_REALLOC realloc +#define CFSTORE_FLASH_STACK_BUF_SIZE 64 +#define CFSTORE_FLASH_K64F_CURRENT_PROGRAM_UNIT_SIZE 8 +#define CFSTORE_TEST_DATA_KEYNAME "com.arm.mbed.configurationstore.test.flush.cfstoreflushtest02" +#define CFSTORE_TEST_DATA_KEYNAME_SHORT "com.arm" +#define CFSTORE_TEST_DATA_VALUE_INIT "\1" +#define CFSTORE_TEST_DATA_KEYNAME_SIZE (sizeof(CFSTORE_TEST_DATA_KEYNAME) - 1) +#define CFSTORE_TEST_DATA_VALUE_SIZE (sizeof(CFSTORE_TEST_DATA_VALUE_INIT) - 1) +#define CFSTORE_FLASH_UTEST_MSG_BUF_SIZE 256 +#define CFSTORE_FLASH_MTD_ASYNC_OPS_ON 1 +#define CFSTORE_FLASH_MTD_ASYNC_OPS_OFF 0 +#define CFSTORE_FLASH_CASE_TIMEOUT_MS 5000 + +/* + * Globals + */ + +#if defined CFSTORE_CONFIG_BACKEND_FLASH_ENABLED && CFSTORE_CONFIG_BACKEND_FLASH_ENABLED == 1 +char cfstore_flash_utest_msg_g[CFSTORE_FLASH_UTEST_MSG_BUF_SIZE]; +uint16_t cfstore_flash_mtd_async_ops_g = 0; +extern ARM_DRIVER_STORAGE ARM_Driver_Storage_(0); + +/* KV data for test_01 */ +static cfstore_kv_data_t cfstore_flush_test_01_kv_data[] = { + { CFSTORE_TEST_DATA_KEYNAME, CFSTORE_TEST_DATA_VALUE_INIT}, + { NULL, NULL}, +}; + + +/* @brief key value header structure defining key_name length, value length + * @note + * 8 bytes long */ +typedef struct cfstore_area_header_t +{ + uint32_t vlength; + uint8_t klength; + uint8_t perm_owner_read : 1; + uint8_t perm_owner_write : 1; + uint8_t perm_owner_execute : 1; + uint8_t perm_other_read : 1; + uint8_t perm_other_write : 1; + uint8_t perm_other_execute : 1; + uint8_t reserved : 2; + uint8_t refcount; + struct flags_t { + uint8_t deleting : 1; + uint8_t reserved : 7; + } flags ; +} cfstore_area_header_t; + + +/* @brief data structure for managing test data */ +typedef struct cfstore_flash_data_blob_t { + cfstore_area_header_t hdr; + uint8_t data[CFSTORE_TEST_DATA_KEYNAME_SIZE + CFSTORE_TEST_DATA_VALUE_SIZE]; /* 61 bytes for key_name, 1 byte for value */ +} cfstore_flash_data_blob_t; + +/* + * Defines + * + * CFSTORE_FLASH_AREA_SIZE_MIN + * valid sizes of areas should always be greater than the size of the header, and therefore + * greater than this value, which is defined as smaller than the header size + */ +#define CFSTORE_FLASH_AREA_SIZE_MIN (sizeof(cfstore_area_header_t) - 1) + +/* + * Shared implementation between sync and async tests + */ + +/* print key name string from area where key_name is not null terminated*/ +static void cfstore_dump_key_name(uint8_t* keyname, uint8_t len, const char* tag) +{ + char blob_data[CFSTORE_KEY_NAME_MAX_LENGTH]; + + (void) tag; + assert(keyname != NULL); + assert(tag != NULL); + assert(len > 0); + memcpy(blob_data, keyname, len); + blob_data[len] = '\0'; + CFSTORE_DBGLOG("%s:keyname=%s\r\n", tag, blob_data); +} + +/* @brief test fsm states and events */ +typedef enum cfstore_flash_fsm_state_t { + cfstore_flash_fsm_state_initializing = 0, + cfstore_flash_fsm_state_reading, + cfstore_flash_fsm_state_writing, + cfstore_flash_fsm_state_committing, + cfstore_flash_fsm_state_max +} cfstore_flash_fsm_state_t; + +/* @brief test fsm events */ +typedef enum cfstore_flash_fsm_event_t { + cfstore_flash_fsm_event_init_done = 0, + cfstore_flash_fsm_event_read_done, + cfstore_flash_fsm_event_write_done, + cfstore_flash_fsm_event_commit_done, + cfstore_flash_fsm_event_max, +} cfstore_flash_fsm_event_t; + +typedef void (*cfstore_flash_fsm_handler)(void* ctx); + +typedef struct cfstore_fsm_t +{ + cfstore_flash_fsm_state_t state; + cfstore_flash_fsm_event_t event; +} cfstore_fsm_t; + +typedef struct cfstore_flash_ctx_t +{ + uint8_t* area_0_head; + uint8_t* area_0_tail; + FlashJournal_t jrnl; + uint64_t expected_blob_size; + cfstore_fsm_t fsm; + int32_t status; + FlashJournal_OpCode_t cmd_code; + uint64_t expected_read_size; +} cfstore_flash_ctx_t; + +/* + * Globals + */ +static cfstore_flash_ctx_t cfstore_flash_ctx_g; +static const char* cfstore_flash_opcode_str[] = +{ + "FLASH_JOURNAL_OPCODE_INITIALIZE", + "FLASH_JOURNAL_OPCODE_GET_INFO", + "FLASH_JOURNAL_OPCODE_READ_BLOB", + "FLASH_JOURNAL_OPCODE_LOG_BLOB", + "FLASH_JOURNAL_OPCODE_COMMIT", + "FLASH_JOURNAL_OPCODE_RESET", +}; + +#ifdef CFSTORE_DEBUG +static const char* cfstore_flash_state_str[] = +{ + "initializing", + "reading", + "writing", + "committing", + "unknown" +}; + +static const char* cfstore_flash_event_str[] = +{ + "init_done", + "read_done", + "write_done", + "commit_done", + "unknown" +}; +#endif /* CFSTORE_DEBUG */ + +/* + * Forward decl + */ +static void cfstore_fsm_state_handle_event(cfstore_fsm_t* fsm, cfstore_flash_fsm_event_t event, void* context); +static void cfstore_fsm_state_set(cfstore_fsm_t* fsm, cfstore_flash_fsm_state_t new_state, void* ctx); + +/* + * context related methods + */ + +/* @brief get a pointer to the global context data structure */ +static cfstore_flash_ctx_t* cfstore_flash_ctx_get(void) +{ + return &cfstore_flash_ctx_g; +} + + +/* @brief flash journal asynchronous callback handler */ +void cfstore_flash_test_01_callback(int32_t status, FlashJournal_OpCode_t cmd_code) +{ + cfstore_flash_ctx_t* ctx = cfstore_flash_ctx_get(); + + CFSTORE_FENTRYLOG("%s:entered: status=%d, cmd_code=%d (%s)\r\n", __func__, (int) status, (int) cmd_code, cfstore_flash_opcode_str[cmd_code]); + switch(cmd_code) + { + case FLASH_JOURNAL_OPCODE_INITIALIZE: + ctx->fsm.event = cfstore_flash_fsm_event_init_done; + break; + case FLASH_JOURNAL_OPCODE_READ_BLOB: + ctx->fsm.event = cfstore_flash_fsm_event_read_done; + break; + case FLASH_JOURNAL_OPCODE_LOG_BLOB: + ctx->fsm.event = cfstore_flash_fsm_event_write_done; + break; + case FLASH_JOURNAL_OPCODE_COMMIT: + ctx->fsm.event = cfstore_flash_fsm_event_commit_done; + break; + case FLASH_JOURNAL_OPCODE_GET_INFO: + case FLASH_JOURNAL_OPCODE_RESET: + default: + CFSTORE_TEST_UTEST_MESSAGE(cfstore_flash_utest_msg_g, CFSTORE_FLASH_UTEST_MSG_BUF_SIZE, "%s:Error: received asynchronous notification for opcode=%d (%s) when api call should have been synchronous", __func__, cmd_code, cmd_code <= FLASH_JOURNAL_OPCODE_RESET ? cfstore_flash_opcode_str[cmd_code] : "unknown"); + TEST_ASSERT_MESSAGE(false, cfstore_flash_utest_msg_g) + return; + } + ctx->status = status; + ctx->cmd_code = cmd_code; + cfstore_fsm_state_handle_event(&ctx->fsm, ctx->fsm.event, (void*) ctx); + return; +} + + +/* @brief fsm handler called on entry to initializing state */ +static void cfstore_flash_fsm_init_on_entry(void* context) +{ + /* round up cfstore_flash_data_blob_t to nearest k64f program unit size */ + const ARM_DRIVER_STORAGE *drv = &ARM_Driver_Storage_(0); + FlashJournal_Info_t info; + FlashJournal_Status_t status = JOURNAL_STATUS_ERROR; + cfstore_flash_ctx_t* ctx = (cfstore_flash_ctx_t*) context; + + /* check that the mtd is in synchronous mode */ + CFSTORE_FENTRYLOG("%s:entered: \r\n", __func__); + memset(&info, 0, sizeof(info)); + + /* FlashJournal_initialize() is potentially asynchronous */ + status = (FlashJournal_Status_t) FlashJournal_initialize(&ctx->jrnl, drv, &FLASH_JOURNAL_STRATEGY_SEQUENTIAL, cfstore_flash_test_01_callback); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_flash_utest_msg_g, CFSTORE_FLASH_UTEST_MSG_BUF_SIZE, "%s:Error: failed to initialize flash journaling layer (status=%d)\r\n", __func__, status); + TEST_ASSERT_MESSAGE(status >= JOURNAL_STATUS_OK, cfstore_flash_utest_msg_g); + /* if status > 0, expect async callback, otherwise initialisation has been completed */ + if(status > 0) { + cfstore_flash_test_01_callback(status, FLASH_JOURNAL_OPCODE_INITIALIZE); + } + return; +} + +/* brief callback handler when in state initializing */ +static void cfstore_flash_fsm_initializing(void* context) +{ + cfstore_flash_ctx_t* ctx = (cfstore_flash_ctx_t*) context; + + CFSTORE_FENTRYLOG("%s:entered\r\n", __func__); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_flash_utest_msg_g, CFSTORE_FLASH_UTEST_MSG_BUF_SIZE, "%s:Error: entered handler(%s) but not in initializing state (fsm->state=%d)\r\n", __func__, __func__, (int) ctx->fsm.state); + TEST_ASSERT_MESSAGE(ctx->fsm.state == cfstore_flash_fsm_state_initializing, cfstore_flash_utest_msg_g); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_flash_utest_msg_g, CFSTORE_FLASH_UTEST_MSG_BUF_SIZE, "%s:Error: cmd_code code (%d) is not as expected (%d)\r\n", __func__, ctx->cmd_code, FLASH_JOURNAL_OPCODE_INITIALIZE); + TEST_ASSERT_MESSAGE(ctx->cmd_code == FLASH_JOURNAL_OPCODE_INITIALIZE, cfstore_flash_utest_msg_g); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_flash_utest_msg_g, CFSTORE_FLASH_UTEST_MSG_BUF_SIZE, "%s:Error: status=%" PRId32 "\r\n", __func__, ctx->status); + TEST_ASSERT_MESSAGE(ctx->status >= JOURNAL_STATUS_OK, cfstore_flash_utest_msg_g); + /* only change state if status > 0*/ + if(ctx->status > 0){ + cfstore_fsm_state_set(&ctx->fsm, cfstore_flash_fsm_state_reading, ctx); + } +} + +/* static void cfstore_flash_fsm_init_on_exit(void* context){ (void) context;} */ + +/* brief callback handler called when entering the reading state + * note + * flash journal has initialised successfully. now + */ +static void cfstore_flash_fsm_read_on_entry(void* context) +{ + uint8_t* ptr = NULL; + int32_t ret = 0; + FlashJournal_Info_t info; + FlashJournal_Status_t status = JOURNAL_STATUS_ERROR; + cfstore_flash_ctx_t* ctx = (cfstore_flash_ctx_t*) context; + + CFSTORE_FENTRYLOG("%s:entered\r\n", __func__); + CFSTORE_ASSERT(ctx != NULL); + /* drv->GetInfo() is synchronous */ + status = FlashJournal_getInfo(&ctx->jrnl, &info); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_flash_utest_msg_g, CFSTORE_FLASH_UTEST_MSG_BUF_SIZE, "%s:Error: failed get journal info (status=%d)\r\n", __func__, (int) status); + TEST_ASSERT_MESSAGE(status == JOURNAL_STATUS_OK, cfstore_flash_utest_msg_g); + CFSTORE_DBGLOG("%s:FlashJournal_getInfo() done. info.sizeofJournaledBlob=%lu\r\n", __func__, (long unsigned int) info.sizeofJournaledBlob); + + if(info.sizeofJournaledBlob > 0) + { + /* setup the expected blob size for writing + * This is a multiple of program unit so the write doesnt fail due to unaligned log */ + ctx->expected_blob_size = sizeof(cfstore_flash_data_blob_t); + if(ctx->expected_blob_size % CFSTORE_FLASH_K64F_CURRENT_PROGRAM_UNIT_SIZE > 0){ + ctx->expected_blob_size += (CFSTORE_FLASH_K64F_CURRENT_PROGRAM_UNIT_SIZE - (sizeof(cfstore_flash_data_blob_t) % CFSTORE_FLASH_K64F_CURRENT_PROGRAM_UNIT_SIZE)); + } + /* test that a blob size is the expected size for flash data that has been written before */ + CFSTORE_TEST_UTEST_MESSAGE(cfstore_flash_utest_msg_g, CFSTORE_FLASH_UTEST_MSG_BUF_SIZE, "%s:Error: info.sizeofJournaledBlob does not match expect size. expected_blob_size (%lu) != info.sizeofJournaledBlob (%lu)\r\n", __func__, (unsigned long int) ctx->expected_blob_size, (unsigned long int) info.sizeofJournaledBlob); + TEST_ASSERT_EQUAL_INT64_MESSAGE(ctx->expected_blob_size, info.sizeofJournaledBlob, cfstore_flash_utest_msg_g); + + /* grow the area by the size of the stored blob */ + ptr = (uint8_t*) CFSTORE_REALLOC((void*) ctx->area_0_head, ctx->expected_blob_size); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_flash_utest_msg_g, CFSTORE_FLASH_UTEST_MSG_BUF_SIZE, "%s:realloc failed flash blob (size=%d)\r\n", __func__, (int)info.sizeofJournaledBlob); + TEST_ASSERT_MESSAGE(ptr != NULL, cfstore_flash_utest_msg_g); + memset(ptr, 0, ctx->expected_blob_size); + if(ptr != ctx->area_0_head){ + CFSTORE_DBGLOG("%s:cfstore_ctx_g.area_0_head pointer changed (cfstore_ctx_g.area_0_head=%p, ptr=%p)\r\n", __func__, ctx->area_0_head, ptr); + ctx->area_0_head = ptr; + ctx->area_0_tail = ctx->area_0_head + info.sizeofJournaledBlob; + } + ret = FlashJournal_read(&ctx->jrnl, (void*) ctx->area_0_head, info.sizeofJournaledBlob); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_flash_utest_msg_g, CFSTORE_FLASH_UTEST_MSG_BUF_SIZE, "%s:Error: unable to read flash journal (ret=%" PRId32 ". info.sizeofJournaledBlob=%d)\r\n", __func__, ret, (int) info.sizeofJournaledBlob); + TEST_ASSERT_MESSAGE(ret >= JOURNAL_STATUS_OK, cfstore_flash_utest_msg_g); + if(ret > 0){ + /* read has completed synchronously*/ + CFSTORE_TEST_UTEST_MESSAGE(cfstore_flash_utest_msg_g, CFSTORE_FLASH_UTEST_MSG_BUF_SIZE, "%s:Error: unable to read all data from flash journal (expected size=%lu, read=%" PRId32 ")\r\n", __func__, (unsigned long int)info.sizeofJournaledBlob, ret); + TEST_ASSERT_EQUAL_INT32_MESSAGE( (int32_t) info.sizeofJournaledBlob, ret, cfstore_flash_utest_msg_g); + cfstore_flash_test_01_callback(ret, FLASH_JOURNAL_OPCODE_READ_BLOB); + } + } else { + /* there is no blob, move to next state. need a +ve status value to indicate async completion + * to the fsm reading state handler. use CFSTORE_FLASH_AREA_SIZE_MIN for this value */ + ctx->expected_blob_size = CFSTORE_FLASH_AREA_SIZE_MIN; + status = (FlashJournal_Status_t) CFSTORE_FLASH_AREA_SIZE_MIN; + cfstore_flash_test_01_callback(status, FLASH_JOURNAL_OPCODE_READ_BLOB); + } + return; +} + +/* @brief fsm handler when in reading state */ +void cfstore_flash_fsm_reading(void* context) +{ + int32_t ret = 0; + cfstore_flash_ctx_t* ctx = (cfstore_flash_ctx_t*) context; + cfstore_flash_data_blob_t *blob = NULL; + + CFSTORE_FENTRYLOG("%s:entered\r\n", __func__); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_flash_utest_msg_g, CFSTORE_FLASH_UTEST_MSG_BUF_SIZE, "%s:Error: entered handler(%s) but not in reading state (fsm->state=%d)\r\n", __func__, __func__, (int) ctx->fsm.state); + TEST_ASSERT_MESSAGE(ctx->fsm.state == cfstore_flash_fsm_state_reading, cfstore_flash_utest_msg_g); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_flash_utest_msg_g, CFSTORE_FLASH_UTEST_MSG_BUF_SIZE, "%s:Error: cmd_code code (%d) is not as expected (%d)\r\n", __func__, ctx->cmd_code, FLASH_JOURNAL_OPCODE_READ_BLOB); + TEST_ASSERT_MESSAGE(ctx->cmd_code == FLASH_JOURNAL_OPCODE_READ_BLOB, cfstore_flash_utest_msg_g); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_flash_utest_msg_g, CFSTORE_FLASH_UTEST_MSG_BUF_SIZE, "%s:Error: status=%" PRId32 "\r\n", __func__, ctx->status); + TEST_ASSERT_MESSAGE(ctx->status >= JOURNAL_STATUS_OK, cfstore_flash_utest_msg_g); + + if(ctx->status > 0) + { + if(ctx->status > (int32_t) CFSTORE_FLASH_AREA_SIZE_MIN) + { + /* check the correct amount of data was read, which is the status code */ + CFSTORE_TEST_UTEST_MESSAGE(cfstore_flash_utest_msg_g, CFSTORE_FLASH_UTEST_MSG_BUF_SIZE, "%s:Error: unable to read all data from flash journal (expected size=%lu, read=%" PRId32 ")\r\n", __func__, (unsigned long int) ctx->expected_blob_size, ctx->status); + /* ctx->status contains the status of the read that was completed */ + TEST_ASSERT_EQUAL_INT64_MESSAGE(ctx->expected_blob_size, (int32_t) ctx->status, cfstore_flash_utest_msg_g); + if(ctx->area_0_head != NULL) + { + /* check the key_name read from flash is correct */ + blob = (cfstore_flash_data_blob_t*) ctx->area_0_head; + cfstore_dump_key_name(blob->data, CFSTORE_TEST_DATA_KEYNAME_SIZE, __func__); + ret = memcmp(blob->data, cfstore_flush_test_01_kv_data[0].key_name, strlen(cfstore_flush_test_01_kv_data[0].key_name)); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_flash_utest_msg_g, CFSTORE_FLASH_UTEST_MSG_BUF_SIZE, "%s:Error: incorrect key_name read from flash (expected 0 from memcpy(keyname, flash_data), actual was non-zero)", __func__); + TEST_ASSERT_EQUAL_INT_MESSAGE(0, ret, cfstore_flash_utest_msg_g); + } + } + cfstore_fsm_state_set(&ctx->fsm, cfstore_flash_fsm_state_writing, ctx); + } +} + +/* void cfstore_flash_fsm_read_on_exit(void* context){ (void) context;} */ + +/* @brief on entry to writing state, update value */ +void cfstore_flash_fsm_write_on_entry(void* context) +{ + uint8_t value = 0; + int32_t ret = 0; + cfstore_flash_ctx_t* ctx = (cfstore_flash_ctx_t*) context; + cfstore_flash_data_blob_t *blob = NULL; + + CFSTORE_FENTRYLOG("%s:entered:\r\n", __func__); + /* allocate memory for data if not already done so */ + if(ctx->area_0_head == NULL) + { + /* This is a multiple of program unit so the write doesnt fail due to unaligned log */ + ctx->expected_blob_size = sizeof(cfstore_flash_data_blob_t); + if(ctx->expected_blob_size % CFSTORE_FLASH_K64F_CURRENT_PROGRAM_UNIT_SIZE > 0){ + ctx->expected_blob_size += (CFSTORE_FLASH_K64F_CURRENT_PROGRAM_UNIT_SIZE - (sizeof(cfstore_flash_data_blob_t) % CFSTORE_FLASH_K64F_CURRENT_PROGRAM_UNIT_SIZE)); + } + ctx->area_0_head = (uint8_t*) CFSTORE_REALLOC((void*) ctx->area_0_head, ctx->expected_blob_size); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_flash_utest_msg_g, CFSTORE_FLASH_UTEST_MSG_BUF_SIZE, "%s:Error: unable to allocate memory for context\r\n", __func__); + TEST_ASSERT_MESSAGE(ctx->area_0_head != NULL, cfstore_flash_utest_msg_g); + ctx->area_0_tail = ctx->area_0_head + ctx->expected_blob_size; + memset(ctx->area_0_head, 0, ctx->expected_blob_size); + /* setup data to write to flash */ + blob = (cfstore_flash_data_blob_t*) ctx->area_0_head; + blob->hdr.klength = strlen(cfstore_flush_test_01_kv_data->key_name); + blob->hdr.vlength= 1; + blob->hdr.perm_owner_read = true; + blob->hdr.perm_owner_write = true; + blob->hdr.refcount = 1; + memcpy((void*) blob->data, (const void*) cfstore_flush_test_01_kv_data->key_name, strlen(cfstore_flush_test_01_kv_data->key_name)); + memcpy((void*) &blob->data[CFSTORE_TEST_DATA_KEYNAME_SIZE], (const void*) cfstore_flush_test_01_kv_data->value, strlen(cfstore_flush_test_01_kv_data->value)); + } + if(ctx->area_0_head != NULL) + { + /* data has been read */ + /* check the key_name read from flash is correct */ + blob = (cfstore_flash_data_blob_t*) ctx->area_0_head; + value = (uint8_t) blob->data[CFSTORE_TEST_DATA_KEYNAME_SIZE]; + printf("INFO: value read from flash = %u\r\n", value); + /* update the value */ + value++; + memcpy((void*) &blob->data[CFSTORE_TEST_DATA_KEYNAME_SIZE], (const void*) &value, sizeof(uint8_t)); + } + + ret = FlashJournal_log(&ctx->jrnl, (const void*) ctx->area_0_head, ctx->expected_blob_size); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_flash_utest_msg_g, CFSTORE_FLASH_UTEST_MSG_BUF_SIZE, "%s:Error: ret = JOURNAL_STATUS_SMALL_LOG_REQUEST, bailing out.", __func__); + TEST_ASSERT_MESSAGE(ret != (int32_t) JOURNAL_STATUS_SMALL_LOG_REQUEST, cfstore_flash_utest_msg_g); + + CFSTORE_TEST_UTEST_MESSAGE(cfstore_flash_utest_msg_g, CFSTORE_FLASH_UTEST_MSG_BUF_SIZE, "%s:Error: failed to perform log operation to flash journal (ret=%" PRId32 ")\r\n", __func__, ret); + TEST_ASSERT_MESSAGE(ret >= 0, cfstore_flash_utest_msg_g); + if(ret > 0){ + /* write has completed synchronously*/ + CFSTORE_TEST_UTEST_MESSAGE(cfstore_flash_utest_msg_g, CFSTORE_FLASH_UTEST_MSG_BUF_SIZE, "%s:Error: unable to write all data from flash journal (expected size=%lu, read=%d)\r\n", __func__, (unsigned long int) ctx->expected_blob_size, (int) ret); + TEST_ASSERT_EQUAL_INT32_MESSAGE(ret, (int32_t) ctx->expected_blob_size, cfstore_flash_utest_msg_g); + cfstore_flash_test_01_callback(ret, FLASH_JOURNAL_OPCODE_LOG_BLOB); + } + /* wait for async completion handler*/ +} + +/* @brief fsm handler when in reading state */ +void cfstore_flash_fsm_writing(void* context) +{ + cfstore_flash_ctx_t* ctx = (cfstore_flash_ctx_t*) context; + + CFSTORE_FENTRYLOG("%s:entered:\r\n", __func__); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_flash_utest_msg_g, CFSTORE_FLASH_UTEST_MSG_BUF_SIZE, "%s:Error: entered handler(%s) but not in writing state (fsm->state=%d)\r\n", __func__, __func__, (int) ctx->fsm.state); + TEST_ASSERT_MESSAGE(ctx->fsm.state == cfstore_flash_fsm_state_writing, cfstore_flash_utest_msg_g); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_flash_utest_msg_g, CFSTORE_FLASH_UTEST_MSG_BUF_SIZE, "%s:Error: cmd_code code (%d) is not as expected (%d)\r\n", __func__, ctx->cmd_code, FLASH_JOURNAL_OPCODE_LOG_BLOB); + TEST_ASSERT_MESSAGE(ctx->cmd_code == FLASH_JOURNAL_OPCODE_LOG_BLOB, cfstore_flash_utest_msg_g); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_flash_utest_msg_g, CFSTORE_FLASH_UTEST_MSG_BUF_SIZE, "%s:Error: status=%" PRId32 "\r\n", __func__, ctx->status); + TEST_ASSERT_MESSAGE(ctx->status >= JOURNAL_STATUS_OK, cfstore_flash_utest_msg_g); + + if(ctx->status > 0){ + /* check the correct amount of data was written */ + CFSTORE_TEST_UTEST_MESSAGE(cfstore_flash_utest_msg_g, CFSTORE_FLASH_UTEST_MSG_BUF_SIZE, "%s:Error: unable to write all data from flash journal (expected size=%lu, read=%" PRId32 ")\r\n", __func__, (unsigned long int) ctx->expected_blob_size, ctx->status); + TEST_ASSERT_EQUAL_INT64_MESSAGE(ctx->expected_blob_size, ctx->status, cfstore_flash_utest_msg_g); + cfstore_fsm_state_set(&ctx->fsm, cfstore_flash_fsm_state_committing, ctx); + } + return; +} + +/* void cfstore_flash_fsm_write_on_exit(void* ctx){(void) ctx;} */ + +/* @brief fsm handler when entering committing state */ +void cfstore_flash_fsm_commit_on_entry(void* context) +{ + int32_t ret = 0; + cfstore_flash_ctx_t* ctx = (cfstore_flash_ctx_t*) context; + + CFSTORE_FENTRYLOG("%s:entered:\r\n", __func__); + ret = FlashJournal_commit(&ctx->jrnl); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_flash_utest_msg_g, CFSTORE_FLASH_UTEST_MSG_BUF_SIZE, "%s:Error: failed to perform commit operation to flash journal (ret=%d)\r\n", __func__, (int) ret); + TEST_ASSERT_MESSAGE(ret >= (int32_t) JOURNAL_STATUS_OK, cfstore_flash_utest_msg_g); + /* for flash-journal-strategy-sequential version >0.4.0, commit() return no longer reports size of commit block */ + if(ret > 0){ + Harness::validate_callback(); + } + /* wait for async completion handler*/ + return; +} + + +/* @brief fsm handler when in committing state */ +void cfstore_flash_fsm_committing(void* context) +{ + cfstore_flash_ctx_t* ctx = (cfstore_flash_ctx_t*) context; + + CFSTORE_FENTRYLOG("%s:entered\r\n", __func__); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_flash_utest_msg_g, CFSTORE_FLASH_UTEST_MSG_BUF_SIZE, "%s:Error: entered handler(%s) but not in committing state (fsm->state=%d)\r\n", __func__, __func__, (int) ctx->fsm.state); + TEST_ASSERT_MESSAGE(ctx->fsm.state == cfstore_flash_fsm_state_committing, cfstore_flash_utest_msg_g); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_flash_utest_msg_g, CFSTORE_FLASH_UTEST_MSG_BUF_SIZE, "%s:Error: cmd_code code (%d) is not as expected (%d)\r\n", __func__, ctx->cmd_code, FLASH_JOURNAL_OPCODE_COMMIT); + TEST_ASSERT_MESSAGE(ctx->cmd_code == FLASH_JOURNAL_OPCODE_COMMIT, cfstore_flash_utest_msg_g); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_flash_utest_msg_g, CFSTORE_FLASH_UTEST_MSG_BUF_SIZE, "%s:Error: status=%" PRId32 "\r\n", __func__, ctx->status); + TEST_ASSERT_MESSAGE(ctx->status >= JOURNAL_STATUS_OK, cfstore_flash_utest_msg_g); + + /* check the correct amount of data was written */ + /* for flash-journal-strategy-sequential version >0.4.0, commit() return no longer reports size of commit block */ + Harness::validate_callback(); +} + +/* @brief fsm handler when exiting committing state */ +void cfstore_flash_fsm_commit_on_exit(void* context) +{ + cfstore_flash_ctx_t* ctx = (cfstore_flash_ctx_t*) context; + + CFSTORE_FENTRYLOG("%s:entered\r\n", __func__); + /* test done. clean up*/ + if(ctx->area_0_head){ + CFSTORE_FREE(ctx->area_0_head); + ctx->area_0_head = NULL; + } + Harness::validate_callback(); + } + +#define cfstore_flash_fsm_null NULL + +/* handler functions while in state */ +static cfstore_flash_fsm_handler cfstore_flash_fsm[cfstore_flash_fsm_state_max][cfstore_flash_fsm_event_max] = +{ +/* state\event: init_done read_done write_done commit_done */ +/* initialising */ {cfstore_flash_fsm_initializing, cfstore_flash_fsm_null, cfstore_flash_fsm_null, cfstore_flash_fsm_null }, +/* reading */ {cfstore_flash_fsm_null, cfstore_flash_fsm_reading, cfstore_flash_fsm_null, cfstore_flash_fsm_null }, +/* writing */ {cfstore_flash_fsm_null, cfstore_flash_fsm_null, cfstore_flash_fsm_writing, cfstore_flash_fsm_null }, +/* committing */ {cfstore_flash_fsm_null, cfstore_flash_fsm_null, cfstore_flash_fsm_null, cfstore_flash_fsm_committing }, +}; + + +/* handler functions for entering the state*/ +cfstore_flash_fsm_handler cfstore_flash_fsm_on_entry[cfstore_flash_fsm_state_max] = +{ + cfstore_flash_fsm_init_on_entry, + cfstore_flash_fsm_read_on_entry, + cfstore_flash_fsm_write_on_entry, + cfstore_flash_fsm_commit_on_entry, +}; + +/* handler functions for exiting state, currently none used */ +cfstore_flash_fsm_handler cfstore_flash_fsm_on_exit[cfstore_flash_fsm_state_max] = +{ + NULL, NULL, NULL, NULL, +}; + + +/* @brief inject event into fsm */ +static void cfstore_fsm_state_handle_event(cfstore_fsm_t* fsm, cfstore_flash_fsm_event_t event, void* context) +{ + cfstore_flash_ctx_t* ctx = (cfstore_flash_ctx_t*) context; + + CFSTORE_FENTRYLOG("%s:entered: fsm=%p, event=%d (%s), ctx=%p\r\n", __func__, fsm, (int) event, cfstore_flash_event_str[event], ctx); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_flash_utest_msg_g, CFSTORE_FLASH_UTEST_MSG_BUF_SIZE, "%s:Error: invalid event (%d)\r\n", __func__, (int) event); + TEST_ASSERT_MESSAGE(event < cfstore_flash_fsm_event_max, cfstore_flash_utest_msg_g); + fsm->event = event; + if(cfstore_flash_fsm[fsm->state][fsm->event] != NULL){ + cfstore_flash_fsm[fsm->state][fsm->event](ctx); + } + + /* do not clear context data set by caller as it may be used later + * fsm->event = cfstore_flash_fsm_event_max; + * ctx->status = 0; + * ctx->cmd_code = (FlashJournal_OpCode_t)((int) FLASH_JOURNAL_OPCODE_RESET+1); + */ + return; +} + + +/* @brief function to move to new fsm state, calling state exit function for old state and entry function for new state */ +static void cfstore_fsm_state_set(cfstore_fsm_t* fsm, cfstore_flash_fsm_state_t new_state, void* ctx) +{ + CFSTORE_FENTRYLOG("%s:entered: fsm=%p, new_state=%d, ctx=%p\r\n", __func__, fsm, (int) new_state, ctx); + CFSTORE_DBGLOG("%s:FSM:REQ RX:%s:%s\r\n", __func__, cfstore_flash_state_str[fsm->state], cfstore_flash_state_str[new_state]); + TEST_ASSERT_MESSAGE(fsm != NULL, "fsm is not a valid pointer"); + TEST_ASSERT_MESSAGE(new_state < cfstore_flash_fsm_state_max, "new_state is not a valid state"); + TEST_ASSERT_MESSAGE(ctx != NULL, "ctx is not a valid pointer"); + TEST_ASSERT_MESSAGE(fsm->state < cfstore_flash_fsm_state_max, "fsm->state is not a valid state"); + + if(cfstore_flash_fsm_on_exit[fsm->state] != NULL){ + cfstore_flash_fsm_on_exit[fsm->state](ctx); + } + fsm->state = new_state; + if(cfstore_flash_fsm_on_entry[new_state] != NULL){ + cfstore_flash_fsm_on_entry[new_state](ctx); + } + CFSTORE_DBGLOG("%s:FSM:REQ DONE:\r\n", __func__); + return; +} + +/* @brief initialize global context data structure */ +static void cfstore_flash_ctx_init(cfstore_flash_ctx_t* ctx) +{ + TEST_ASSERT_MESSAGE(ctx != NULL, "ctx is NULL"); + + CFSTORE_FENTRYLOG("%s:entered\r\n", __func__); + memset(&cfstore_flash_ctx_g, 0, sizeof(cfstore_flash_ctx_g)); +} + + +/* @brief asynchronous test 01 */ +static control_t cfstore_flash_journal_async_test_01(void) +{ + cfstore_flash_ctx_t* ctx = cfstore_flash_ctx_get(); + + CFSTORE_FENTRYLOG("%s:entered: \r\n", __func__); + cfstore_flash_mtd_async_ops_g = CFSTORE_FLASH_MTD_ASYNC_OPS_ON; + cfstore_flash_ctx_init(ctx); + cfstore_fsm_state_set(&ctx->fsm, cfstore_flash_fsm_state_initializing, ctx); + + /* allow time for work to be done */ + return CaseTimeout(CFSTORE_FLASH_CASE_TIMEOUT_MS); +} + +#endif /* CFSTORE_CONFIG_BACKEND_FLASH_ENABLED */ + + +/* report whether built/configured for flash sync or async mode */ +static control_t cfstore_flash_test_00(const size_t call_count) +{ + (void) call_count; + CFSTORE_LOG("INITIALIZING: caps.asynchronous_ops=%lu\n", cfstore_driver.GetCapabilities().asynchronous_ops); +#ifdef YOTTA_CFG_CFSTORE_BACKEND_SRAM + CFSTORE_LOG("INITIALIZING: BACKEND=SRAM. Skipping flash test%s", "\n"); +#endif + return CaseNext; +} + +/* Specify all your test cases here */ +Case cases[] = { + Case("flash_journal_async_test_00", cfstore_flash_test_00), +#if defined CFSTORE_CONFIG_BACKEND_FLASH_ENABLED && CFSTORE_CONFIG_BACKEND_FLASH_ENABLED == 1 + Case("flash_journal_async_test_01", cfstore_flash_journal_async_test_01), +#endif +}; + + +utest::v1::status_t greentea_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(100, "default_auto"); + return greentea_test_setup_handler(number_of_cases); +} + +/* Declare your test specification with a custom setup handler */ +Specification specification(greentea_setup, cases); + +#if defined CFSTORE_CONFIG_MBED_OS_VERSION && CFSTORE_CONFIG_MBED_OS_VERSION == 3 +/* mbedosV3*/ +void app_start(int argc __unused, char** argv __unused) +{ + /* Run the test specification */ + Harness::run(specification); +} +#endif /* CFSTORE_CONFIG_MBED_OS_VERSION == 3 */ + +#if defined CFSTORE_CONFIG_MBED_OS_VERSION && CFSTORE_CONFIG_MBED_OS_VERSION == 4 +/* mbedosV3++*/ +int main() +{ + return !Harness::run(specification); +} +#endif /* CFSTORE_CONFIG_MBED_OS_VERSION == 4 */ + + +#endif // __MBED__ && ! defined TOOLCHAIN_GCC_ARM diff --git a/TESTS/cfstore/flush/flush.cpp b/TESTS/cfstore/flush/flush.cpp new file mode 100644 index 0000000000..177789c336 --- /dev/null +++ b/TESTS/cfstore/flush/flush.cpp @@ -0,0 +1,638 @@ +/* @file flush.cpp + * + * mbed Microcontroller Library + * Copyright (c) 2006-2016 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Test cases to flush KVs in the CFSTORE using the drv->Flush() interface. + */ +#if defined __MBED__ && ! defined TOOLCHAIN_GCC_ARM + + +#include +#include +#include +#include + +#ifdef TARGET_LIKE_FRDM_K64F_GCC +#include +#endif + +#include "cfstore_config.h" +#include +#include "cfstore_debug.h" +#include "cfstore_test.h" +#include +#include "utest/utest.h" +#include "unity/unity.h" +#include "greentea-client/test_env.h" +#ifdef YOTTA_CFG_CFSTORE_UVISOR +#include "uvisor-lib/uvisor-lib.h" +#include "cfstore_uvisor.h" +#endif /* YOTTA_CFG_CFSTORE_UVISOR */ + +using namespace utest::v1; + +static control_t cfstore_flush_test_00(const size_t call_count) +{ + (void) call_count; + printf("Not implemented for ARM toolchain\n"); + return CaseNext; +} + + +utest::v1::status_t greentea_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(100, "default_auto"); + return greentea_test_setup_handler(number_of_cases); +} + +Case cases[] = { + /* 1 2 3 4 5 6 7 */ + /* 1234567890123456789012345678901234567890123456789012345678901234567890 */ + Case("FLUSH_test_00", cfstore_flush_test_00), +}; + + +/* Declare your test specification with a custom setup handler */ +Specification specification(greentea_setup, cases); + +int main() +{ + return !Harness::run(specification); +} + + +#else + + + +#include +#include +#include +#include + +#ifdef TARGET_LIKE_FRDM_K64F_GCC +#include +#endif + +#include "cfstore_config.h" +#include "cfstore_test.h" +#include "cfstore_debug.h" +//#include +#include +#include +#include "utest/utest.h" +#include "unity/unity.h" +#include "greentea-client/test_env.h" +#ifdef YOTTA_CFG_CFSTORE_UVISOR +#include "uvisor-lib/uvisor-lib.h" +#endif /* YOTTA_CFG_CFSTORE_UVISOR */ + +using namespace utest::v1; + +/* + * Defines + */ +#define CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE 256 +#define cfstore_flush_fsm_null NULL +#define CFSTORE_FLUSH_CASE_TIMEOUT_MS 10000 +#define CFSTORE_FLUSH_FSM_LOOPS 20 + +#ifdef CFSTORE_DEBUG +#define CFSTORE_FLUSH_GREENTEA_TIMEOUT_S 360 +#else +#define CFSTORE_FLUSH_GREENTEA_TIMEOUT_S 60 +#endif + +/* + * Globals + * + * cfstore_flush_utest_msg_g + * buffer for storing TEST_ASSERT_xxx_MESSAGE messages + */ +char cfstore_flush_utest_msg_g[CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE]; + +/* Configure secure box. */ +#ifdef YOTTA_CFG_CFSTORE_UVISOR +UVISOR_BOX_NAMESPACE("com.arm.mbed.cfstore.test.flush.box1"); +UVISOR_BOX_CONFIG(cfstore_flush_box1, UVISOR_BOX_STACK_SIZE); +#endif /* YOTTA_CFG_CFSTORE_UVISOR */ + + + + +#ifdef TARGET_LIKE_X86_LINUX_NATIVE + +/** @brief basic Flush() test + * + * @return status code + * ARM_DRIVER_OK, the test passed successfully + * ret != ARM_DRIVER_OK, the test failed with the return code + * supplying more details + */ +static int32_t cfstore_flush_test_01_x86_sync(void) +{ + int32_t ret = ARM_DRIVER_ERROR; + ARM_CFSTORE_DRIVER* drv = &cfstore_driver; + + CFSTORE_LOG("cfstore_flush_test_01: Start%s", "\r\n"); + ret = drv->Initialize(NULL, NULL); + if(ret != ARM_DRIVER_OK){ + CFSTORE_ERRLOG("%s:Initialize() call failed (ret=%" PRId32 ").\r\n", __func__, ret); + goto out0; + } + ret = drv->Flush(); + if(ret != ARM_DRIVER_OK){ + CFSTORE_ERRLOG("%s:Flush() call failed (ret=%" PRId32 ").\r\n", __func__, ret); + } + ret = drv->Uninitialize(); + if(ret != ARM_DRIVER_OK){ + CFSTORE_ERRLOG("%s:Initialize() call failed to Uninitialise(ret=%" PRId32 ").\r\n", __func__, ret); + goto out0; + } + out0: + if(ret == ARM_DRIVER_OK){ + CFSTORE_LOG("cfstore_flush_test_01: End: Success%s", "\r\n"); + } else { + CFSTORE_LOG("cfstore_flush_test_01: End: Failed%s", "\r\n"); + } + return ret; +} +#endif /* TARGET_LIKE_X86_LINUX_NATIVE */ + +/* KV data for test_03 */ +static cfstore_kv_data_t cfstore_flush_test_02_kv_data[] = { + { "com.arm.mbed.configurationstore.test.flush.cfstoreflushtest02", "1"}, + /* 1 2 3 4 5 6 7 */ + /* 1234567890123456789012345678901234567890123456789012345678901234567890 */ + { NULL, NULL}, +}; + + +/* async test version */ + +/* @brief test fsm states and events */ +typedef enum cfstore_flush_fsm_state_t { + cfstore_flush_fsm_state_stopped = 0, + cfstore_flush_fsm_state_initializing, + cfstore_flush_fsm_state_flushing, + cfstore_flush_fsm_state_uninitializing, + cfstore_flush_fsm_state_max +} cfstore_flush_fsm_state_t; + +/* @brief test fsm events */ +typedef enum cfstore_flush_fsm_event_t { + cfstore_flush_fsm_event_init_done = 0, + cfstore_flush_fsm_event_flush_done, + cfstore_flush_fsm_event_uninit_done, + cfstore_flush_fsm_event_max, +} cfstore_flush_fsm_event_t; + +typedef void (*cfstore_flush_fsm_handler)(void* ctx); + +typedef struct cfstore_fsm_t +{ + cfstore_flush_fsm_state_t state; + cfstore_flush_fsm_event_t event; +} cfstore_fsm_t; + +typedef struct cfstore_flush_ctx_t +{ + int32_t loops_done; + cfstore_fsm_t fsm; + int32_t status; + ARM_CFSTORE_OPCODE cmd_code; +} cfstore_flush_ctx_t; + + +/* + * Globals + */ +static cfstore_flush_ctx_t cfstore_flush_ctx_g; + +#ifdef CFSTORE_DEBUG +static const char* cfstore_flush_state_str[] = +{ + "stopped", + "initializing", + "flushing", + "uninitializing", + "unknown" +}; + +static const char* cfstore_flush_event_str[] = +{ + "init_done", + "flush_done", + "uninit_done", + "unknown" +}; +#endif + +/* + * Forward decl + */ +static void cfstore_flush_fsm_state_handle_event(cfstore_fsm_t* fsm, cfstore_flush_fsm_event_t event, void* context); +static void cfstore_flush_fsm_state_set(cfstore_fsm_t* fsm, cfstore_flush_fsm_state_t new_state, void* ctx); +/* + * context related methods + */ + +/* @brief get a pointer to the global context data structure */ +static cfstore_flush_ctx_t* cfstore_flush_ctx_get(void) +{ + return &cfstore_flush_ctx_g; +} + +/* @brief initialize global context data structure */ +static void cfstore_flush_ctx_init(cfstore_flush_ctx_t* ctx) +{ + TEST_ASSERT_MESSAGE(ctx != NULL, "ctx is NULL"); + + CFSTORE_FENTRYLOG("%s:entered\r\n", __func__); + memset(&cfstore_flush_ctx_g, 0, sizeof(cfstore_flush_ctx_g)); +} + + +/* @brief cfstore asynchronous callback handler */ +void cfstore_flush_test_01_callback(int32_t status, ARM_CFSTORE_OPCODE cmd_code, void *client_context, ARM_CFSTORE_HANDLE handle) +{ + cfstore_flush_ctx_t* ctx = (cfstore_flush_ctx_t*) client_context; + + CFSTORE_FENTRYLOG("%s:entered: status=%d, cmd_code=%d (%s) ctx=%p, handle=%p\r\n", __func__, (int) status, (int) cmd_code, cfstore_test_opcode_str[cmd_code], ctx, handle); + (void) handle; + switch(cmd_code) + { + case CFSTORE_OPCODE_INITIALIZE: + ctx->fsm.event = cfstore_flush_fsm_event_init_done; + break; + case CFSTORE_OPCODE_FLUSH: + ctx->fsm.event = cfstore_flush_fsm_event_flush_done; + break; + case CFSTORE_OPCODE_UNINITIALIZE: + ctx->fsm.event = cfstore_flush_fsm_event_uninit_done; + break; + case CFSTORE_OPCODE_CLOSE: + case CFSTORE_OPCODE_CREATE: + case CFSTORE_OPCODE_DELETE: + case CFSTORE_OPCODE_FIND: + case CFSTORE_OPCODE_GET_KEY_NAME: + case CFSTORE_OPCODE_GET_STATUS: + case CFSTORE_OPCODE_GET_VALUE_LEN: + case CFSTORE_OPCODE_OPEN: + case CFSTORE_OPCODE_POWER_CONTROL: + case CFSTORE_OPCODE_READ: + case CFSTORE_OPCODE_RSEEK: + case CFSTORE_OPCODE_WRITE: + default: + CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE, "%s:WARN: received asynchronous notification for opcode=%d (%s) when api call should have been synchronous", __func__, cmd_code, cmd_code < CFSTORE_OPCODE_MAX ? cfstore_test_opcode_str[cmd_code] : "unknown"); + CFSTORE_DBGLOG("%s:WARN: received asynchronous notification for opcode=%d (%s) when api call should have been synchronous", __func__, cmd_code, cmd_code < CFSTORE_OPCODE_MAX ? cfstore_test_opcode_str[cmd_code] : "unknown"); + /* TEST_ASSERT_MESSAGE(false, cfstore_flush_utest_msg_g) */ + return; + } + ctx->status = status; + ctx->cmd_code = cmd_code; + cfstore_flush_fsm_state_handle_event(&ctx->fsm, ctx->fsm.event, client_context); + return; +} + +/* @brief fsm handler called on entry to stopping state */ +static void cfstore_flush_fsm_stop_on_entry(void* context) +{ + (void) context; + CFSTORE_FENTRYLOG("%s:entered:\r\n", __func__); + Harness::validate_callback(); + return; +} + +/* @brief fsm handler called on entry to initializing state */ +static void cfstore_flush_fsm_init_on_entry(void* context) +{ + int32_t ret = ARM_DRIVER_ERROR; + cfstore_flush_ctx_t* ctx = (cfstore_flush_ctx_t*) context; + const ARM_CFSTORE_DRIVER* drv = &cfstore_driver; + + /* check that the mtd is in synchronous mode */ + CFSTORE_FENTRYLOG("%s:entered: callback=%p, ctx=%p\r\n", __func__, cfstore_flush_test_01_callback, ctx); + ret = drv->Initialize(cfstore_flush_test_01_callback, ctx); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE, "%s:Error: failed to initialize CFSTORE (ret=%" PRId32 ")\r\n", __func__, ret); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush_utest_msg_g); + CFSTORE_DBGLOG("%s:debug: ret=%" PRId32 "\r\n", __func__, ret); + return; +} + +/* brief callback handler when in state initializing */ +static void cfstore_flush_fsm_initializing(void* context) +{ + cfstore_flush_ctx_t* ctx = (cfstore_flush_ctx_t*) context; + + CFSTORE_FENTRYLOG("%s:entered\r\n", __func__); + CFSTORE_FENTRYLOG("%s:entered: status = %d\r\n", __func__, (int) ctx->status); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE, "%s:Error: entered handler(%s) but not in initializing state (fsm->state=%d)\r\n", __func__, __func__, (int) ctx->fsm.state); + TEST_ASSERT_MESSAGE(ctx->fsm.state == cfstore_flush_fsm_state_initializing, cfstore_flush_utest_msg_g); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE, "%s:Error: cmd_code code (%d) is not as expected (%d)\r\n", __func__, ctx->cmd_code, CFSTORE_OPCODE_INITIALIZE); + TEST_ASSERT_MESSAGE(ctx->cmd_code == CFSTORE_OPCODE_INITIALIZE, cfstore_flush_utest_msg_g); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE, "%s:Error: status=%" PRId32 "\r\n", __func__, ctx->status); + TEST_ASSERT_MESSAGE(ctx->status >= ARM_DRIVER_OK, cfstore_flush_utest_msg_g); + /* only change state if status >= 0*/ + if(ctx->status >= 0){ + cfstore_flush_fsm_state_set(&ctx->fsm, cfstore_flush_fsm_state_flushing, ctx); + } + return; +} + +/* static void cfstore_flush_fsm_init_on_exit(void* context){ (void) context;} */ + + +/* @brief fsm handler called on entry to flushing state */ +static void cfstore_flush_fsm_flush_on_entry(void* context) +{ + bool bfound = false; + int32_t ivalue = 0; + int32_t ret = ARM_DRIVER_ERROR; + ARM_CFSTORE_DRIVER* drv = &cfstore_driver; + const char* key_name_query = "*"; + char value[CFSTORE_KEY_NAME_MAX_LENGTH+1]; + ARM_CFSTORE_SIZE len = CFSTORE_KEY_NAME_MAX_LENGTH+1; + ARM_CFSTORE_HANDLE_INIT(next); + ARM_CFSTORE_HANDLE_INIT(prev); + ARM_CFSTORE_KEYDESC kdesc; + cfstore_flush_ctx_t* ctx = (cfstore_flush_ctx_t*) context; + + /* check that the mtd is in synchronous mode */ + CFSTORE_FENTRYLOG("%s:entered: \r\n", __func__); + memset(&kdesc, 0, sizeof(kdesc)); + + CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE, "%s:Error: entered handler(%s) but not in flushing state (fsm->state=%d)\r\n", __func__, __func__, (int) ctx->fsm.state); + TEST_ASSERT_MESSAGE(ctx->fsm.state == cfstore_flush_fsm_state_flushing, cfstore_flush_utest_msg_g); + /* try to read key; should not be found */ + ret = cfstore_test_kv_is_found(cfstore_flush_test_02_kv_data->key_name, &bfound); + if(ret != ARM_DRIVER_OK && ret != ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND){ + CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE, "%s:Error: cfstore_test_kv_is_found() call failed (ret=%" PRId32 ").\r\n", __func__, ret); + TEST_ASSERT_MESSAGE(false, cfstore_flush_utest_msg_g); + } + + if(!bfound) + { + /* first time start up. nothing is stored in cfstore flash. check this is the case */ + while(drv->Find(key_name_query, prev, next) == ARM_DRIVER_OK) + { + CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE, "%s:Error: have found an entry in cfstore when none should be present", __func__); + TEST_ASSERT_MESSAGE(false, cfstore_flush_utest_msg_g); + } + /* no entries found, which is correct. + * store a value */ + len = strlen(cfstore_flush_test_02_kv_data->value); + ret = cfstore_test_create(cfstore_flush_test_02_kv_data->key_name, cfstore_flush_test_02_kv_data->value, &len, &kdesc); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE, "%s:Error:1: failed to write kv data (ret=%" PRId32 ").\r\n", __func__, ret); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush_utest_msg_g); + /* flush to flash */ + ret = drv->Flush(); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE, "%s:Error: failed to flush data to cfstore flash (ret=%" PRId32 ").\r\n", __func__, ret); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush_utest_msg_g); + CFSTORE_LOG("FLUSH: Success pending for new KV creation (name=%s, value=%s)\n", cfstore_flush_test_02_kv_data->key_name, cfstore_flush_test_02_kv_data->value) + } else { + /*read the value, increment by 1 and write value back */ + len = CFSTORE_KEY_NAME_MAX_LENGTH+1; + ret = cfstore_test_read(cfstore_flush_test_02_kv_data->key_name, value, &len); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE, "%s:Error: failed to read kv data (ret=%" PRId32 ").\r\n", __func__, ret); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush_utest_msg_g); + + ivalue = atoi(value); + CFSTORE_LOG("FLUSH: Read KV from flash (name=%s, value=%" PRId32 ")\n", cfstore_flush_test_02_kv_data->key_name, ivalue); + /* increment value */ + ++ivalue; + snprintf(value, CFSTORE_KEY_NAME_MAX_LENGTH+1, "%" PRId32 "", ivalue); + len = strlen(value); + ret = cfstore_test_write(cfstore_flush_test_02_kv_data->key_name, value, &len); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE, "%s:Error: failed to write kv data (ret=%" PRId32 ").\r\n", __func__, ret); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush_utest_msg_g); + + /* flush to flash */ + ret = drv->Flush(); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE, "%s:Error: failed to flush data to cfstore flash (ret=%" PRId32 ").\r\n", __func__, ret); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush_utest_msg_g); + CFSTORE_LOG("FLUSH: Success pending for new KV value to flash (name=%s, value=%" PRId32 ")\n", cfstore_flush_test_02_kv_data->key_name, ivalue); + } + return; +} + + +/* brief callback handler when in state flushing */ +static void cfstore_flush_fsm_flushing(void* context) +{ + cfstore_flush_ctx_t* ctx = (cfstore_flush_ctx_t*) context; + + CFSTORE_FENTRYLOG("%s:entered\r\n", __func__); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE, "%s:Error: entered handler(%s) but not in flushing state (fsm->state=%d)\r\n", __func__, __func__, (int) ctx->fsm.state); + TEST_ASSERT_MESSAGE(ctx->fsm.state == cfstore_flush_fsm_state_flushing, cfstore_flush_utest_msg_g); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE, "%s:Error: cmd_code code (%d) is not as expected (%d)\r\n", __func__, ctx->cmd_code, CFSTORE_OPCODE_FLUSH); + TEST_ASSERT_MESSAGE(ctx->cmd_code == CFSTORE_OPCODE_FLUSH, cfstore_flush_utest_msg_g); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE, "%s:Error: status=%" PRId32 "\r\n", __func__, ctx->status); + TEST_ASSERT_MESSAGE(ctx->status >= ARM_DRIVER_OK, cfstore_flush_utest_msg_g); + /* only change state if status >= 0*/ + if(ctx->status >= 0){ + CFSTORE_LOG("FLUSH: Successfully flushed data to flash.%s", "\n"); + cfstore_flush_fsm_state_set(&ctx->fsm, cfstore_flush_fsm_state_uninitializing, ctx); + } + return; +} + +/* static void cfstore_flush_fsm_flush_on_exit(void* context){ (void) context;} */ + + +/* @brief fsm handler called on entry to uninitializing state */ +static void cfstore_flush_fsm_uninit_on_entry(void* context) +{ + int32_t ret = ARM_DRIVER_ERROR; + cfstore_flush_ctx_t* ctx = (cfstore_flush_ctx_t*) context; + const ARM_CFSTORE_DRIVER* drv = &cfstore_driver; + + /* check that the mtd is in synchronous mode */ + CFSTORE_FENTRYLOG("%s:entered: \r\n", __func__); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE, "%s:Error: entered handler(%s) but not in uninitializing state (fsm->state=%d)\r\n", __func__, __func__, (int) ctx->fsm.state); + TEST_ASSERT_MESSAGE(ctx->fsm.state == cfstore_flush_fsm_state_uninitializing, cfstore_flush_utest_msg_g); + ret = drv->Uninitialize(); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE, "%s:Error: failed to uninitialize CFSTORE (ret=%" PRId32 ")\r\n", __func__, ret); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush_utest_msg_g); + return; +} + +/* brief callback handler when in state uninitializing */ +static void cfstore_flush_fsm_uninitializing(void* context) +{ + cfstore_flush_ctx_t* ctx = (cfstore_flush_ctx_t*) context; + + CFSTORE_FENTRYLOG("%s:entered\r\n", __func__); + CFSTORE_DBGLOG("%s:ctx->status=%" PRId32 ", ctx->loops_done=%" PRId32 "\r\n", __func__, ctx->status, ctx->loops_done); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE, "%s:Error: entered handler(%s) but not in uninitializing state (fsm->state=%d)\r\n", __func__, __func__, (int) ctx->fsm.state); + TEST_ASSERT_MESSAGE(ctx->fsm.state == cfstore_flush_fsm_state_uninitializing, cfstore_flush_utest_msg_g); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE, "%s:Error: cmd_code code (%d) is not as expected (%d)\r\n", __func__, ctx->cmd_code, CFSTORE_OPCODE_UNINITIALIZE); + TEST_ASSERT_MESSAGE(ctx->cmd_code == CFSTORE_OPCODE_UNINITIALIZE, cfstore_flush_utest_msg_g); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE, "%s:Error: status=%" PRId32 "\r\n", __func__, ctx->status); + TEST_ASSERT_MESSAGE(ctx->status >= ARM_DRIVER_OK, cfstore_flush_utest_msg_g); + /* only change state if status >= 0*/ + if(ctx->status >= ARM_DRIVER_OK){ + ++ctx->loops_done; + if(ctx->loops_done < CFSTORE_FLUSH_FSM_LOOPS){ + cfstore_flush_fsm_state_set(&ctx->fsm, cfstore_flush_fsm_state_initializing, ctx); + } else { + /* move to init state */ + cfstore_flush_fsm_state_set(&ctx->fsm, cfstore_flush_fsm_state_stopped, ctx); + } + } + return; +} + +/* static void cfstore_flush_fsm_uninit_on_exit(void* context) {(void)context;} */ + + + +/* handler functions while in state */ +static cfstore_flush_fsm_handler cfstore_flush_fsm[cfstore_flush_fsm_state_max][cfstore_flush_fsm_event_max] = +{ +/* state\event: init_done flush_done unint_done */ +/* stopped */ {cfstore_flush_fsm_null, cfstore_flush_fsm_null, cfstore_flush_fsm_null }, +/* initialising */ {cfstore_flush_fsm_initializing, cfstore_flush_fsm_null, cfstore_flush_fsm_null }, +/* flushing */ {cfstore_flush_fsm_null, cfstore_flush_fsm_flushing, cfstore_flush_fsm_null }, +/* uninitializing */ {cfstore_flush_fsm_null, cfstore_flush_fsm_null, cfstore_flush_fsm_uninitializing } +}; + + +/* handler functions for entering the state*/ +static cfstore_flush_fsm_handler cfstore_flush_fsm_on_entry[cfstore_flush_fsm_state_max] = +{ + cfstore_flush_fsm_stop_on_entry, + cfstore_flush_fsm_init_on_entry, + cfstore_flush_fsm_flush_on_entry, + cfstore_flush_fsm_uninit_on_entry +}; + +/* handler functions for exiting state, currently none used */ +static cfstore_flush_fsm_handler cfstore_flush_fsm_on_exit[cfstore_flush_fsm_state_max] = +{ + cfstore_flush_fsm_null, + cfstore_flush_fsm_null, + cfstore_flush_fsm_null, + cfstore_flush_fsm_null +}; + + +/* @brief inject event into fsm */ +static void cfstore_flush_fsm_state_handle_event(cfstore_fsm_t* fsm, cfstore_flush_fsm_event_t event, void* context) +{ + cfstore_flush_ctx_t* ctx = (cfstore_flush_ctx_t*) context; + + CFSTORE_FENTRYLOG("%s:entered: fsm=%p, state=(%s), event=%d (%s), ctx=%p\r\n", __func__, fsm, cfstore_flush_state_str[fsm->state], (int) event, cfstore_flush_event_str[event], ctx); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE, "%s:Error: invalid event (%d)\r\n", __func__, (int) event); + TEST_ASSERT_MESSAGE(event < cfstore_flush_fsm_event_max, cfstore_flush_utest_msg_g); + fsm->event = event; + if(cfstore_flush_fsm[fsm->state][fsm->event] != NULL){ + cfstore_flush_fsm[fsm->state][fsm->event](ctx); + } + + /* do not clear context data set by caller as it may be used later + * fsm->event = cfstore_flush_fsm_event_max; + * ctx->status = 0; + * ctx->cmd_code = (FlashJournal_OpCode_t)((int) FLASH_JOURNAL_OPCODE_RESET+1); + */ + return; +} + + +/* @brief function to move to new fsm state, calling state exit function for old state and entry function for new state */ +static void cfstore_flush_fsm_state_set(cfstore_fsm_t* fsm, cfstore_flush_fsm_state_t new_state, void* ctx) +{ + #ifdef CFSTORE_DEBUG + cfstore_flush_fsm_state_t old_state = fsm->state; + #endif + + CFSTORE_FENTRYLOG("%s:entered: fsm=%p, ctx=%p\r\n", __func__, fsm, ctx); + #ifdef CFSTORE_DEBUG + CFSTORE_DBGLOG("%s:FSM:REQ RX:%s:%s\r\n", __func__, cfstore_flush_state_str[fsm->state], cfstore_flush_state_str[new_state]); + #endif + TEST_ASSERT_MESSAGE(fsm != NULL, "fsm is not a valid pointer"); + TEST_ASSERT_MESSAGE(new_state < cfstore_flush_fsm_state_max, "new_state is not a valid state"); + TEST_ASSERT_MESSAGE(ctx != NULL, "ctx is not a valid pointer"); + TEST_ASSERT_MESSAGE(fsm->state < cfstore_flush_fsm_state_max, "fsm->state is not a valid state"); + + if(cfstore_flush_fsm_on_exit[fsm->state] != NULL){ + cfstore_flush_fsm_on_exit[fsm->state](ctx); + } + fsm->state = new_state; + if(cfstore_flush_fsm_on_entry[new_state] != NULL){ + cfstore_flush_fsm_on_entry[new_state](ctx); + } + #ifdef CFSTORE_DEBUG + CFSTORE_DBGLOG("%s:FSM:REQ DONE fsm=%p, fsm->state (old_state)=%s, new_state=%s, ctx=%p\r\n", __func__, fsm, cfstore_flush_state_str[old_state], cfstore_flush_state_str[new_state], ctx); + #endif + return; +} + + +/* @brief asynchronous test 01 */ +static control_t cfstore_flush_test_02_k64f(void) +{ + cfstore_flush_ctx_t* ctx = cfstore_flush_ctx_get(); + + CFSTORE_FENTRYLOG("%s:entered: \r\n", __func__); + cfstore_flush_ctx_init(ctx); + cfstore_flush_fsm_state_set(&ctx->fsm, cfstore_flush_fsm_state_initializing, ctx); + return CaseTimeout(CFSTORE_FLUSH_GREENTEA_TIMEOUT_S*1000); +} + +/* report whether built/configured for flash sync or async mode */ +static control_t cfstore_flush_test_00(const size_t call_count) +{ + (void) call_count; + CFSTORE_LOG("INITIALIZING: caps.asynchronous_ops=%lu\n", cfstore_driver.GetCapabilities().asynchronous_ops); + return CaseNext; +} + + +utest::v1::status_t greentea_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(CFSTORE_FLUSH_GREENTEA_TIMEOUT_S, "default_auto"); + return greentea_test_setup_handler(number_of_cases); +} + +Case cases[] = { + Case("FLUSH_test_00", cfstore_flush_test_00), + Case("FLUSH_test_01", cfstore_flush_test_02_k64f), +}; + + +/* Declare your test specification with a custom setup handler */ +Specification specification(greentea_setup, cases); + +#if defined CFSTORE_CONFIG_MBED_OS_VERSION && CFSTORE_CONFIG_MBED_OS_VERSION == 3 +/* mbedosV3*/ +void app_start(int argc __unused, char** argv __unused) +{ + /* Run the test specification */ + Harness::run(specification); +} +#endif /* CFSTORE_CONFIG_MBED_OS_VERSION == 3 */ + +#if defined CFSTORE_CONFIG_MBED_OS_VERSION && CFSTORE_CONFIG_MBED_OS_VERSION == 4 +/* mbedosV3++*/ +int main() +{ + return !Harness::run(specification); +} +#endif /* CFSTORE_CONFIG_MBED_OS_VERSION == 4 */ + + +#endif // __MBED__ && ! defined TOOLCHAIN_GCC_ARM diff --git a/TESTS/cfstore/flush2/flush2.cpp b/TESTS/cfstore/flush2/flush2.cpp new file mode 100644 index 0000000000..ca868d18af --- /dev/null +++ b/TESTS/cfstore/flush2/flush2.cpp @@ -0,0 +1,333 @@ +/* @file flush.cpp + * + * mbed Microcontroller Library + * Copyright (c) 2006-2016 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Test cases to flush KVs in the CFSTORE using the drv->Flush() interface. + */ +#if defined __MBED__ && ! defined TOOLCHAIN_GCC_ARM + + +#include +#include +#include +#include + +#ifdef TARGET_LIKE_FRDM_K64F_GCC +#include +#endif + +#include "cfstore_config.h" +#include +#include "cfstore_debug.h" +#include "cfstore_test.h" +#include +#include "utest/utest.h" +#include "unity/unity.h" +#include "greentea-client/test_env.h" +#ifdef YOTTA_CFG_CFSTORE_UVISOR +#include "uvisor-lib/uvisor-lib.h" +#include "cfstore_uvisor.h" +#endif /* YOTTA_CFG_CFSTORE_UVISOR */ + +using namespace utest::v1; + +static control_t cfstore_flush2_test_00(const size_t call_count) +{ + (void) call_count; + printf("Not implemented for ARM toolchain\n"); + return CaseNext; +} + + +utest::v1::status_t greentea_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(100, "default_auto"); + return greentea_test_setup_handler(number_of_cases); +} + +Case cases[] = { + /* 1 2 3 4 5 6 7 */ + /* 1234567890123456789012345678901234567890123456789012345678901234567890 */ + Case("FLUSH2_test_00", cfstore_flush2_test_00), +}; + + +/* Declare your test specification with a custom setup handler */ +Specification specification(greentea_setup, cases); + +int main() +{ + return !Harness::run(specification); +} + + + +#else + + + +#include +#include +#include +#include + +#ifdef TARGET_LIKE_FRDM_K64F_GCC +#include +#endif + +#include "utest/utest.h" +#include "unity/unity.h" +#include "cfstore_config.h" +#include +#include "greentea-client/test_env.h" +#include "cfstore_test.h" +#include "cfstore_debug.h" +#include "cfstore_utest.h" +#ifdef YOTTA_CFG_CFSTORE_UVISOR +#include "uvisor-lib/uvisor-lib.h" +#endif /* YOTTA_CFG_CFSTORE_UVISOR */ + +using namespace utest::v1; + +/* + * Defines + */ +#define CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE 256 +#define cfstore_flush_fsm_null NULL +#define CFSTORE_FLUSH_CASE_TIMEOUT_MS 10000 + +/* Configure secure box. */ +#ifdef YOTTA_CFG_CFSTORE_UVISOR +UVISOR_BOX_NAMESPACE("com.arm.mbed.cfstore.test.flush2.box1"); +UVISOR_BOX_CONFIG(cfstore_flush2_box1, UVISOR_BOX_STACK_SIZE); +#endif /* YOTTA_CFG_CFSTORE_UVISOR */ + + +/* + * Globals + * + * cfstore_flush_utest_msg_g + * buffer for storing TEST_ASSERT_xxx_MESSAGE messages + */ +static char cfstore_flush_utest_msg_g[CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE]; + +/* KV data for test_03 */ +static cfstore_kv_data_t cfstore_flush_test_02_kv_data[] = { + { "com.arm.mbed.configurationstore.test.flush.cfstoreflushtest02", "1"}, + /* 1 2 3 4 5 6 7 */ + /* 1234567890123456789012345678901234567890123456789012345678901234567890 */ + { NULL, NULL}, +}; + +/* async test version */ + +typedef struct cfstore_flush_ctx_t +{ + int32_t status; + ARM_CFSTORE_OPCODE cmd_code; +} cfstore_flush_ctx_t; + + +/* + * Globals + */ +static cfstore_flush_ctx_t cfstore_flush_ctx_g; + +/* + * context related methods + */ + +/* @brief get a pointer to the global context data structure */ +static cfstore_flush_ctx_t* cfstore_flush_ctx_get(void) +{ + return &cfstore_flush_ctx_g; +} + +/* @brief initialize global context data structure */ +static void cfstore_flush_ctx_init(cfstore_flush_ctx_t* ctx) +{ + TEST_ASSERT_MESSAGE(ctx != NULL, "ctx is NULL"); + + CFSTORE_FENTRYLOG("%s:entered\r\n", __func__); + memset(&cfstore_flush_ctx_g, 0, sizeof(cfstore_flush_ctx_g)); +} + + +/* report whether built/configured for flash sync or async mode */ +static control_t cfstore_flush2_test_00(const size_t call_count) +{ + (void) call_count; + CFSTORE_LOG("INITIALIZING: caps.asynchronous_ops=%lu\n", cfstore_driver.GetCapabilities().asynchronous_ops); + return CaseNext; +} + +control_t cfstore_flush2_test_01_start(const size_t call_count) +{ + int32_t ret = ARM_DRIVER_ERROR; + cfstore_flush_ctx_t* ctx = cfstore_flush_ctx_get(); + const ARM_CFSTORE_DRIVER* drv = &cfstore_driver; + + /* check that the mtd is in synchronous mode */ + CFSTORE_FENTRYLOG("%s:entered:\r\n", __func__); + (void) call_count; + cfstore_flush_ctx_init(ctx); + ret = drv->Initialize(cfstore_utest_default_callback, ctx); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE, "%s:Error: failed to initialize CFSTORE (ret=%" PRId32 ")\r\n", __func__, ret); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush_utest_msg_g); + return CaseTimeout(100000); +} + + +static control_t cfstore_flush2_test_01_mid(const size_t call_count) +{ + + bool bfound = false; + int32_t ivalue = 0; + int32_t ret = ARM_DRIVER_ERROR; + ARM_CFSTORE_DRIVER* drv = &cfstore_driver; + const char* key_name_query = "*"; + char value[CFSTORE_KEY_NAME_MAX_LENGTH+1]; + ARM_CFSTORE_SIZE len = CFSTORE_KEY_NAME_MAX_LENGTH+1; + ARM_CFSTORE_HANDLE_INIT(next); + ARM_CFSTORE_HANDLE_INIT(prev); + ARM_CFSTORE_KEYDESC kdesc; + + /* check that the mtd is in synchronous mode */ + CFSTORE_FENTRYLOG("%s:entered: \r\n", __func__); + (void) call_count; + memset(&kdesc, 0, sizeof(kdesc)); + + /* try to read key; should not be found */ + ret = cfstore_test_kv_is_found(cfstore_flush_test_02_kv_data->key_name, &bfound); + if(ret != ARM_DRIVER_OK && ret != ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND){ + CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE, "%s:Error: cfstore_test_kv_is_found() call failed (ret=%" PRId32 ").\r\n", __func__, ret); + TEST_ASSERT_MESSAGE(false, cfstore_flush_utest_msg_g); + } + + if(!bfound) + { + /* first time start up. nothing is stored in cfstore flash. check this is the case */ + while(drv->Find(key_name_query, prev, next) == ARM_DRIVER_OK) + { + CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE, "%s:Error: have found an entry in cfstore when none should be present", __func__); + TEST_ASSERT_MESSAGE(false, cfstore_flush_utest_msg_g); + } + /* no entries found, which is correct. + * store a value */ + len = strlen(cfstore_flush_test_02_kv_data->value); + ret = cfstore_test_create(cfstore_flush_test_02_kv_data->key_name, cfstore_flush_test_02_kv_data->value, &len, &kdesc); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE, "%s:Error:1: failed to write kv data (ret=%" PRId32 ").\r\n", __func__, ret); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush_utest_msg_g); + /* flush to flash */ + ret = drv->Flush(); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE, "%s:Error: failed to flush data to cfstore flash (ret=%" PRId32 ").\r\n", __func__, ret); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush_utest_msg_g); + + } else { + /*read the value, increment by 1 and write value back */ + len = CFSTORE_KEY_NAME_MAX_LENGTH+1; + ret = cfstore_test_read(cfstore_flush_test_02_kv_data->key_name, value, &len); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE, "%s:Error: failed to read kv data (ret=%" PRId32 ").\r\n", __func__, ret); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush_utest_msg_g); + + /* increment value */ + ivalue = atoi(value); + ++ivalue; + snprintf(value, CFSTORE_KEY_NAME_MAX_LENGTH+1, "%d", (int) ivalue); + len = strlen(value); + ret = cfstore_test_write(cfstore_flush_test_02_kv_data->key_name, value, &len); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE, "%s:Error: failed to write kv data (ret=%" PRId32 ").\r\n", __func__, ret); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush_utest_msg_g); + + /* flush to flash */ + ret = drv->Flush(); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_FLUSH_UTEST_MSG_BUF_SIZE, "%s:Error: failed to flush data to cfstore flash (ret=%" PRId32 ").\r\n", __func__, ret); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_flush_utest_msg_g); + } + return CaseTimeout(100000); +} + +control_t cfstore_flush2_test_01_end(const size_t call_count) +{ + const ARM_CFSTORE_DRIVER* drv = &cfstore_driver; + + CFSTORE_FENTRYLOG("%s:entered:\r\n", __func__); + (void) call_count; + CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Uninitialize() call failed.\n", __func__); + TEST_ASSERT_MESSAGE(drv->Uninitialize() >= ARM_DRIVER_OK, cfstore_flush_utest_msg_g); + return CaseNext; +} + + +/** + * @brief test to open(create) a very large value, write the data, close, then flush. + * for a N keys simultaneously. + * + * @return status code + * ARM_DRIVER_OK, the test passed successfully + * ret < ARM_DRIVER_OK, the test failed with the return code + * supplying more details + */ +static control_t cfstore_flush2_test_02(const size_t call_count) +{ + (void) call_count; + //todo: implement test + CFSTORE_TEST_UTEST_MESSAGE(cfstore_flush_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Warn: Not implemented\n", __func__); + CFSTORE_LOG("%s: WARN: requires implementation\n", __func__); + TEST_ASSERT_MESSAGE(true, cfstore_flush_utest_msg_g); + return CaseNext; +} + + +utest::v1::status_t greentea_setup(const size_t number_of_cases) +{ + // Call the default reporting function- + GREENTEA_SETUP(100, "default_auto"); + return greentea_test_setup_handler(number_of_cases); +} + +Case cases[] = { + Case("CFSTORE_FLUSH2_test_00", cfstore_flush2_test_00), + Case("CFSTORE_FLUSH2_test_01_start", cfstore_flush2_test_01_start), + Case("CFSTORE_FLUSH2_test_01_mid", cfstore_flush2_test_01_mid), + Case("CFSTORE_FLUSH2_test_01_end", cfstore_flush2_test_01_end), + Case("CFSTORE_FLUSH2_test_02_start", cfstore_utest_default_start), + Case("CFSTORE_FLUSH2_test_02_end", cfstore_flush2_test_02), +}; + + +// Declare your test specification with a custom setup handler +Specification specification(greentea_setup, cases); + +#if defined CFSTORE_CONFIG_MBED_OS_VERSION && CFSTORE_CONFIG_MBED_OS_VERSION == 3 +/* mbedosV3*/ +void app_start(int argc __unused, char** argv __unused) +{ + /* Run the test specification */ + Harness::run(specification); +} +#endif /* CFSTORE_CONFIG_MBED_OS_VERSION == 3 */ + +#if defined CFSTORE_CONFIG_MBED_OS_VERSION && CFSTORE_CONFIG_MBED_OS_VERSION == 4 +/* mbedosV3++*/ +int main() +{ + return !Harness::run(specification); +} +#endif /* CFSTORE_CONFIG_MBED_OS_VERSION == 4 */ + + +#endif // __MBED__ && ! defined TOOLCHAIN_GCC_ARM diff --git a/TESTS/cfstore/init/init.cpp b/TESTS/cfstore/init/init.cpp new file mode 100644 index 0000000000..109438a76b --- /dev/null +++ b/TESTS/cfstore/init/init.cpp @@ -0,0 +1,223 @@ +/** @file init.cpp + * + * mbed Microcontroller Library + * Copyright (c) 2006-2016 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Test cases to test initialization/uninitialization code. + */ +#if defined __MBED__ && ! defined TOOLCHAIN_GCC_ARM +#include +#include +#include +#include + +#ifdef TARGET_LIKE_FRDM_K64F_GCC +#include +#endif + +#include "cfstore_config.h" +#include +#include "cfstore_debug.h" +#include "cfstore_test.h" +#include +#include "utest/utest.h" +#include "unity/unity.h" +#include "greentea-client/test_env.h" +#ifdef YOTTA_CFG_CFSTORE_UVISOR +#include "uvisor-lib/uvisor-lib.h" +#include "cfstore_uvisor.h" +#endif /* YOTTA_CFG_CFSTORE_UVISOR */ + +using namespace utest::v1; + +static control_t cfstore_init_test_00(const size_t call_count) +{ + (void) call_count; + printf("Not implemented for ARM toolchain\n"); + return CaseNext; +} + + +utest::v1::status_t greentea_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(100, "default_auto"); + return greentea_test_setup_handler(number_of_cases); +} + +Case cases[] = { + /* 1 2 3 4 5 6 7 */ + /* 1234567890123456789012345678901234567890123456789012345678901234567890 */ + Case("INIT_test_00", cfstore_init_test_00), +}; + + +/* Declare your test specification with a custom setup handler */ +Specification specification(greentea_setup, cases); + +int main() +{ + return !Harness::run(specification); +} + + + +#else + + +#include +#include +#include +#include + +#ifdef TARGET_LIKE_FRDM_K64F_GCC +#include +#endif + +//#include +#include +#include "cfstore_config.h" +#include "cfstore_test.h" +#include "cfstore_debug.h" +#include +#include "utest/utest.h" +#include "unity/unity.h" +#include "greentea-client/test_env.h" +#ifdef YOTTA_CFG_CONFIG_UVISOR +#include "uvisor-lib/uvisor-lib.h" +#endif /* YOTTA_CFG_CONFIG_UVISOR */ + + +using namespace utest::v1; + +static char cfstore_init_utest_msg_g[CFSTORE_UTEST_MSG_BUF_SIZE]; + +typedef struct cfstore_init_ctx_t +{ + ARM_CFSTORE_CAPABILITIES caps; +} cfstore_init_ctx_t; + +static cfstore_init_ctx_t cfstore_init_ctx_g; +extern ARM_CFSTORE_DRIVER cfstore_driver; +ARM_CFSTORE_DRIVER *cfstore_drv = &cfstore_driver; + + +/* report whether built/configured for flash sync or async mode */ +static control_t cfstore_init_test_00(const size_t call_count) +{ + (void) call_count; + CFSTORE_LOG("INITIALIZING: caps.asynchronous_ops=%lu\n", cfstore_driver.GetCapabilities().asynchronous_ops); + return CaseNext; +} + +static void cfstore_init_test_01(cfstore_init_ctx_t* ctx) +{ + int32_t ret; + + (void) ctx; + CFSTORE_LOG("INITIALIZING%s", "\r\n"); + ret = cfstore_drv->Initialize(NULL, NULL); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_init_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Initialize() should return ret >= 0 for async/synch modes(ret=%ld)\r\n", __func__, ret); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_init_utest_msg_g); + + CFSTORE_LOG("FLUSHING1%s", "\r\n"); + ret = cfstore_drv->Flush(); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_init_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Flush() failed (ret=%ld)\r\n", __func__, ret); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_init_utest_msg_g); + + CFSTORE_LOG("UNINITIALIZING%s", "\r\n"); + ret = cfstore_drv->Uninitialize(); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_init_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Uninitialize() should return ret >= 0 for synch mode(ret=%ld)\r\n", __func__, ret); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_init_utest_msg_g); + + CFSTORE_LOG("***************%s", "\r\n"); + CFSTORE_LOG("*** SUCCESS ***%s", "\r\n"); + CFSTORE_LOG("***************%s", "\r\n"); + return; +} + +static control_t cfstore_init_app_start(const size_t call_count) +{ + cfstore_init_ctx_t* ctx = &cfstore_init_ctx_g; + + (void) call_count; + + /* initialise the context */ + memset(ctx, 0, sizeof(cfstore_init_ctx_t)); + ctx->caps = cfstore_drv->GetCapabilities(); + CFSTORE_LOG("%s:INITIALIZING: caps.asynchronous_ops=%lu\n", __func__, ctx->caps.asynchronous_ops); + if(ctx->caps.asynchronous_ops == true){ + /* This is a sync mode only test. If this test is not built for sync mode, then skip testing return true + * This means the test will conveniently pass when run in CI as part of async mode testing */ + CFSTORE_LOG("*** Skipping test as binary built for flash journal async mode, and this test is sync-only%s", "\n"); + return CaseNext; + } + cfstore_init_test_01(ctx); + return CaseNext; +} + +#ifndef YOTTA_CONFIGURATION_STORE_INIT_VERSION_STRING + + +/* when built as Configuration-Store example, include greentea support otherwise omit */ + +utest::v1::status_t greentea_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(100, "default_auto"); + return greentea_test_setup_handler(number_of_cases); +} + +Case cases[] = { + /* 1 2 3 4 5 6 7 */ + /* 1234567890123456789012345678901234567890123456789012345678901234567890 */ + Case("INIT_test_00", cfstore_init_test_00), + Case("INIT_test_01_start", cfstore_init_app_start), +}; + + +/* Declare your test specification with a custom setup handler */ +Specification specification(greentea_setup, cases); + +#if defined CFSTORE_CONFIG_MBED_OS_VERSION && CFSTORE_CONFIG_MBED_OS_VERSION == 3 +/* mbedosV3*/ +void app_start(int argc __unused, char** argv __unused) +{ + /* Run the test specification */ + Harness::run(specification); +} +#endif /* CFSTORE_CONFIG_MBED_OS_VERSION == 3 */ + +#if defined CFSTORE_CONFIG_MBED_OS_VERSION && CFSTORE_CONFIG_MBED_OS_VERSION == 4 +/* mbedosV3++*/ +int main() +{ + return !Harness::run(specification); +} +#endif /* CFSTORE_CONFIG_MBED_OS_VERSION == 4 */ + + +#else // YOTTA_CONFIGURATION_STORE_INIT_VERSION_STRING + + +// stand alone Configuration-Store-Example +void app_start(int argc __unused, char** argv __unused) +{ + cfstore_init_app_start(0); +} + + +#endif // YOTTA_CONFIGURATION_STORE_INIT_VERSION_STRING + + +#endif // __MBED__ && ! defined TOOLCHAIN_GCC_ARM diff --git a/TESTS/cfstore/misc/misc.cpp b/TESTS/cfstore/misc/misc.cpp new file mode 100644 index 0000000000..56443c7d67 --- /dev/null +++ b/TESTS/cfstore/misc/misc.cpp @@ -0,0 +1,460 @@ +/* + * @file misc.cpp + * + * mbed Microcontroller Library + * Copyright (c) 2006-2016 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Test cases for miscellaneious API drv->Xxx() functions. + */ +#if defined __MBED__ && ! defined TOOLCHAIN_GCC_ARM + + +#include +#include +#include +#include + +#ifdef TARGET_LIKE_FRDM_K64F_GCC +#include +#endif + +#include "cfstore_config.h" +#include +#include "cfstore_debug.h" +#include "cfstore_test.h" +#include +#include "utest/utest.h" +#include "unity/unity.h" +#include "greentea-client/test_env.h" +#ifdef YOTTA_CFG_CFSTORE_UVISOR +#include "uvisor-lib/uvisor-lib.h" +#include "cfstore_uvisor.h" +#endif /* YOTTA_CFG_CFSTORE_UVISOR */ + +using namespace utest::v1; + +static control_t cfstore_misc_test_00(const size_t call_count) +{ + (void) call_count; + printf("Not implemented for ARM toolchain\n"); + return CaseNext; +} + + +utest::v1::status_t greentea_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(100, "default_auto"); + return greentea_test_setup_handler(number_of_cases); +} + +Case cases[] = { + /* 1 2 3 4 5 6 7 */ + /* 1234567890123456789012345678901234567890123456789012345678901234567890 */ + Case("MISC_test_00", cfstore_misc_test_00), +}; + + +/* Declare your test specification with a custom setup handler */ +Specification specification(greentea_setup, cases); + +int main() +{ + return !Harness::run(specification); +} + + + +#else + + +#include +#include +#include + +#ifdef TARGET_LIKE_FRDM_K64F_GCC +#include +#endif + +#include "cfstore_config.h" +#include "cfstore_test.h" +#include "cfstore_debug.h" +#include +#include "cfstore_config.h" +#include +#include "utest/utest.h" +#include "unity/unity.h" +#include "greentea-client/test_env.h" +#include "cfstore_utest.h" +#ifdef YOTTA_CFG_CFSTORE_UVISOR +#include "uvisor-lib/uvisor-lib.h" +#include "cfstore_uvisor.h" +#endif /* YOTTA_CFG_CFSTORE_UVISOR */ + +using namespace utest::v1; + +static char cfstore_misc_utest_msg_g[CFSTORE_UTEST_MSG_BUF_SIZE]; + +#ifdef YOTTA_CFG_CFSTORE_UVISOR +/* Create the main box ACL list for the application. + * The main ACL gets inherited by all the other boxes + */ +CFSTORE_UVISOR_MAIN_ACL(cfstore_acl_uvisor_box_misc_g); + +/* Enable uVisor. */ +UVISOR_SET_MODE_ACL(UVISOR_ENABLED, cfstore_acl_uvisor_box_misc_g); +#endif /* YOTTA_CFG_CFSTORE_UVISOR */ + + + +/* report whether built/configured for flash sync or async mode */ +static control_t cfstore_misc_test_00(const size_t call_count) +{ + (void) call_count; + CFSTORE_LOG("INITIALIZING: caps.asynchronous_ops=%lu\n", cfstore_driver.GetCapabilities().asynchronous_ops); + return CaseNext; +} + + +/** @brief basic PowerControl() test + * + * @return status code + * ARM_DRIVER_OK, the test passed successfully + * ret < ARM_DRIVER_OK, the test failed with the return code + * supplying more details + */ +static control_t cfstore_misc_test_00_start(const size_t call_count) +{ + int32_t ret = ARM_DRIVER_ERROR; + ARM_CFSTORE_DRIVER* drv = &cfstore_driver; + ARM_POWER_STATE state = ARM_POWER_OFF; + + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + (void) call_count; + + /* try setting the power control state before initialised, which should fail */ + ret = drv->PowerControl(state); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_misc_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Eror: PowerControl() call should have failed as CFSTORE not initialised, but the call succeeded\r\n", __func__); + TEST_ASSERT_MESSAGE(ret < ARM_DRIVER_OK, cfstore_misc_utest_msg_g); + + ret = drv->Initialize(cfstore_utest_default_callback, NULL); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_misc_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to initialize CFSTORE (ret=%" PRId32 ")\n", __func__, ret); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_misc_utest_msg_g); + return CaseTimeout(CFSTORE_UTEST_DEFAULT_TIMEOUT_MS); +} + +static control_t cfstore_misc_test_00_end(const size_t call_count) +{ + int32_t ret = ARM_DRIVER_ERROR; + ARM_CFSTORE_DRIVER* drv = &cfstore_driver; + ARM_POWER_STATE state = ARM_POWER_OFF; + + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + (void) call_count; + + while(state <= ARM_POWER_FULL) + { + ret = drv->PowerControl(state); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_misc_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: PowerControl() call failed\r\n", __func__); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_misc_utest_msg_g); + state = (ARM_POWER_STATE)((uint32_t) state + 1); + } + /*try invalid value which should fail*/ + ret = drv->PowerControl((ARM_POWER_STATE ) 0xffffffff); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_misc_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:ERror: PowerControl() did not fail with bad value 0xffffffff (not as expected)\r\n", __func__); + TEST_ASSERT_MESSAGE(ret < ARM_DRIVER_OK, cfstore_misc_utest_msg_g); + + ret = drv->Uninitialize(); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_misc_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Uninitialize() call failed.\n", __func__); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_misc_utest_msg_g); + return CaseNext; +} + + +/** @brief basic GetVersion() test + * + * @return status code + * ARM_DRIVER_OK, the test passed successfully + * ret < ARM_DRIVER_OK, the test failed with the return code + * supplying more details + */ +static control_t cfstore_misc_test_01(const size_t call_count) +{ + ARM_CFSTORE_DRIVER* drv = &cfstore_driver; + ARM_DRIVER_VERSION version; + + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + (void) call_count; + memset(&version, 0, sizeof(version)); + + version = drv->GetVersion(); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_misc_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:GetVersion() failed to return correct API version.\r\n", __func__); + TEST_ASSERT_MESSAGE(version.api == ARM_CFSTORE_API_VERSION, cfstore_misc_utest_msg_g); + + CFSTORE_TEST_UTEST_MESSAGE(cfstore_misc_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:GetVersion() to return correct driver version.\r\n", __func__); + TEST_ASSERT_MESSAGE(version.drv == ARM_CFSTORE_DRV_VERSION, cfstore_misc_utest_msg_g); + return CaseNext; +} + + +/** @brief basic GetCapabilities() test + * + * @return status code + * ARM_DRIVER_OK, the test passed successfully + * ret < ARM_DRIVER_OK, the test failed with the return code + * supplying more details + */ +static control_t cfstore_misc_test_02(const size_t call_count) +{ + ARM_CFSTORE_DRIVER* drv = &cfstore_driver; + ARM_CFSTORE_CAPABILITIES caps; + + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + (void) call_count; + memset(&caps, 0, sizeof(caps)); + caps = drv->GetCapabilities(); + //CFSTORE_TEST_UTEST_MESSAGE(cfstore_misc_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Capabilities() failed to return asynchronous_ops == false.\r\n", __func__); + //TEST_ASSERT_MESSAGE(caps.asynchronous_ops == false, cfstore_misc_utest_msg_g); + +#ifdef YOTTA_CFG_CONFIG_HARDWARE_MTD_ASYNC_OPS + /* sync mode */ + printf("%s:sync mode: caps.asynchronous_ops =%" PRIu32 "\n", __func__, caps.asynchronous_ops); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_misc_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: GetCapabilities() reported caps.asynchronous_ops != false but system built for sync operation.\r\n", __func__); + TEST_ASSERT_MESSAGE(caps.asynchronous_ops == false, cfstore_misc_utest_msg_g); +#else + /* async mode */ + printf("%s:async mode: caps.asynchronous_ops =%" PRIu32 "\n", __func__, caps.asynchronous_ops); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_misc_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: GetCapabilities() reported caps.asynchronous_ops != true but system built for async operation.\r\n", __func__); + TEST_ASSERT_MESSAGE(caps.asynchronous_ops == true, cfstore_misc_utest_msg_g); +#endif + + + CFSTORE_TEST_UTEST_MESSAGE(cfstore_misc_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Capabilities() failed to return uvisor_support_enabled == false.\r\n", __func__); + TEST_ASSERT_MESSAGE(caps.uvisor_support_enabled == false, cfstore_misc_utest_msg_g); + return CaseNext; +} + + +/* KV data for test_03 */ +static cfstore_kv_data_t cfstore_misc_test_03_kv_data[] = { + /* 1 2 3 4 5 6 7 */ + /* 1234567890123456789012345678901234567890123456789012345678901234567890 */ + { "The.principles.of.least.action.in.quantum.mechanics", "DoctoralThesis"}, + { "Space.Time.Approach.to.Quantum.Electrodynamic", " PhysicalReview766)"}, + { "An.Operator.Calculus.Having.Applications.in.Quantum.Electrodynamics", "PhysicalReview84)"}, + { NULL, NULL}, +}; + + +/** @brief basic GetKeyName() test + * + * @return status code + * ARM_DRIVER_OK, the test passed successfully + * ret < ARM_DRIVER_OK, the test failed with the return code + * supplying more details + */ +static control_t cfstore_misc_test_03_end(const size_t call_count) +{ + uint8_t key_name_len = 0; + char key_name_buf[CFSTORE_KEY_NAME_MAX_LENGTH+1]; + int32_t ret = ARM_DRIVER_ERROR; + ARM_CFSTORE_DRIVER* drv = &cfstore_driver; + cfstore_kv_data_t* node = NULL; + ARM_CFSTORE_HANDLE_INIT(hkey); + ARM_CFSTORE_FMODE flags; + + CFSTORE_FENTRYLOG("%s:entered\r\n", __func__); + (void) call_count; + memset(key_name_buf, 0, CFSTORE_KEY_NAME_MAX_LENGTH+1); + /* dont set any flags to get default settings */ + memset(&flags, 0, sizeof(flags)); + + ret = cfstore_test_create_table(cfstore_misc_test_03_kv_data); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_misc_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: unable to create keys from table.\r\n", __func__); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_misc_utest_msg_g); + + node = cfstore_misc_test_03_kv_data; + while(node->key_name != NULL) + { + CFSTORE_DBGLOG("%s:About to open KV (key_name=\"%s\", value=\"%s\")\r\n", __func__, node->key_name, node->value); + ret = drv->Open(node->key_name, flags, hkey); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_misc_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Failed to open node (key_name=\"%s\", value=\"%s\")(ret=%" PRId32 ")\r\n", __func__, node->key_name, node->value, ret); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_misc_utest_msg_g); + + key_name_len = CFSTORE_KEY_NAME_MAX_LENGTH+1; + memset(key_name_buf, 0, key_name_len); + drv->GetKeyName(hkey, key_name_buf, &key_name_len); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_misc_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to GetKeyName() (key_name (expected)=\"%s\", key_name (returned)=\"%s\", value=\"%s\"), len return=%d, len expected=%d\r\n", __func__, node->key_name, key_name_buf, node->value, (int) key_name_len, (int) strlen(node->key_name)); + TEST_ASSERT_MESSAGE(key_name_len == strlen(node->key_name)+1, cfstore_misc_utest_msg_g); + + CFSTORE_LOG("GetKeyName() successfully reported key_name (key_name=\"%s\")\r\n", key_name_buf); + ret = drv->Close(hkey); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_misc_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Failed to close key (key_name=\"%s\", value=\"%s\")\r\n", __func__, node->key_name, node->value); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_misc_utest_msg_g); + node++; + } + + cfstore_test_delete_all(); + ret = drv->Uninitialize(); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_misc_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Uninitialize() call failed.\n", __func__); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_misc_utest_msg_g); + return CaseNext; +} + + +/** @brief basic GetValueLen() test + * + * @return status code + * ARM_DRIVER_OK, the test passed successfully + * ret < ARM_DRIVER_OK, the test failed with the return code + * supplying more details + */ +static control_t cfstore_misc_test_04_end(const size_t call_count) +{ + int32_t ret = ARM_DRIVER_ERROR; + ARM_CFSTORE_SIZE len = 0; + ARM_CFSTORE_DRIVER* drv = &cfstore_driver; + cfstore_kv_data_t* node = NULL; + ARM_CFSTORE_HANDLE_INIT(hkey); + ARM_CFSTORE_FMODE flags; + + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + (void) call_count; + /* dont set any flags to get default settings */ + memset(&flags, 0, sizeof(flags)); + + ret = cfstore_test_create_table(cfstore_misc_test_03_kv_data); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_misc_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: unable to create keys from table.\r\n", __func__); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_misc_utest_msg_g); + + node = cfstore_misc_test_03_kv_data; + while(node->key_name != NULL) + { + CFSTORE_DBGLOG("%s:About to open KV (key_name=\"%s\", value=\"%s\")\r\n", __func__, node->key_name, node->value); + ret = drv->Open(node->key_name, flags, hkey); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_misc_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Failed to open node (key_name=\"%s\", value=\"%s\")(ret=%d)\r\n", __func__, node->key_name, node->value, (int) ret); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_misc_utest_msg_g); + + drv->GetValueLen(hkey, &len); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_misc_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Errro: GetValueLen() retrieve incorrect length of value blob(expected=%d, returned=%d)\r\n", __func__, (int) strlen(node->value), (int) len); + TEST_ASSERT_MESSAGE(len == strlen(node->value), cfstore_misc_utest_msg_g); + CFSTORE_LOG("GetValueLen() successfully reported correct value blob length%s", "\r\n"); + + ret = drv->Close(hkey); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_misc_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Failed to close key (key_name=\"%s\", value=\"%s\")\r\n", __func__, node->key_name, node->value); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_misc_utest_msg_g); + node++; + } + cfstore_test_delete_all(); + ret = drv->Uninitialize(); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_misc_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Uninitialize() call failed.\n", __func__); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_misc_utest_msg_g); + return CaseNext; +} + + +/** @brief basic GetStatus() test + * + * @return status code + * ARM_DRIVER_OK, the test passed successfully + * ret < ARM_DRIVER_OK, the test failed with the return code + * supplying more details + */ +static control_t cfstore_misc_test_05_start(const size_t call_count) +{ + int32_t ret = ARM_DRIVER_ERROR; + ARM_CFSTORE_STATUS status; + ARM_CFSTORE_DRIVER* drv = &cfstore_driver; + + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + (void) call_count; + + status = drv->GetStatus(); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_misc_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: GetStatus() before initialisation should have reported error, but reported no error.\r\n", __func__); + TEST_ASSERT_MESSAGE(status.error == true, cfstore_misc_utest_msg_g); + + ret = drv->Initialize(cfstore_utest_default_callback, NULL); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_misc_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to initialize CFSTORE (ret=%" PRId32 ")\n", __func__, ret); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_misc_utest_msg_g); + return CaseTimeout(CFSTORE_UTEST_DEFAULT_TIMEOUT_MS); +} + +static control_t cfstore_misc_test_05_end(const size_t call_count) +{ + int32_t ret = ARM_DRIVER_ERROR; + ARM_CFSTORE_DRIVER* drv = &cfstore_driver; + ARM_CFSTORE_STATUS status; + + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + (void) call_count; + + status = drv->GetStatus(); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_misc_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: GetStatus() but reported error.\r\n", __func__); + TEST_ASSERT_MESSAGE(status.error == false, cfstore_misc_utest_msg_g); + + CFSTORE_TEST_UTEST_MESSAGE(cfstore_misc_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: GetStatus() reported operation in progress.\r\n", __func__); + TEST_ASSERT_MESSAGE(status.in_progress == false, cfstore_misc_utest_msg_g); + + ret = drv->Uninitialize(); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_misc_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Uninitialize() call failed.\n", __func__); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_misc_utest_msg_g); + return CaseNext; +} + + +utest::v1::status_t greentea_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(200, "default_auto"); + return greentea_test_setup_handler(number_of_cases); +} + +Case cases[] = { + /* 1 2 3 4 5 6 7 */ + /* 1234567890123456789012345678901234567890123456789012345678901234567890 */ + Case("MISC_test_00", cfstore_misc_test_00), + Case("MISC_test_00_start", cfstore_misc_test_00_start), + Case("MISC_test_00_end", cfstore_misc_test_00_end), + Case("MISC_test_01", cfstore_misc_test_01), + Case("MISC_test_02", cfstore_misc_test_02), + Case("MISC_test_03_start", cfstore_utest_default_start), + Case("MISC_test_03_end", cfstore_misc_test_03_end), + Case("MISC_test_04_start", cfstore_utest_default_start), + Case("MISC_test_04_end", cfstore_misc_test_04_end), + Case("MISC_test_05_start", cfstore_misc_test_05_start), + Case("MISC_test_05_end", cfstore_misc_test_05_end), +}; + + +/* Declare your test specification with a custom setup handler */ +Specification specification(greentea_setup, cases); + +#if defined CFSTORE_CONFIG_MBED_OS_VERSION && CFSTORE_CONFIG_MBED_OS_VERSION == 3 +/* mbedosV3*/ +void app_start(int argc __unused, char** argv __unused) +{ + /* Run the test specification */ + Harness::run(specification); +} +#endif /* CFSTORE_CONFIG_MBED_OS_VERSION == 3 */ + +#if defined CFSTORE_CONFIG_MBED_OS_VERSION && CFSTORE_CONFIG_MBED_OS_VERSION == 4 +/* mbedosV3++*/ +int main() +{ + return !Harness::run(specification); +} +#endif /* CFSTORE_CONFIG_MBED_OS_VERSION == 4 */ + + +#endif // __MBED__ && ! defined TOOLCHAIN_GCC_ARM diff --git a/TESTS/cfstore/open/open.cpp b/TESTS/cfstore/open/open.cpp new file mode 100644 index 0000000000..653e25ea6f --- /dev/null +++ b/TESTS/cfstore/open/open.cpp @@ -0,0 +1,702 @@ +/* + * @file open.cpp + * + * mbed Microcontroller Library + * Copyright (c) 2006-2016 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Test cases to open KVs in the CFSTORE using the drv->Open() interface. + */ +#if defined __MBED__ && ! defined TOOLCHAIN_GCC_ARM + + +#include +#include +#include +#include + +#ifdef TARGET_LIKE_FRDM_K64F_GCC +#include +#endif + +#include "cfstore_config.h" +#include +#include "cfstore_debug.h" +#include "cfstore_test.h" +#include +#include "utest/utest.h" +#include "unity/unity.h" +#include "greentea-client/test_env.h" +#ifdef YOTTA_CFG_CFSTORE_UVISOR +#include "uvisor-lib/uvisor-lib.h" +#include "cfstore_uvisor.h" +#endif /* YOTTA_CFG_CFSTORE_UVISOR */ + +using namespace utest::v1; + +static control_t cfstore_open_test_00(const size_t call_count) +{ + (void) call_count; + printf("Not implemented for ARM toolchain\n"); + return CaseNext; +} + + +utest::v1::status_t greentea_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(100, "default_auto"); + return greentea_test_setup_handler(number_of_cases); +} + +Case cases[] = { + /* 1 2 3 4 5 6 7 */ + /* 1234567890123456789012345678901234567890123456789012345678901234567890 */ + Case("OPEN_test_00", cfstore_open_test_00), +}; + + +/* Declare your test specification with a custom setup handler */ +Specification specification(greentea_setup, cases); + +int main() +{ + return !Harness::run(specification); +} + + +#else + + +#include +#include +#include /*rand()*/ +#include + +#ifdef TARGET_LIKE_FRDM_K64F_GCC +#include +#endif + +#include "cfstore_config.h" +#include "cfstore_test.h" +#include "cfstore_debug.h" +//#include +#include +#include +#include "utest/utest.h" +#include "unity/unity.h" +#include "greentea-client/test_env.h" +#include "cfstore_utest.h" +#ifdef YOTTA_CFG_CFSTORE_UVISOR +#include "uvisor-lib/uvisor-lib.h" +#endif /* YOTTA_CFG_CFSTORE_UVISOR */ + +using namespace utest::v1; + +static char cfstore_open_utest_msg_g[CFSTORE_UTEST_MSG_BUF_SIZE]; + +/* Configure secure box. */ +#ifdef YOTTA_CFG_CFSTORE_UVISOR +UVISOR_BOX_NAMESPACE("com.arm.mbed.cfstore.test.open.box1"); +UVISOR_BOX_CONFIG(cfstore_open_box1, UVISOR_BOX_STACK_SIZE); +#endif /* YOTTA_CFG_CFSTORE_UVISOR */ + + +#ifdef CFSTORE_DEBUG +#define CFSTORE_OPEN_GREENTEA_TIMEOUT_S 3000 +#else +#define CFSTORE_OPEN_GREENTEA_TIMEOUT_S 1000 +#endif + + +/* support functions */ + +/* + * open tests that focus on testing cfstore_open() + * cfstore_handle_t cfstore_open(const char* key_name, char* data, ARM_CFSTORE_SIZE* len, cfstore_key_desc_t* kdesc) + */ + +/* KV data for test_01 */ +static cfstore_kv_data_t cfstore_open_test_01_kv_data[] = { + { "yotta.hello-world.animal{wobbly-dog}{foot}frontLeft", "missing"}, + { NULL, NULL}, +}; + + +/* report whether built/configured for flash sync or async mode */ +static control_t cfstore_open_test_00(const size_t call_count) +{ + (void) call_count; + CFSTORE_LOG("INITIALIZING: caps.asynchronous_ops=%lu\n", cfstore_driver.GetCapabilities().asynchronous_ops); + return CaseNext; +} + +/** @brief + * Basic open test which does the following: + * - creates KV with default rw perms and writes some data to the value blob. + * - closes the newly created KV. + * - opens the KV with the default permissions (r-only) + * - reads the KV data and checks its the same as the previously created data. + * - closes the opened key + * + * @return status code + * ARM_DRIVER_OK, the test passed successfully + * ret < ARM_DRIVER_OK, the test failed with the return code + * supplying more details + */ +static control_t cfstore_open_test_01_end(const size_t call_count) +{ + char* read_buf; + int32_t ret = ARM_DRIVER_ERROR; + ARM_CFSTORE_SIZE len = 0; + ARM_CFSTORE_DRIVER* drv = &cfstore_driver; + ARM_CFSTORE_KEYDESC kdesc; + ARM_CFSTORE_HANDLE_INIT(hkey); + cfstore_kv_data_t *node; + ARM_CFSTORE_FMODE flags; + + CFSTORE_DBGLOG("%s:entered\n", __func__); + (void) call_count; + node = cfstore_open_test_01_kv_data; + memset(&kdesc, 0, sizeof(kdesc)); + memset(&flags, 0, sizeof(flags)); + + kdesc.drl = ARM_RETENTION_WHILE_DEVICE_ACTIVE; + CFSTORE_DBGLOG("%s:About to create new node (key_name=\"%s\", value=\"%s\")\n", __func__, node->key_name, node->value); + ret = drv->Create(node->key_name, strlen(node->value), &kdesc, hkey); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create node (key_name=\"%s\", value=\"%s\")(ret=%" PRId32 ")\n", __func__, node->key_name, node->value, ret); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_open_utest_msg_g); + + CFSTORE_DBGLOG("%s:length of KV=%d (key_name=\"%s\", value=\"%s\")\n", __func__, (int) len, node->key_name, node->value); + len = strlen(node->value); + ret = drv->Write(hkey, (char*) node->value, &len); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to write key (key_name=\"%s\", value=\"%s\")(ret=%" PRId32 ")\n", __func__, node->key_name, node->value, ret); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_open_utest_msg_g); + + CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to write full value data (key_name=\"%s\", value=\"%s\"), len=%d, (ret=%" PRId32 ")\n", __func__, node->key_name, node->value, (int) len, ret); + TEST_ASSERT_MESSAGE(len == strlen(node->value), cfstore_open_utest_msg_g); + + printf("Created KV successfully (key_name=\"%s\", value=\"%s\")\n", node->key_name, node->value); + ret = drv->Close(hkey); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to close handle (ret=%" PRId32 ")\n", __func__, ret); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_open_utest_msg_g); + + /* now open the newly created key */ + ret = drv->Open(node->key_name, flags, hkey); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to open node (key_name=\"%s\", value=\"%s\")(ret=%" PRId32 ")\n", __func__, node->key_name, node->value, ret); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_open_utest_msg_g); + + len = strlen(node->value) + 1; + read_buf = (char*) malloc(len); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to allocated read buffer \n", __func__); + TEST_ASSERT_MESSAGE(read_buf != NULL, cfstore_open_utest_msg_g); + + printf("Opened KV successfully (key_name=\"%s\", value=\"%s\")\n", node->key_name, node->value); + memset(read_buf, 0, len); + ret = drv->Read(hkey, read_buf, &len); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to write key (key_name=\"%s\", value=\"%s\")\n", __func__, node->key_name, node->value); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_open_utest_msg_g); + + /* check read data is as expected */ + CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: read value data (%s) != KV value data (key_name=\"%s\", value=\"%s\")\n", __func__, read_buf, node->key_name, node->value); + TEST_ASSERT_MESSAGE(strncmp(read_buf, node->value, strlen(node->value)) == 0, cfstore_open_utest_msg_g); + + if(read_buf){ + free(read_buf); + } + CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Close() call failed.\n", __func__); + TEST_ASSERT_MESSAGE(drv->Close(hkey) >= ARM_DRIVER_OK, cfstore_open_utest_msg_g); + + ret = drv->Uninitialize(); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Uninitialize() call failed.\n", __func__); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_open_utest_msg_g); + return CaseNext; +} + +static cfstore_kv_data_t cfstore_open_test_02_data[] = { + CFSTORE_INIT_1_TABLE_MID_NODE, + { NULL, NULL}, +}; + +/** + * @brief test to open() a pre-existing key and try to write it, which should fail + * as by default pre-existing keys are opened read-only + * + * Basic open test which does the following: + * - creates KV with default rw perms and writes some data to the value blob. + * - closes the newly created KV. + * - opens the KV with the default permissions (read-only) + * - tries to write the KV data which should fail because KV was not opened with write flag set. + * - closes the opened key + * + * @return status code + * ARM_DRIVER_OK, the test passed successfully + * ret < ARM_DRIVER_OK, the test failed with the return code + * supplying more details + */ +static control_t cfstore_open_test_02_end(const size_t call_count) +{ + int32_t ret = ARM_DRIVER_ERROR; + ARM_CFSTORE_SIZE len = 0; + ARM_CFSTORE_DRIVER* drv = &cfstore_driver; + ARM_CFSTORE_KEYDESC kdesc; + ARM_CFSTORE_HANDLE_INIT(hkey); + ARM_CFSTORE_FMODE flags; + + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + (void) call_count; + memset(&kdesc, 0, sizeof(kdesc)); + /* dont set any flags to get default settings */ + memset(&flags, 0, sizeof(flags)); + kdesc.drl = ARM_RETENTION_WHILE_DEVICE_ACTIVE; + len = strlen(cfstore_open_test_02_data[0].value); + ret = cfstore_test_create(cfstore_open_test_02_data[0].key_name, (char*) cfstore_open_test_02_data[0].value, &len, &kdesc); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create KV in store (ret=%" PRId32 ").\n", __func__, ret); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_open_utest_msg_g); + + /* by default, owner of key opens with read-only permissions*/ + ret = drv->Open(cfstore_open_test_02_data[0].key_name, flags, hkey); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to open node (key_name=\"%s\")(ret=%" PRId32 ")\n", __func__, cfstore_open_test_02_data[0].key_name, ret); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_open_utest_msg_g); + + len = strlen(cfstore_open_test_02_data[0].value); + ret = drv->Write(hkey, cfstore_open_test_02_data[0].value, &len); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: call to Write() succeeded when should have failed (key_name=\"%s\")(ret=%" PRId32 ").\n", __func__, cfstore_open_test_02_data[0].key_name, ret); + TEST_ASSERT_MESSAGE(ret == ARM_CFSTORE_DRIVER_ERROR_KEY_READ_ONLY, cfstore_open_utest_msg_g); + + CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Close() call failed.\n", __func__); + TEST_ASSERT_MESSAGE(drv->Close(hkey) >= ARM_DRIVER_OK, cfstore_open_utest_msg_g); + + ret = drv->Uninitialize(); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Uninitialize() call failed.\n", __func__); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_open_utest_msg_g); + return CaseNext; +} + + +/** + * @brief test to open() a pre-existing key and try to write it, which should succeed + * because the key was opened read-write permissions explicitly + * + * Basic open test which does the following: + * - creates KV with default rw perms and writes some data to the value blob. + * - closes the newly created KV. + * - opens the KV with the rw permissions (non default) + * - tries to write the KV data which should succeeds because KV was opened with write flag set. + * - closes the opened key + * + * @return status code + * ARM_DRIVER_OK, the test passed successfully + * ret < ARM_DRIVER_OK, the test failed with the return code + * supplying more details + */ +static control_t cfstore_open_test_03_end(const size_t call_count) +{ + int32_t ret = ARM_DRIVER_ERROR; + ARM_CFSTORE_SIZE len = 0; + ARM_CFSTORE_DRIVER* drv = &cfstore_driver; + ARM_CFSTORE_KEYDESC kdesc; + ARM_CFSTORE_HANDLE_INIT(hkey); + ARM_CFSTORE_FMODE flags; + + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + (void) call_count; + memset(&kdesc, 0, sizeof(kdesc)); + /* dont set any flags to get default settings */ + memset(&flags, 0, sizeof(flags)); + kdesc.drl = ARM_RETENTION_WHILE_DEVICE_ACTIVE; + len = strlen(cfstore_open_test_02_data[0].value); + ret = cfstore_test_create(cfstore_open_test_02_data[0].key_name, (char*) cfstore_open_test_02_data[0].value, &len, &kdesc); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create KV in store (ret=%" PRId32 ").\n", __func__, ret); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_open_utest_msg_g); + + /* opens with read-write permissions*/ + flags.read = true; + flags.write = true; + ret = drv->Open(cfstore_open_test_02_data[0].key_name, flags, hkey); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to open node (key_name=\"%s\")(ret=%" PRId32 ")\n", __func__, cfstore_open_test_02_data[0].key_name, ret); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_open_utest_msg_g); + + len = strlen(cfstore_open_test_02_data[0].value); + ret = drv->Write(hkey, cfstore_open_test_02_data[0].value, &len); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: call to Write() failed when should have succeeded (key_name=\"%s\")(ret=%" PRId32 ").\n", __func__, cfstore_open_test_02_data[0].key_name, ret); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_open_utest_msg_g); + + CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Close() call failed.\n", __func__); + TEST_ASSERT_MESSAGE(drv->Close(hkey) >= ARM_DRIVER_OK, cfstore_open_utest_msg_g); + + ret = drv->Uninitialize(); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Uninitialize() call failed.\n", __func__); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_open_utest_msg_g); + return CaseNext; +} + + + +/** @brief test to call cfstore_open() with a key_name string that exceeds + * the maximum length + * + * @return status code + * CFSTORE_ERR_SUCCESS, the test passed successfully + * CFSTORE_ERR_FAILED, the test failed + * + */ +static control_t cfstore_open_test_04_end(const size_t call_count) +{ + char kv_name_good[CFSTORE_KEY_NAME_MAX_LENGTH+1]; /* extra char for terminating null */ + char kv_name_bad[CFSTORE_KEY_NAME_MAX_LENGTH+2]; + int32_t ret = ARM_DRIVER_ERROR; + ARM_CFSTORE_SIZE len = 0; + ARM_CFSTORE_DRIVER* drv = &cfstore_driver; + ARM_CFSTORE_KEYDESC kdesc; + ARM_CFSTORE_FMODE flags; + + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + (void) call_count; + memset(kv_name_good, 0, CFSTORE_KEY_NAME_MAX_LENGTH+1); + memset(kv_name_bad, 0, CFSTORE_KEY_NAME_MAX_LENGTH+2); + memset(&kdesc, 0, sizeof(kdesc)); + /* dont set any flags to get default settings */ + memset(&flags, 0, sizeof(flags)); + + len = CFSTORE_KEY_NAME_MAX_LENGTH; + ret = cfstore_test_kv_name_gen(kv_name_good, len); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: unable to generate kv_name_good.\n", __func__); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK , cfstore_open_utest_msg_g); + + CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: kv_name_good is not the correct length (len=%d, expected=%d).\n", __func__, (int) strlen(kv_name_good), (int) len); + TEST_ASSERT_MESSAGE(strlen(kv_name_good) == CFSTORE_KEY_NAME_MAX_LENGTH, cfstore_open_utest_msg_g); + + ret = cfstore_test_create(kv_name_good, kv_name_good, &len, &kdesc); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create KV in store for kv_name_good(ret=%" PRId32 ").\n", __func__, ret); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_open_utest_msg_g); + + len = CFSTORE_KEY_NAME_MAX_LENGTH+1; + ret = cfstore_test_kv_name_gen(kv_name_bad, len); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: unable to generate kv_name_bad.\n", __func__); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK , cfstore_open_utest_msg_g); + + CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: kv_name_bad is not the correct length (len=%d, expected=%d).\n", __func__, (int) strlen(kv_name_bad), (int) len); + TEST_ASSERT_MESSAGE(strlen(kv_name_bad) == CFSTORE_KEY_NAME_MAX_LENGTH+1, cfstore_open_utest_msg_g); + + memset(&kdesc, 0, sizeof(kdesc)); + ret = cfstore_test_create(kv_name_bad, kv_name_bad, &len, &kdesc); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: created KV in store for kv_name_bad when should have failed(ret=%" PRId32 ").\n", __func__, ret); + TEST_ASSERT_MESSAGE(ret < ARM_DRIVER_OK, cfstore_open_utest_msg_g); + + ret = drv->Uninitialize(); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Uninitialize() call failed.\n", __func__); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_open_utest_msg_g); + return CaseNext; +} + + +typedef struct cfstore_open_kv_name_ascii_node { + uint32_t code; + uint32_t f_allowed : 1; +} cfstore_open_kv_name_ascii_node; + +static const uint32_t cfstore_open_kv_name_ascii_table_code_sentinel_g = 256; + +/*@brief table recording ascii character codes permitted in kv names */ +static cfstore_open_kv_name_ascii_node cfstore_open_kv_name_ascii_table[] = +{ + {0, false}, /* codes 0-44 not allowed */ + {45, true}, /* codes 45-46 == [-.] allowed */ + {47, false}, /* code 47 not allowed */ + {48, true}, /* codes 48-57 not allowed */ + {58, false}, /* codes 46-64 not allowed */ + {64, true}, /* codes 64-91 allowed [@A-Z] */ + {91, false}, /* code 91-96 not allowed */ + {95, true}, /* code 95 allowed '_' */ + {96, false}, /* codes 96 not allowed */ + {97, true}, /* codes 65-90 allowed [A-Z] and {*/ + {123, false}, /* codes 123 '}' not allowed on its own*/ + {124, false}, /* codes 124 not allowed */ + {125, false}, /* code 125 '}' not allowed on its own*/ + {126, false}, /* codes 126-255 not allowed */ + {cfstore_open_kv_name_ascii_table_code_sentinel_g, false}, /* sentinel */ +}; + +enum cfstore_open_kv_name_pos { + cfstore_open_kv_name_pos_start = 0x0, + cfstore_open_kv_name_pos_mid, + cfstore_open_kv_name_pos_end, + cfstore_open_kv_name_pos_max +}; + +/** @brief test to call cfstore_open() with key_name that in includes + * illegal characters + * - the character(s) can be at the beginning of the key_name + * - the character(s) can be at the end of the key_name + * - the character(s) can be somewhere within the key_name string + * - a max-length string of random characters (legal and illegal) + * - a max-length string of random illegal characters only + * + * @return status code + * ARM_DRIVER_OK, the test passed successfully + * ret < ARM_DRIVER_OK, the test failed with the return code + * supplying more details + */ +static control_t cfstore_open_test_05_end(const size_t call_count) +{ + bool f_allowed = false; + const char* pos_str = NULL; + char kv_name[CFSTORE_KEY_NAME_MAX_LENGTH+1]; /* extra char for terminating null */ + uint32_t j = 0; + int32_t ret = ARM_DRIVER_OK; + size_t name_len = CFSTORE_KEY_NAME_MAX_LENGTH; + ARM_CFSTORE_KEYDESC kdesc; + cfstore_open_kv_name_ascii_node* node = NULL; + uint32_t pos; + ARM_CFSTORE_DRIVER* drv = &cfstore_driver; + + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + (void) call_count; + + /* create bad keyname strings with invalid character code at start of keyname */ + node = cfstore_open_kv_name_ascii_table; + while(node->code != cfstore_open_kv_name_ascii_table_code_sentinel_g) + { + /* loop over range */ + for(j = node->code; j < (node+1)->code; j++) + { + /* set the start, mid, last character of the name to the test char code */ + for(pos = (uint32_t) cfstore_open_kv_name_pos_start; pos < (uint32_t) cfstore_open_kv_name_pos_max; pos++) + { + name_len = CFSTORE_KEY_NAME_MAX_LENGTH; + memset(kv_name, 0, CFSTORE_KEY_NAME_MAX_LENGTH+1); + memset(&kdesc, 0, sizeof(kdesc)); + kdesc.drl = ARM_RETENTION_WHILE_DEVICE_ACTIVE; + + ret = cfstore_test_kv_name_gen(kv_name, name_len); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: unable to generate kv_name.\n", __func__); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK , cfstore_open_utest_msg_g); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: kv_name incorrect length (len=%d, expected= %d).\n", __func__, (int) strlen(kv_name), (int) name_len); + TEST_ASSERT_MESSAGE(strlen(kv_name) == name_len, cfstore_open_utest_msg_g); + + /* overwrite a char at the pos start, mid, end of the kv_name with an ascii char code (both illegal and legal)*/ + switch(pos) + { + case cfstore_open_kv_name_pos_start: + kv_name[0] = (char) j; + pos_str = "start"; + break; + case cfstore_open_kv_name_pos_mid: + /* create bad keyname strings with invalid character code in the middle of keyname */ + kv_name[name_len/2] = (char) j; + pos_str = "middle"; + break; + case cfstore_open_kv_name_pos_end: + /* create bad keyname strings with invalid character code at end of keyname */ + kv_name[name_len-1] = (char) j; + pos_str = "end"; + break; + default: + CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: unexpected value of pos (pos=%d).\n", __func__, (int) pos); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_open_utest_msg_g); + break; + } + ret = cfstore_test_create(kv_name, kv_name, &name_len, &kdesc); + + /* special cases */ + switch(j) + { + case 0 : + case 46 : + switch(pos) + { + /* for code = 0 (null terminator). permitted at mid and end of string */ + /* for code = 46 ('.'). permitted at mid and end of string but not at start */ + case cfstore_open_kv_name_pos_start: + f_allowed = false; + break; + case cfstore_open_kv_name_pos_mid: + case cfstore_open_kv_name_pos_end: + default: + f_allowed = true; + break; + } + break; + default: + f_allowed = node->f_allowed; + break; + } + if(f_allowed == true) + { + CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create KV in store when kv_name contains valid characters (code=%" PRId32 ", ret=%" PRId32 ").\n", __func__, j, ret); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_open_utest_msg_g); + CFSTORE_LOG("Successfully created a KV with valid keyname containing ascii character code %" PRIu32 " (%c) at the %s of the keyname.\n", j, (int) j, pos_str); + + ret = cfstore_test_delete(kv_name); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to delete KV previously created (code=%" PRId32 ", ret=%" PRId32 ").\n", __func__, j, ret); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_open_utest_msg_g); + } + else + { /*node->f_allowed == false => not allowed to create kv name with ascii code */ + CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: created KV in store when kv_name contains an invalid character (code=%" PRId32 ", ret=%" PRId32 ").\n", __func__, j, ret); + TEST_ASSERT_MESSAGE(ret < ARM_DRIVER_OK, cfstore_open_utest_msg_g); + CFSTORE_LOG("Successfully failed to create a KV with an invalid keyname containing ascii character code %" PRId32 " at the %s of the keyname.\n", j, pos_str); + } + } + } + node++; + } + + CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Uninitialize() call failed.\n", __func__); + TEST_ASSERT_MESSAGE(drv->Uninitialize() >= ARM_DRIVER_OK, cfstore_open_utest_msg_g); + return CaseNext; +} + + +static const char cfstore_open_ascii_illegal_buf_g[] = "!\"�$%&'()*+,./:;<=>?@[\\]^_`{|}~"; /* 31 chars */ + +/** @brief test to call cfstore_open() with key_name that in includes + * illegal characters + * - a max-length string of random illegal characters only + * + * @return status code + * ARM_DRIVER_OK, the test passed successfully + * ret < ARM_DRIVER_OK, the test failed with the return code + * supplying more details + */ +static control_t cfstore_open_test_06_end(const size_t call_count) +{ + char kv_name[CFSTORE_KEY_NAME_MAX_LENGTH+1]; /* extra char for terminating null */ + size_t i = 0; + uint32_t pos = 0; + int32_t ret = ARM_DRIVER_OK; + size_t name_len = CFSTORE_KEY_NAME_MAX_LENGTH; + ARM_CFSTORE_KEYDESC kdesc; + size_t buf_data_max = 0; + ARM_CFSTORE_DRIVER* drv = &cfstore_driver; + + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + (void) call_count; + + /* create bad keyname strings with invalid character code at start of keyname */ + buf_data_max = strlen(cfstore_open_ascii_illegal_buf_g); + name_len = CFSTORE_KEY_NAME_MAX_LENGTH; + memset(kv_name, 0, CFSTORE_KEY_NAME_MAX_LENGTH+1); + kdesc.drl = ARM_RETENTION_WHILE_DEVICE_ACTIVE; + + /* generate a kv name of illegal chars*/ + for(i = 0; i < name_len; i++) + { + pos = rand() % (buf_data_max+1); + kv_name[i] = cfstore_open_ascii_illegal_buf_g[pos]; + } + + ret = cfstore_test_create(kv_name, kv_name, &name_len, &kdesc); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: created KV in store when kv_name contains invalid characters (ret=%" PRId32 ").\n", __func__, ret); + TEST_ASSERT_MESSAGE(ret < ARM_DRIVER_OK, cfstore_open_utest_msg_g); + + CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Uninitialize() call failed.\n", __func__); + TEST_ASSERT_MESSAGE(drv->Uninitialize() >= ARM_DRIVER_OK, cfstore_open_utest_msg_g); + return CaseNext; +} + +/** @brief test to call cfstore_open() with key_name that in includes + * illegal characters + * - a max-length string of random characters (legal and illegal) + * + * @return status code + * ARM_DRIVER_OK, the test passed successfully + * ret < ARM_DRIVER_OK, the test failed with the return code + * supplying more details + */ +static control_t cfstore_open_test_07_end(const size_t call_count) +{ + char kv_name[CFSTORE_KEY_NAME_MAX_LENGTH+1]; /* extra char for terminating null */ + size_t i = 0; + int32_t ret = ARM_DRIVER_OK; + size_t name_len = CFSTORE_KEY_NAME_MAX_LENGTH; + ARM_CFSTORE_KEYDESC kdesc; + size_t buf_data_max = 0; + ARM_CFSTORE_DRIVER* drv = &cfstore_driver; + + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + (void) call_count; + + /* create bad keyname strings with invalid character code at start of keyname */ + buf_data_max = strlen(cfstore_open_ascii_illegal_buf_g); + name_len = CFSTORE_KEY_NAME_MAX_LENGTH; + memset(kv_name, 0, CFSTORE_KEY_NAME_MAX_LENGTH+1); + kdesc.drl = ARM_RETENTION_WHILE_DEVICE_ACTIVE; + + ret = cfstore_test_kv_name_gen(kv_name, name_len); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: unable to generate kv_name.\n", __func__); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK , cfstore_open_utest_msg_g); + + /* pepper the illegal chars across the string*/ + for(i++; i < buf_data_max; i++){ + kv_name[rand() % (name_len+1)] = cfstore_open_ascii_illegal_buf_g[i]; + } + ret = cfstore_test_create(kv_name, kv_name, &name_len, &kdesc); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: created KV in store when kv_name contains invalid characters (ret=%" PRId32 ").\n", __func__, ret); + TEST_ASSERT_MESSAGE(ret < ARM_DRIVER_OK, cfstore_open_utest_msg_g); + + CFSTORE_TEST_UTEST_MESSAGE(cfstore_open_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Uninitialize() call failed.\n", __func__); + TEST_ASSERT_MESSAGE(drv->Uninitialize() >= ARM_DRIVER_OK, cfstore_open_utest_msg_g); + return CaseNext; +} + +utest::v1::status_t greentea_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(CFSTORE_OPEN_GREENTEA_TIMEOUT_S, "default_auto"); + return greentea_test_setup_handler(number_of_cases); +} + +Case cases[] = { + /* 1 2 3 4 5 6 7 */ + /* 1234567890123456789012345678901234567890123456789012345678901234567890 */ + Case("OPEN_test_00", cfstore_open_test_00), + Case("OPEN_test_01_start", cfstore_utest_default_start), + Case("OPEN_test_01_end", cfstore_open_test_01_end), + Case("OPEN_test_02_start", cfstore_utest_default_start), + Case("OPEN_test_02_end", cfstore_open_test_02_end), + Case("OPEN_test_03_start", cfstore_utest_default_start), + Case("OPEN_test_03_end", cfstore_open_test_03_end), + Case("OPEN_test_04_start", cfstore_utest_default_start), + Case("OPEN_test_04_end", cfstore_open_test_04_end), + Case("OPEN_test_05_start", cfstore_utest_default_start), + Case("OPEN_test_05_end", cfstore_open_test_05_end), + Case("OPEN_test_06_start", cfstore_utest_default_start), + Case("OPEN_test_06_end", cfstore_open_test_06_end), + Case("OPEN_test_07_start", cfstore_utest_default_start), + Case("OPEN_test_07_end", cfstore_open_test_07_end), +}; + + +/* Declare your test specification with a custom setup handler */ +Specification specification(greentea_setup, cases); + +#if defined CFSTORE_CONFIG_MBED_OS_VERSION && CFSTORE_CONFIG_MBED_OS_VERSION == 3 +/* mbedosV3*/ +void app_start(int argc __unused, char** argv __unused) +{ + /* Run the test specification */ + Harness::run(specification); +} +#endif /* CFSTORE_CONFIG_MBED_OS_VERSION == 3 */ + +#if defined CFSTORE_CONFIG_MBED_OS_VERSION && CFSTORE_CONFIG_MBED_OS_VERSION == 4 +/* mbedosV3++*/ +int main() +{ + return !Harness::run(specification); +} +#endif /* CFSTORE_CONFIG_MBED_OS_VERSION == 4 */ + + +#endif // __MBED__ && ! defined TOOLCHAIN_GCC_ARM diff --git a/TESTS/cfstore/read/read.cpp b/TESTS/cfstore/read/read.cpp new file mode 100644 index 0000000000..ff3b4c59a2 --- /dev/null +++ b/TESTS/cfstore/read/read.cpp @@ -0,0 +1,265 @@ +/** @file read.cpp + * + * mbed Microcontroller Library + * Copyright (c) 2006-2016 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Test cases to read KVs in the CFSTORE using the drv->Read() API call. + */ +#if defined __MBED__ && ! defined TOOLCHAIN_GCC_ARM + + +#include +#include +#include +#include + +#ifdef TARGET_LIKE_FRDM_K64F_GCC +#include +#endif + +#include "cfstore_config.h" +#include +#include "cfstore_debug.h" +#include "cfstore_test.h" +#include +#include "utest/utest.h" +#include "unity/unity.h" +#include "greentea-client/test_env.h" +#ifdef YOTTA_CFG_CFSTORE_UVISOR +#include "uvisor-lib/uvisor-lib.h" +#include "cfstore_uvisor.h" +#endif /* YOTTA_CFG_CFSTORE_UVISOR */ + +using namespace utest::v1; + +static control_t cfstore_read_test_00(const size_t call_count) +{ + (void) call_count; + printf("Not implemented for ARM toolchain\n"); + return CaseNext; +} + + +utest::v1::status_t greentea_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(100, "default_auto"); + return greentea_test_setup_handler(number_of_cases); +} + +Case cases[] = { + /* 1 2 3 4 5 6 7 */ + /* 1234567890123456789012345678901234567890123456789012345678901234567890 */ + Case("READ_test_00", cfstore_read_test_00), +}; + + +/* Declare your test specification with a custom setup handler */ +Specification specification(greentea_setup, cases); + +int main() +{ + return !Harness::run(specification); +} + + + +#else + + +#include +#include +#include + +#ifdef TARGET_LIKE_FRDM_K64F_GCC +#include +#endif + +#include "cfstore_config.h" +#include "cfstore_test.h" +#include "cfstore_debug.h" +//#include +#include +#include +#include "utest/utest.h" +#include "unity/unity.h" +#include "greentea-client/test_env.h" +#include "cfstore_utest.h" +#ifdef YOTTA_CFG_CFSTORE_UVISOR +#include "uvisor-lib/uvisor-lib.h" +#endif /* YOTTA_CFG_CFSTORE_UVISOR */ + +using namespace utest::v1; + +static char cfstore_read_utest_msg_g[CFSTORE_UTEST_MSG_BUF_SIZE]; + +/* Configure secure box. */ +#ifdef YOTTA_CFG_CFSTORE_UVISOR +UVISOR_BOX_NAMESPACE("com.arm.mbed.cfstore.test.read.box1"); +UVISOR_BOX_CONFIG(cfstore_read_box1, UVISOR_BOX_STACK_SIZE); +#endif /* YOTTA_CFG_CFSTORE_UVISOR */ + + +/* KV data for test_01 */ +static cfstore_kv_data_t cfstore_read_test_01_kv_data[] = { + CFSTORE_INIT_1_TABLE_MID_NODE, + { NULL, NULL}, +}; + +/* report whether built/configured for flash sync or async mode */ +static control_t cfstore_read_test_00(const size_t call_count) +{ + (void) call_count; + CFSTORE_LOG("INITIALIZING: caps.asynchronous_ops=%lu\n", cfstore_driver.GetCapabilities().asynchronous_ops); + return CaseNext; +} + + +/* @brief check char at offset is as expected */ +static int32_t cfstore_read_seek_test(ARM_CFSTORE_HANDLE hkey, uint32_t offset, const char expected) +{ + ARM_CFSTORE_SIZE len = 1; + char read_buf[1]; + int32_t ret = ARM_DRIVER_ERROR; + ARM_CFSTORE_DRIVER* drv = &cfstore_driver; + + ret = drv->Rseek(hkey, offset); + if(ret < ARM_DRIVER_OK){ + CFSTORE_ERRLOG("%s:failed to Rseek() to desired offset (offset=%d) (ret=%" PRId32 ").\n", __func__, (int) offset, ret); + goto out0; + } + ret = drv->Read(hkey, read_buf, &len); + if(ret < ARM_DRIVER_OK){ + CFSTORE_ERRLOG("%s:failed to Read() (offset=%d)(ret=%" PRId32 ").\n", __func__, (int) offset, ret); + goto out0; + } + if(read_buf[0] != expected){ + ret = ARM_DRIVER_ERROR; + goto out0; + } +out0: + return ret; +} + +/** @brief + * + * + * @return status code + * ARM_DRIVER_OK, the test passed successfully + * ret < ARM_DRIVER_OK, the test failed with the return code + * supplying more details + */ +static control_t cfstore_read_test_01_end(const size_t call_count) +{ + int32_t ret = ARM_DRIVER_ERROR; + ARM_CFSTORE_SIZE len = 0; + ARM_CFSTORE_DRIVER* drv = &cfstore_driver; + ARM_CFSTORE_KEYDESC kdesc; + ARM_CFSTORE_HANDLE_INIT(hkey); + cfstore_test_rw_data_entry_t *node; + ARM_CFSTORE_FMODE flags; + + CFSTORE_DBGLOG("%s:entered\n", __func__); + (void) call_count; + memset(&kdesc, 0, sizeof(kdesc)); + memset(&flags, 0, sizeof(flags)); + + /* create a key for reading */ + kdesc.drl = ARM_RETENTION_WHILE_DEVICE_ACTIVE; + len = strlen(cfstore_read_test_01_kv_data[0].value); + ret = cfstore_test_create(cfstore_read_test_01_kv_data[0].key_name, (char*) cfstore_read_test_01_kv_data[0].value, &len, &kdesc); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_read_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create KV in store (ret=%" PRId32 ").\n", __func__, ret); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_read_utest_msg_g); + + /* now open the newly created key */ + ret = drv->Open(cfstore_read_test_01_kv_data[0].key_name, flags, hkey); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_read_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to open node (key_name=\"%s\", value=\"%s\")(ret=%" PRId32 ")\n", __func__, cfstore_read_test_01_kv_data[0].key_name, cfstore_read_test_01_kv_data[0].value, ret); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_read_utest_msg_g); + + /* seek back and forth in key and check the characters are as expected */ + node = cfstore_test_rw_data_table; + while(node->offset != CFSTORE_TEST_RW_TABLE_SENTINEL) + { + ret = cfstore_read_seek_test(hkey, node->offset, node->rw_char); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_read_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Rseek() to offset (%d) didn't read expected char (\'%c\') (ret=%" PRId32 ")\n", __func__, (int) node->offset, node->rw_char, ret); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_read_utest_msg_g); + node++; + } + CFSTORE_TEST_UTEST_MESSAGE(cfstore_read_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Close() call failed.\n", __func__); + TEST_ASSERT_MESSAGE(drv->Close(hkey) >= ARM_DRIVER_OK, cfstore_read_utest_msg_g); + + ret = drv->Uninitialize(); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_read_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Uninitialize() call failed.\n", __func__); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_read_utest_msg_g); + return CaseNext; +} + + +/** @brief + * + * @return status code + * ARM_DRIVER_OK, the test passed successfully + * ret < ARM_DRIVER_OK, the test failed with the return code + * supplying more details + */ +static control_t cfstore_read_test_02_end(const size_t call_count) +{ + (void) call_count; + /*todo: implement test */ + CFSTORE_TEST_UTEST_MESSAGE(cfstore_read_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Warn: Not implemented\n", __func__); + CFSTORE_LOG("%s: WARN: requires implementation\n", __func__); + TEST_ASSERT_MESSAGE(true, cfstore_read_utest_msg_g); + return CaseNext; +} + + +utest::v1::status_t greentea_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(200, "default_auto"); + return greentea_test_setup_handler(number_of_cases); +} + +Case cases[] = { + /* 1 2 3 4 5 6 7 */ + /* 1234567890123456789012345678901234567890123456789012345678901234567890 */ + Case("READ_test_00", cfstore_read_test_00), + Case("READ_test_01_start", cfstore_utest_default_start), + Case("READ_test_01_end", cfstore_read_test_01_end), + Case("READ_test_02_start", cfstore_utest_default_start), + Case("READ_test_02_end", cfstore_read_test_02_end), +}; + + +/* Declare your test specification with a custom setup handler */ +Specification specification(greentea_setup, cases); + +#if defined CFSTORE_CONFIG_MBED_OS_VERSION && CFSTORE_CONFIG_MBED_OS_VERSION == 3 +/* mbedosV3*/ +void app_start(int argc __unused, char** argv __unused) +{ + /* Run the test specification */ + Harness::run(specification); +} +#endif /* CFSTORE_CONFIG_MBED_OS_VERSION == 3 */ + +#if defined CFSTORE_CONFIG_MBED_OS_VERSION && CFSTORE_CONFIG_MBED_OS_VERSION == 4 +/* mbedosV3++*/ +int main() +{ + return !Harness::run(specification); +} +#endif /* CFSTORE_CONFIG_MBED_OS_VERSION == 4 */ + + +#endif // __MBED__ && ! defined TOOLCHAIN_GCC_ARM diff --git a/TESTS/cfstore/write/write.cpp b/TESTS/cfstore/write/write.cpp new file mode 100644 index 0000000000..667d24385c --- /dev/null +++ b/TESTS/cfstore/write/write.cpp @@ -0,0 +1,272 @@ +/** @file write.cpp + * + * mbed Microcontroller Library + * Copyright (c) 2006-2016 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Test cases to write KVs in the CFSTORE using the drv->Write() API call. + */ +#if defined __MBED__ && ! defined TOOLCHAIN_GCC_ARM + + +#include +#include +#include +#include + +#ifdef TARGET_LIKE_FRDM_K64F_GCC +#include +#endif + +#include "cfstore_config.h" +#include +#include "cfstore_debug.h" +#include "cfstore_test.h" +#include +#include "utest/utest.h" +#include "unity/unity.h" +#include "greentea-client/test_env.h" +#ifdef YOTTA_CFG_CFSTORE_UVISOR +#include "uvisor-lib/uvisor-lib.h" +#include "cfstore_uvisor.h" +#endif /* YOTTA_CFG_CFSTORE_UVISOR */ + +using namespace utest::v1; + +static control_t cfstore_write_test_00(const size_t call_count) +{ + (void) call_count; + printf("Not implemented for ARM toolchain\n"); + return CaseNext; +} + + +utest::v1::status_t greentea_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(100, "default_auto"); + return greentea_test_setup_handler(number_of_cases); +} + +Case cases[] = { + /* 1 2 3 4 5 6 7 */ + /* 1234567890123456789012345678901234567890123456789012345678901234567890 */ + Case("WRITE_test_00", cfstore_write_test_00), +}; + + +/* Declare your test specification with a custom setup handler */ +Specification specification(greentea_setup, cases); + +int main() +{ + return !Harness::run(specification); +} + + + +#else + + +#include +#include +#include + + +#ifdef TARGET_LIKE_FRDM_K64F_GCC +#include +#endif + +#include "cfstore_config.h" +#include "cfstore_test.h" +#include "cfstore_debug.h" +//#include +#include +#include +#include "utest/utest.h" +#include "unity/unity.h" +#include "greentea-client/test_env.h" +#include "cfstore_utest.h" +#ifdef YOTTA_CFG_CFSTORE_UVISOR +#include "uvisor-lib/uvisor-lib.h" +#endif /* YOTTA_CFG_CFSTORE_UVISOR */ + +using namespace utest::v1; + +static char cfstore_write_utest_msg_g[CFSTORE_UTEST_MSG_BUF_SIZE]; + +/* Configure secure box. */ +#ifdef YOTTA_CFG_CFSTORE_UVISOR +UVISOR_BOX_NAMESPACE("com.arm.mbed.cfstore.test.write.box1"); +UVISOR_BOX_CONFIG(cfstore_write_box1, UVISOR_BOX_STACK_SIZE); +#endif /* YOTTA_CFG_CFSTORE_UVISOR */ + + +/* + * write tests + * cfstore_handle_t cfstore_write() + */ + +/* KV data for test_01 */ +static cfstore_kv_data_t cfstore_write_test_01_kv_data[] = { + CFSTORE_INIT_1_TABLE_MID_NODE, + { NULL, NULL}, +}; + + +/* report whether built/configured for flash sync or async mode */ +static control_t cfstore_write_test_00(const size_t call_count) +{ + (void) call_count; + CFSTORE_LOG("INITIALIZING: caps.asynchronous_ops=%lu\n", cfstore_driver.GetCapabilities().asynchronous_ops); + return CaseNext; +} + +/** @brief test to write many times to an open KV to test data is appended + * sequentially to the end of the value blob + * + * + * @return status code + * ARM_DRIVER_OK, the test passed successfully + * ret < ARM_DRIVER_OK, the test failed with the return code + * supplying more details + */ +static control_t cfstore_write_test_01_end(const size_t call_count) +{ + char read_buf[CFSTORE_KEY_NAME_MAX_LENGTH+1]; + uint32_t i = 0; + int32_t ret = ARM_DRIVER_ERROR; + ARM_CFSTORE_SIZE len = 0; + ARM_CFSTORE_DRIVER* drv = &cfstore_driver; + ARM_CFSTORE_KEYDESC kdesc; + ARM_CFSTORE_HANDLE_INIT(hkey); + ARM_CFSTORE_FMODE flags; + + CFSTORE_DBGLOG("%s:entered\n", __func__); + (void) call_count; + memset(read_buf, 0, CFSTORE_KEY_NAME_MAX_LENGTH+1); + memset(&kdesc, 0, sizeof(kdesc)); + memset(&flags, 0, sizeof(flags)); + + /* create an empty KV of the required length */ + kdesc.drl = ARM_RETENTION_WHILE_DEVICE_ACTIVE; + len = strlen(cfstore_write_test_01_kv_data[0].value); + ret = cfstore_test_create(cfstore_write_test_01_kv_data[0].key_name, "one", &len, &kdesc); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_write_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to create new KV (key_name=%s, ret=%" PRId32 ").\n", __func__, cfstore_write_test_01_kv_data[0].key_name, ret); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_write_utest_msg_g); + + /* now open the newly created key and write repeated to created the string */ + flags.write = true; + ret = drv->Open(cfstore_write_test_01_kv_data[0].key_name, flags, hkey); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_write_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to open node (key_name=\"%s\", value=\"%s\")(ret=%" PRId32 ")\n", __func__, cfstore_write_test_01_kv_data[0].key_name, cfstore_write_test_01_kv_data[0].value, ret); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_write_utest_msg_g); + + for(i = 0; i < strlen(cfstore_write_test_01_kv_data[0].value); i++) + { + len = 1; + ret = drv->Write(hkey, &cfstore_write_test_01_kv_data[0].value[i], &len); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_write_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Write failed for char (\'%c\') (ret=%" PRId32 ")\n", __func__, cfstore_write_test_01_kv_data[0].value[i], ret); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_write_utest_msg_g); + } + /* check that the value created in the key is as expected*/ + len = CFSTORE_KEY_NAME_MAX_LENGTH+1; + ret = drv->Read(hkey, read_buf, &len); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_write_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Read failed (ret=%" PRId32 ")\n", __func__, ret); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_write_utest_msg_g); + + /* check node key_names are identical */ + CFSTORE_TEST_UTEST_MESSAGE(cfstore_write_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: KV value (%s) is not as expected (%s).\n", __func__, read_buf, cfstore_write_test_01_kv_data[0].value); + TEST_ASSERT_MESSAGE(strncmp(read_buf, cfstore_write_test_01_kv_data[0].value, strlen(cfstore_write_test_01_kv_data[0].value)) == 0, cfstore_write_utest_msg_g); + + CFSTORE_TEST_UTEST_MESSAGE(cfstore_write_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Close() call failed.\n", __func__); + TEST_ASSERT_MESSAGE(drv->Close(hkey) >= ARM_DRIVER_OK, cfstore_write_utest_msg_g); + + cfstore_test_delete_all(); + ret = drv->Uninitialize(); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_write_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Uninitialize() call failed.\n", __func__); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_write_utest_msg_g); + return CaseNext; +} + +/** @brief test to write with a NULL buffer, which should fail gracefully + * + * + * @return status code + * ARM_DRIVER_OK, the test passed successfully + * ret < ARM_DRIVER_OK, the test failed with the return code + * supplying more details + */ +static control_t cfstore_write_test_02_end(const size_t call_count) +{ + int32_t ret = ARM_DRIVER_ERROR; + ARM_CFSTORE_SIZE len = 0; + ARM_CFSTORE_KEYDESC kdesc; + ARM_CFSTORE_DRIVER* drv = &cfstore_driver; + + CFSTORE_DBGLOG("%s:entered\n", __func__); + (void) call_count; + memset(&kdesc, 0, sizeof(kdesc)); + + /* create an empty KV of the required length */ + kdesc.drl = ARM_RETENTION_WHILE_DEVICE_ACTIVE; + len = strlen(cfstore_write_test_01_kv_data[0].value); + ret = cfstore_test_create(cfstore_write_test_01_kv_data[0].key_name, NULL, &len, &kdesc); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_write_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error KV creation should have failed due to null write buffer but something else happended (ret=%" PRId32 ").\n", __func__, ret); + TEST_ASSERT_MESSAGE(ret == ARM_CFSTORE_DRIVER_ERROR_INVALID_WRITE_BUFFER, cfstore_write_utest_msg_g); + + ret = drv->Uninitialize(); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_write_utest_msg_g, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: Uninitialize() call failed.\n", __func__); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_write_utest_msg_g); + return CaseNext; +} + + +utest::v1::status_t greentea_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(200, "default_auto"); + return greentea_test_setup_handler(number_of_cases); +} + +Case cases[] = { + /* 1 2 3 4 5 6 7 */ + /* 1234567890123456789012345678901234567890123456789012345678901234567890 */ + Case("WRITE_test_00", cfstore_write_test_00), + Case("WRITE_test_01_start", cfstore_utest_default_start), + Case("WRITE_test_01_end", cfstore_write_test_01_end), + Case("WRITE_test_02_start", cfstore_utest_default_start), + Case("WRITE_test_02_end", cfstore_write_test_02_end), +}; + + +/* Declare your test specification with a custom setup handler */ +Specification specification(greentea_setup, cases); + +#if defined CFSTORE_CONFIG_MBED_OS_VERSION && CFSTORE_CONFIG_MBED_OS_VERSION == 3 +/* mbedosV3*/ +void app_start(int argc __unused, char** argv __unused) +{ + /* Run the test specification */ + Harness::run(specification); +} +#endif /* CFSTORE_CONFIG_MBED_OS_VERSION == 3 */ + +#if defined CFSTORE_CONFIG_MBED_OS_VERSION && CFSTORE_CONFIG_MBED_OS_VERSION == 4 +/* mbedosV3++*/ +int main() +{ + return !Harness::run(specification); +} +#endif /* CFSTORE_CONFIG_MBED_OS_VERSION == 4 */ + + +#endif // __MBED__ && ! defined TOOLCHAIN_GCC_ARM diff --git a/storage/cfstore/LICENSE b/storage/cfstore/LICENSE new file mode 100644 index 0000000000..3ebeebb336 --- /dev/null +++ b/storage/cfstore/LICENSE @@ -0,0 +1,8 @@ +Unless specifically indicated otherwise in a file, files are licensed +2 under the Apache 2.0 license, as can be found in: apache-2.0.txt + +Source code in cfstore_fnmatch.c is licensed under the agreements in the +following files: +- berkeley.txt +- chernov.txt +- tatmanjants.txt \ No newline at end of file diff --git a/storage/cfstore/Makefile.scripts b/storage/cfstore/Makefile.scripts new file mode 100644 index 0000000000..b9067d61a7 --- /dev/null +++ b/storage/cfstore/Makefile.scripts @@ -0,0 +1,65 @@ +########################################################################### +# +# Copyright (c) 2013-2015, ARM Limited, All Rights Reserved +# SPDX-License-Identifier: Apache-2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +########################################################################### + +# +# inline debugging/flashing scripts +# +define __SCRIPT_GDB + target remote $(DEBUG_HOST) + monitor endian little + monitor reset + monitor halt + monitor semihosting enable + monitor speed 1000 + monitor loadbin $(TARGET_BIN) 0 + monitor flash device = $(CPU) + load $(TARGET) + file $(TARGET) + $(GDB_DEBUG_UVISOR) + b vmpu_init_post + b app_start +endef +export __SCRIPT_GDB + +define __SCRIPT_FLASH + r + loadbin $(TARGET_BIN) 0 + r + g + q +endef +export __SCRIPT_FLASH + +define __SCRIPT_ERASE + h + Sleep 100 + unlock kinetis + Sleep 100 + erase + q +endef +export __SCRIPT_ERASE + +define __SCRIPT_RESET + h + r + g + q +endef +export __SCRIPT_RESET diff --git a/storage/cfstore/README.md b/storage/cfstore/README.md new file mode 100644 index 0000000000..64b9d01251 --- /dev/null +++ b/storage/cfstore/README.md @@ -0,0 +1,112 @@ +# Secure Key-Value Storage # + + +## Executive Summary + +The Configuration Store (CFSTORE) is a secure, +associative key-value (KV) store C-Language Hardware Abstraction Layer. +CFSTORE provides the secure and persistent storage for: +- Storing encryption keys data. +- Storing configuration data. +- Storing firmware, firmware updates and incremental firmware blocks for assembling into a firmware update. + +These services are presented to clients with: +- A conceptually simple, file-like interface for storing and managing data using (key, value) pairs in + persistent storage media. +- A simple, hardware-independent API to promote portability across multiple platforms and a low attack surface. +- A very small code/memory footprint so CFSTORE is capable of running on highly-constrained memory systems (~10kB free memory) + where typically available SRAM << NV storage. +- A simple (low complexity) storage capability at the expense of features. For example, CFSTORE only supports the storage of + binary blobs rather than a rich set of data types. + +Current support includes: +- NV-backed support. Integration with Flash Abstraction (Flash Journal Strategy Sequential) for persistent storage on the Freescale FRDM K64F target. +- SRAM backed support. +- More than 60 test cases with >80% test coverage. +- Comprehensive documentation. + + +# Configuration-Store Software Architecture + +```C + + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Configuration Store Client | + | e.g. FOTA | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Configuration Store | | uvisor | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | + | Flash Abstraction Layer | | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | + | Flash Driver Layer | | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + SW + ----------------------------------------------------------------------- + HW + + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | NV Storage Media e.g. Flash | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Configuration Store Software Architecture + +``` + +The above figure shows the following entities (from top to bottom): +- A Configuration Store client e.g. FOTA. +- Configuration Store, the associative KV pair store. +- Flash Abstraction Layer, portable across the driver layer. +- Flash Driver layer e.g. CMSIS-Driver. +- NV Storage Media. These are the physical storage media. + + +# Providing Feedback + +If you would like to make a contribution to CFSTORE, please provide feedback/designs/comments/code in one of the following ways: +- By logging an issue in the CFSTORE repo. +- By submitting a Pull Request to the CFSTORE repo. +- By sending an email to: +-- simon.hughes@arm.com +-- milosch.meriac@arm.com + + +# Further Reading + +* The [CFSTORE Getting Started Guide.][CFSTORE_GETSTART] +* The [CFSTORE Client Example 3 for flash-journal synchronous mode only (simpler code).][CFSTORE_EX3] +* The [CFSTORE Client Example 1 for both flash-journal modes (asynchronous and synchronous)(more complicated but versatile code).][CFSTORE_EX1] +* The CFSTORE Product Requirements were not written. +* The [CFSTORE Engineering Requirements.][CFSTORE_ENGREQ] +* The [CFSTORE High Level Design Document.][CFSTORE_HLD] +* The [CFSTORE Low Level Design Document.][CFSTORE_LLD] +* The [CFSTORE Project Test Plan describing the test methodologies and test cases.][CFSTORE_TESTPLAN] +* The [CFSTORE Release Notes.][CFSTORE_RELEASES] +* The [CFSTORE Jenkins Build and Test Results.][CFSTORE_JENKINS_BT] +* The [CFSTORE Jenkins Code Coverage Results.][CFSTORE_JENKINS_COV] +* The [CFSTORE Project Plan describing milestones and roadmap.][CFSTORE_PROJPLAN] +* The [CFSTORE Project Plan Excel Spreadsheet with estimates and milestones][CFSTORE_PROJXLS] +* The [Flash Abstraction Layer.][FAL] + + +[CFSTORE_ENGREQ]: https://github.com/ARMmbed/configuration-store/blob/master/doc/design/configuration_store_requirements.md +[CFSTORE_EX1]: https://github.com/ARMmbed/configuration-store-example1 +[CFSTORE_EX3]: https://github.com/ARMmbed/configuration-store-example3 +[CFSTORE_GETSTART]: https://github.com/ARMmbed/configuration-store/blob/master/doc/design/configuration_store_getting_started.md +[CFSTORE_HLD]: https://github.com/ARMmbed/configuration-store/blob/master/doc/design/configuration_store_hld.md +[CFSTORE_JENKINS_BT]: http://e108747.cambridge.arm.com:8080/job/configuration-store-nightly-build-and-test/ +[CFSTORE_JENKINS_COV]: http://e108747.cambridge.arm.com:8080/job/configuration-store-test-coverage/ +[CFSTORE_LLD]: https://github.com/ARMmbed/configuration-store/blob/master/doc/design/configuration_store_lld.md +[CFSTORE_TESTPLAN]: https://github.com/ARMmbed/configuration-store/blob/master/doc/design/configuration_store_test_plan.md +[CFSTORE_PRODREQ]: https://github.com/ARMmbed/configuration-store/blob/master/doc/design/configuration_store_product_requirements.md +[CFSTORE_PROJPLAN]:https://github.com/ARMmbed/configuration-store/blob/master/doc/design/configuration_store_project.md +[CFSTORE_PROJXLS]:https://github.com/ARMmbed/configuration-store/blob/master/doc/project/ARM_MBED_TN_0020_cfstore_project_plan.xlsx +[CFSTORE_RELEASES]:https://github.com/ARMmbed/configuration-store/blob/master/doc/project/configuration_store_releases.md +[CFSTORE_TERM]: https://github.com/ARMmbed/configuration-store/blob/master/doc/design/configuration_store_terminology.md +[FAL]: https://github.com/ARMmbed/flash-abstraction diff --git a/storage/cfstore/VERSION b/storage/cfstore/VERSION new file mode 100644 index 0000000000..a3c7a02f9b --- /dev/null +++ b/storage/cfstore/VERSION @@ -0,0 +1,3 @@ +{ + "version": "0.3.3", +} diff --git a/storage/cfstore/apache-2.0.txt b/storage/cfstore/apache-2.0.txt new file mode 100644 index 0000000000..35750c5de1 --- /dev/null +++ b/storage/cfstore/apache-2.0.txt @@ -0,0 +1,13 @@ +Copyright (c) 2016 ARM Limited + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/storage/cfstore/berkeley.txt b/storage/cfstore/berkeley.txt new file mode 100644 index 0000000000..85d6eacfe0 --- /dev/null +++ b/storage/cfstore/berkeley.txt @@ -0,0 +1,31 @@ +/* + * Copyright (c) 1989, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Guido van Rossum. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ \ No newline at end of file diff --git a/storage/cfstore/chernov.txt b/storage/cfstore/chernov.txt new file mode 100644 index 0000000000..a81f43cd23 --- /dev/null +++ b/storage/cfstore/chernov.txt @@ -0,0 +1,25 @@ +/* + * Copyright (C) 1996 by Andrey A. Chernov, Moscow, Russia. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ diff --git a/storage/cfstore/configuration-store/configuration_store.h b/storage/cfstore/configuration-store/configuration_store.h new file mode 100644 index 0000000000..560b29753d --- /dev/null +++ b/storage/cfstore/configuration-store/configuration_store.h @@ -0,0 +1,949 @@ +/** @file configure-store.h + * + * mbed Microcontroller Library + * Copyright (c) 2006-2016 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * This is the interface file to configuration store service. + */ +#ifndef __CONFIGURATION_STORE_H +#define __CONFIGURATION_STORE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include /* requierd for memset() in ARM_CFSTORE_HANDLE_INIT() */ + +#define DEVICE_STORAGE 1 /* enable storage */ +#include +#include + +#define ARM_CFSTORE_API_VERSION ARM_DRIVER_VERSION_MAJOR_MINOR(1,0) /* API version */ +#define ARM_CFSTORE_DRV_VERSION ARM_DRIVER_VERSION_MAJOR_MINOR(0,1) /* DRV version */ + +/* CFSTORE Specific error codes*/ +#define ARM_CFSTORE_DRIVER_ERROR_UNINITIALISED -1000 /* Start of driver specific errors */ +#define ARM_CFSTORE_DRIVER_ERROR_PREEXISTING_KEY -1001 +#define ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND -1002 +#define ARM_CFSTORE_DRIVER_ERROR_INVALID_HANDLE -1003 +#define ARM_CFSTORE_DRIVER_ERROR_OUT_OF_MEMORY -1004 +#define ARM_CFSTORE_DRIVER_ERROR_PREEXISTING_KEY_DELETING -1005 +#define ARM_CFSTORE_DRIVER_ERROR_INVALID_HANDLE_BUF -1006 +#define ARM_CFSTORE_DRIVER_ERROR_INTERNAL -1007 +#define ARM_CFSTORE_DRIVER_ERROR_INVALID_KEY_NAME -1008 +#define ARM_CFSTORE_DRIVER_ERROR_VALUE_SIZE_TOO_LARGE -1009 +#define ARM_CFSTORE_DRIVER_ERROR_KEY_READ_ONLY -1010 +#define ARM_CFSTORE_DRIVER_ERROR_INVALID_SEEK -1011 +#define ARM_CFSTORE_DRIVER_ERROR_KEY_UNREADABLE -1012 +#define ARM_CFSTORE_DRIVER_ERROR_INVALID_WRITE_BUFFER -1013 +#define ARM_CFSTORE_DRIVER_ERROR_INVALID_KEY_LEN -1014 +#define ARM_CFSTORE_DRIVER_ERROR_NOT_SUPPORTED -1015 +#define ARM_CFSTORE_DRIVER_ERROR_INVALID_READ_BUFFER -1016 +#define ARM_CFSTORE_DRIVER_ERROR_INVALID_KEY_DESCRIPTOR -1017 +#define ARM_CFSTORE_DRIVER_ERROR_PERM_NO_READ_ACCESS -1018 +#define ARM_CFSTORE_DRIVER_ERROR_PERM_NO_WRITE_ACCESS -1019 +#define ARM_CFSTORE_DRIVER_ERROR_PERM_NO_EXECUTE_ACCESS -1020 +#define ARM_CFSTORE_DRIVER_ERROR_NO_PERMISSIONS -1021 +#define ARM_CFSTORE_DRIVER_ERROR_HANDLE_COUNT_MAX -1022 +#define ARM_CFSTORE_DRIVER_ERROR_JOURNAL_STATUS_ERROR -1023 +#define ARM_CFSTORE_DRIVER_ERROR_JOURNAL_STATUS_BUSY -1024 +#define ARM_CFSTORE_DRIVER_ERROR_JOURNAL_STATUS_TIMEOUT -1025 +#define ARM_CFSTORE_DRIVER_ERROR_JOURNAL_STATUS_UNSUPPORTED -1026 +#define ARM_CFSTORE_DRIVER_ERROR_JOURNAL_STATUS_PARAMETER -1027 +#define ARM_CFSTORE_DRIVER_ERROR_JOURNAL_STATUS_BOUNDED_CAPACITY -1028 +#define ARM_CFSTORE_DRIVER_ERROR_JOURNAL_STATUS_STORAGE_API_ERROR -1029 +#define ARM_CFSTORE_DRIVER_ERROR_JOURNAL_STATUS_STORAGE_IO_ERROR -1030 +#define ARM_CFSTORE_DRIVER_ERROR_JOURNAL_STATUS_NOT_INITIALIZED -1031 +#define ARM_CFSTORE_DRIVER_ERROR_JOURNAL_STATUS_ATTEMPTING_COMMIT_WITHOUT_WRITE -1032 +#define ARM_CFSTORE_DRIVER_ERROR_JOURNAL_STATUS_EMPTY -1033 +#define ARM_CFSTORE_DRIVER_ERROR_JOURNAL_STATUS_SMALL_LOG_REQUEST -1034 +#define ARM_CFSTORE_DRIVER_ERROR_OPERATION_PENDING -1035 +#define ARM_CFSTORE_DRIVER_ERROR_UVISOR_BOX_ID -1036 +#define ARM_CFSTORE_DRIVER_ERROR_UVISOR_NAMESPACE -1037 + + +/* + * Type Definitions + * + * ARM_CFSTORE_HANDLE + * opaque cfstore handle for manipulating cfstore data objects e.g. KV pairs. + */ +typedef void *ARM_CFSTORE_HANDLE; +typedef size_t ARM_CFSTORE_SIZE; +typedef size_t ARM_CFSTORE_OFFSET; + +typedef struct _ARM_CFSTORE_STATUS { + uint32_t in_progress : 1; + uint32_t error : 1; +} ARM_CFSTORE_STATUS; + + +/* Defines + * + * CFSTORE_KEY_NAME_MAX_LENGTH + * The maximum length of the null terminated character string used as a + * key name string. + * + * CFSTORE_VALUE_SIZE_MAX + * Max size of the KV value blob (currently 64MB) + * + * CFSTORE_HANDLE_BUFSIZE + * size of the buffer owned and supplied by client to CFSTORE to hold internal + * data structures, referenced by the key handle. Note this can change on + * different platforms depending on the sizeof types. + * + */ +#define CFSTORE_KEY_NAME_MAX_LENGTH 220 +#define CFSTORE_VALUE_SIZE_MAX (1<<26) + +#ifdef TARGET_LIKE_FRDM_K64F_GCC +#define CFSTORE_HANDLE_BUFSIZE 24 +#endif + +#ifdef TARGET_LIKE_X86_LINUX_NATIVE +#define CFSTORE_HANDLE_BUFSIZE 40 +#endif + +/* @brief Helper macro to declare handle and client owned buffer supplied + * to CFSTORE for storing opaque handle state */ +#define ARM_CFSTORE_HANDLE_INIT(__name) \ + uint8_t (__name##_buf_cFsToRe)[CFSTORE_HANDLE_BUFSIZE]; \ + ARM_CFSTORE_HANDLE (__name) = (ARM_CFSTORE_HANDLE) (__name##_buf_cFsToRe); \ + memset((__name##_buf_cFsToRe), 0, CFSTORE_HANDLE_BUFSIZE) + +/* @brief Helper macro to swap 2 handles, which is useful for the Find() + * idiom (see CFSTORE_NOTE1 later). + */ +#if defined __MBED__ && defined TOOLCHAIN_GCC_ARM +#define CFSTORE_HANDLE_SWAP(__a_HaNdLe, __b_HaNdLe) \ + do{ ARM_CFSTORE_HANDLE __temp_HaNdLe = (__a_HaNdLe); \ + __asm volatile("" ::: "memory"); \ + (__a_HaNdLe) = (__b_HaNdLe); \ + __asm volatile("" ::: "memory"); \ + (__b_HaNdLe) = (__temp_HaNdLe); \ + __asm volatile("" ::: "memory"); \ + }while(0) +#endif + +#if defined __MBED__ && defined TOOLCHAIN_ARM +/* todo: implment this macro */ +#define CFSTORE_HANDLE_SWAP(__a_HaNdLe, __b_HaNdLe) \ + do{ ARM_CFSTORE_HANDLE __temp_HaNdLe = (__a_HaNdLe); \ + __dmb(0xf); \ + (__a_HaNdLe) = (__b_HaNdLe); \ + __dmb(0xf); \ + (__b_HaNdLe) = (__temp_HaNdLe); \ + __dmb(0xf); \ + }while(0) +#endif + +/* @brief The access control permissions for the key-value. + * @note A client requires the perm_xxx_write set to be able to + * delete the KV. + * @param perm_owner_read + * if set => this KV is owner readable + * @param perm_owner_write + * if set => this KV is owner writable + * @param perm_owner_execute (currently not supported) + * if set => this KV is owner executable + * @param perm_other_read + * if set => this KV is world readable + * @param perm_other_write + * if set => this KV is world writable + * @param perm_other_execute (currently not supported) + * if set => this KV is world executable + * @param reserved + * reserved for future use. + */ +typedef struct ARM_CFSTORE_ACCESS_CONTROL_LIST +{ + uint32_t perm_owner_read : 1; + uint32_t perm_owner_write : 1; + uint32_t perm_owner_execute : 1; + uint32_t perm_other_read : 1; + uint32_t perm_other_write : 1; + uint32_t perm_other_execute : 1; + uint32_t reserved : 26; +} ARM_CFSTORE_ACCESS_CONTROL_LIST; + + +/* @brief file mode bitfield structure for specifying how flags for the + * following operations: + * - ARM_CFSTORE_DRIVER::(*Create)(), when creating a KV. + * - ARM_CFSTORE_DRIVER::(*Open)(), when opening a pre-existing KV. + * + * continuous + * if set, the key value should be stored in a continuous sequence of hardware + * addresses + * + * lazy_flush + * if set then configuration store will defer flushing the KV + * changes until an optimal time. e.g. to save energy rather than performing + * the operation immediately. + * + * flush_on_close + * if set then the key-value should be flushed to the backing store when + * the key is closed. + * + * read + * if set then the KV can be read + * + * write + * if set then the KV can be written + * + * storage_detect + * if set then the call to ARM_CFSTORE_DRIVER::(*Create)() returns whether + * a key could be created with the required storage characteristics. The + * key is not created. + */ + +typedef struct ARM_CFSTORE_FMODE +{ + uint32_t continuous : 1; + uint32_t lazy_flush : 1; + uint32_t flush_on_close : 1; + uint32_t read : 1; + uint32_t write : 1; + uint32_t execute : 1; + uint32_t storage_detect : 1; + uint32_t reserved : 25; +} ARM_CFSTORE_FMODE; + + +/** + * @brief descriptor used to create keys + * + * @param acl + * Access Control List specifying the access permissions of the KV. + * @param drl + * data retention level for the KV required by the client. CFSTORE will + * store the KV in the specified type store/media. + * @param security + * flash security properties for the KV required by the client. CFSTORE + * will store the KV in a storage media supporting the specified + * security attributes. + * @param flags + * A bitfield containing the access mode setting for the key. + * + */ +typedef struct ARM_CFSTORE_KEYDESC +{ + /*key descriptor attributes */ + ARM_CFSTORE_ACCESS_CONTROL_LIST acl; + uint8_t drl; + ARM_STORAGE_SECURITY_FEATURES security; + ARM_CFSTORE_FMODE flags; +} ARM_CFSTORE_KEYDESC; + + +/* ARM_CFSTORE_OPCODE, ARM_CFSTORE_CALLBACK and the Asynchronous Completion + * of Driver Dispatch methods [REFERENCE_1] + * + * Configuration Store driver dispatch methods can operate in 2 modes: + + * - Synchronous i.e. when: + * ARM_CFSTORE_CAPABILITIES::asynchronous_ops == 0 + * then the ARM_CFSTORE_DRIVER::Dispatch_Method_Xxx() will return: + * - >= 0 => CFSTORE Dispatch_Method_Xxx() completed successfully + * - otherwise CFSTORE Dispatch_Method_Xxx() did not complete successfully + * (return code supplies further details). + * In synchronous mode there it is optional as to whether the client registers + * a client callback with the Initialize() method. If one is registered, it + * will be called to indicate the synchronous completion status. + * + * - Asynchronous i.e. when: + * ARM_CFSTORE_CAPABILITIES::asynchronous_ops == 1 + * then the ARM_CFSTORE_DRIVER::Dispatch_Method_Xxx() will return: + * - return_value = ARM_DRIVER_OK (i.e. ==0) implies CFSTORE + * Dispatch_Method_Xxx() transaction pending. Dispatch_Method_Xxx + * completion status will be indicated via + * an asynchronous call to ARM_CFSTORE_CALLBACK registered with the + * ARM_CFSTORE_DRIVER::(*Initialize)(), where the status supplied to + * the callback will be the final status of the call. + * - return_value > ARM_DRIVER_OK (i.e. > 0) implies CFSTORE Dispatch_Method_Xxx() completely + * synchronously and successfully. The return_value has specific + * meaning for the Dispatch_Method_Xxx() e.g. for the Read() method + * return_value is the number of bytes read. + * - otherwise return_value < 0 => CFSTORE Dispatch_Method_Xxx() + * completed unsuccessfully (return code supplies further details). + * + * The client registered asynchronous callback method ARM_CFSTORE_CALLBACK is + * registered by the client using: + * ARM_CFSTORE_DRIVER::(*Initialize)(ARM_CFSTORE_CALLBACK callback, + * void* client_context) + * See the (*Initialize) documentation for more details. + * + * The registered callback has the following prototype: + * + * typedef void (*ARM_CFSTORE_CALLBACK)( + * int32_t status, + * ARM_CFSTORE_OPCODE cmd_code, + * void *client_context, + * ARM_CFSTORE_HANDLE handle); + * + * Before an asynchronous notification is received, a client can check on the + * status of the call by calling ARM_CFSTORE_DRIVER::(*GetStatus)(). + * + */ +typedef enum ARM_CFSTORE_OPCODE { + CFSTORE_OPCODE_CLOSE = 1, + CFSTORE_OPCODE_CREATE, + CFSTORE_OPCODE_DELETE, + CFSTORE_OPCODE_FIND, + CFSTORE_OPCODE_FLUSH, + CFSTORE_OPCODE_GET_KEY_NAME, + CFSTORE_OPCODE_GET_STATUS, + CFSTORE_OPCODE_GET_VALUE_LEN, + CFSTORE_OPCODE_INITIALIZE, + CFSTORE_OPCODE_OPEN, + CFSTORE_OPCODE_POWER_CONTROL, + CFSTORE_OPCODE_READ, + CFSTORE_OPCODE_RSEEK, + CFSTORE_OPCODE_UNINITIALIZE, + CFSTORE_OPCODE_WRITE, + CFSTORE_OPCODE_MAX +} ARM_CFSTORE_OPCODE; + + +/* [REFERENCE_2] + * + * @brief client registered callback type for receiving asynchronous event + * notifications. + * + * @param status + * In the case that cmd_code is one of ARM_CFSTORE_OPCODE then this + * is the asynchronous completion status of the associated + * ARM_CFSTORE_DRIVER::Dispatch_Method_Xxx() + * @param cmd_code + * ARM_CFSTORE_OPCODE for the + * ARM_CFSTORE_DRIVER::Dispatch_Method_Xxx() for which this + * invocation of the callback is an asynchronous completion event. + * @param client_context + * The client ARM_CFSTORE_CALLBACK context registered with the + * ARM_CFSTORE_DRIVER::(*Initialize)() method. + * @param handle + * For certain ARM_CFSTORE_DRIVER::Dispatch_Method_Xxx() e.g. + * ARM_CFSTORE_DRIVER::(*Create)() + * ARM_CFSTORE_DRIVER::(*Open)() + * ARM_CFSTORE_DRIVER::(*Find)() + * then an open key handle is supplied upon asynchronous completion. + * See the documentation of the ARM_CFSTORE_OpCode_e and the + * ARM_CFSTORE_DRIVER::Dispatch_Method_Xxx() for further details. + * + */ +typedef void (*ARM_CFSTORE_CALLBACK)(int32_t status, ARM_CFSTORE_OPCODE cmd_code, void *client_context, ARM_CFSTORE_HANDLE handle); + + +/* @brief Find the capabilities of the configuration store. + * + * @param asynchronous_ops + * If set => the configuration store dispatch interface is operating in + * non-blocking (asynchronous) mode. + * If clr => the configuration store dispatch interface is operating in + * blocking (synchronous) mode. + * @param uvisor_support_enabled + * The configuration store is using uvisor security contexts. + */ + +typedef struct ARM_CFSTORE_CAPABILITIES +{ + uint32_t asynchronous_ops : 1; + uint32_t uvisor_support_enabled : 1; +} ARM_CFSTORE_CAPABILITIES; + + +/** + * This is the set of operations constituting the Configuration Store driver. + * + * The functions dispatch methods can operate synchronously or asynchronously + * depending on the underlying implementation. The client of this interface + * should not assume one or other mode of operation but use the + * (*GetCapabilities) method to determine the operational mode and then + * behave accordingly. + */ +typedef struct _ARM_DRIVER_CFSTORE +{ + /** + * @brief Get driver version. + * + * The synchronous function GetVersion() returns version information of the + * driver implementation in ARM_DRIVER_VERSION. + * - ARM_DRIVER_VERSION::api + * the version of the CMSIS-Driver specification used to implement + * this driver. + * - ARM_DRIVER_VERSION::drv + * the source code version of the actual configuration store driver + * implementation. + * + * @return \ref ARM_DRIVER_VERSION, the configuration store driver + * version information + */ + ARM_DRIVER_VERSION (*GetVersion)(void); + + + /** + * @brief Close the hkey context previously recovered from CFSTORE. + * + * @param hkey + * IN: a previously returned handle from (*Create((), (*Open)() + * or (*Find)() to close. + * + * @return return_value + * + * See REFERENCE_1 and REFERENCE_2. + * ARM_CFSTORE_DRIVER::(*Close)() asynchronous completion command code + * (*ARM_CFSTORE_CALLBACK) function argument values on return: + * @param status + * ARM_DRIVER_OK => success, KV deleted, else failure. + * @param cmd_code == CFSTORE_OPCODE_CLOSE + * @param client context + * as registered with ARM_CFSTORE_DRIVER::(*Initialize)() + * @param hkey == NULL + */ + int32_t (*Close)(ARM_CFSTORE_HANDLE hkey); + + + /** + * @brief Create a key-value int he configuration strore. + * + * Once created, the following attributes of a KV cannot be changed: + * - the key_name + * - the permissions or attributes specifies by the key descriptor kdesc. + * To change these properties, the key must be deleted and then created + * again with the new properties. + * + * @param key_name + * IN: zero terminated string specifying the key name. + * @param value_len + * the client specifies the length of the value data item in the + * KV being created. + * @param kdesc + * IN: key descriptor, specifying how the details of the key + * create operations. Note the following cases: + * 1) if key_name is not present in the CFSTORE and kdesc is NULL + * (i.e. a new KV pair is being created), + * then CFSTORE will chose the most appropriate defaults + * e.g. CFSTORE will store the KV in nv store if the value size + * is large, with no security guarantees just safety. + * 2) if key_name is present in the CFSTORE and kdesc is NULL + * (i.e. there is a pre-existing KV pair), + * then CFSTORE will grow/shrink the value data buffer to + * value_len octets. This idiom can be used to increase/decrease + * the size of the KV value storage. + * 3) If the kdesc->flags.storage_detect == 1 then the function + * does not create the key but reports whether the key + * with the specified size and storage media attributes + * could/could not be created by configuration storage. + * @param hkey + * IN: pointer to client owned buffer of CFSTORE_HANDLE_BUFSIZE + * bytes + * OUT: on success, hkey is a valid handle to a KV. + * + * @return return_value + * + * See REFERENCE_1 and REFERENCE_2. + * ARM_CFSTORE_DRIVER::(*Create)() asynchronous completion command code + * (*ARM_CFSTORE_CALLBACK) function argument values on return: + * @param status + * ARM_DRIVER_OK => success, KV deleted, else failure. + * @param cmd_code == CFSTORE_OPCODE_CREATE + * @param client context + * as registered with ARM_CFSTORE_DRIVER::(*Initialize)() + * @param hkey now contains returned handle to newly created key. + */ + int32_t (*Create)(const char* key_name, ARM_CFSTORE_SIZE value_len, const ARM_CFSTORE_KEYDESC* kdesc, ARM_CFSTORE_HANDLE hkey); + + + /** + * @brief delete key-value from configuration store + * + * This method is used in the following ways: + * - (*Open)() to get a handle to the key, (*Delete)() to delete the key, + * (*Close)() to close the handle to the key. + * - (*Find)() to get a handle to the key, (*Delete)() to delete the key, + * (*Close)() to close the handle to the key. + * + * @param hkey + * IN: the handle of the key to delete. + * + * @return return_value + * + * See REFERENCE_1 and REFERENCE_2. + * ARM_CFSTORE_DRIVER::(*Delete)() asynchronous completion command code + * (*ARM_CFSTORE_CALLBACK) function argument values on return: + * @param status + * ARM_DRIVER_OK => success, KV deleted, else failure. + * @param cmd_code == CFSTORE_OPCODE_DELETE + * @param client context + * as registered with ARM_CFSTORE_DRIVER::(*Initialize)() + * @param hkey, unused. + * + */ + int32_t (*Delete)(ARM_CFSTORE_HANDLE hkey); + + + /** + * @brief find stored keys that match a query string + * + * find a list of pre-existing keys according to a query pattern. + * The search pattern can have the following formats + * - 'com.arm.mbed.wifi.accesspoint.essid'. Find whether an object + * exists that has a key matching + * 'com.arm.mbed.wifi.accesspoint.essid' + * - 'com.arm.mbed.wifi.accesspoint*.essid'. Find all keys that + * start with the substring 'com.arm.mbed.wifi.accesspoint' and + * end with the substring '.essid' + * - 'yotta.your-yotta-registry-module-name.*'. Find all key_name + * strings that begin with the substring + * 'yotta.your-yotta-registry-module-name.' + * - 'yotta.hello-world.animal[dog][foot][*]'. Find all key_name + * strings beginning yotta.hello-world.animal[dog][foot] + * - 'yotta.hello-world.animal[dog][foot]*' + * - 'yotta.hello-world.animal[dog*3]' + * + * It is possible to iterate over the list of matching keys by + * using the idiom below (in the synchronous case)(CFSTORE_NOTE1) + * + * int32_t ret = ARM_DRIVER_ERROR; + * const char* key_name_query = "*"; + * char key_name[CFSTORE_KEY_NAME_MAX_LENGTH+1]; + * uint8_t len = CFSTORE_KEY_NAME_MAX_LENGTH+1; + * ARM_CFSTORE_HANDLE_INIT(next); + * ARM_CFSTORE_HANDLE_INIT(prev); + * + * while(drv->Find(key_name_query, prev, next) == ARM_DRIVER_OK) + * { + * len = CFSTORE_KEY_NAME_MAX_LENGTH+1; + * drv->GetKeyName(next, key_name, &len); + * printf("Found matching key-value with key_name=%s\n", key_name); + * CFSTORE_HANDLE_SWAP(prev, next); + * } + * + * The iteration over the find results can be terminated before + * the end of the list is reached by closing the last open + * file handle and not making any further calls to + * find() e.g. + * + * int32_t ret = ARM_DRIVER_ERROR; + * const char* key_name_query = "*"; + * char key_name[CFSTORE_KEY_NAME_MAX_LENGTH+1]; + * uint8_t len = CFSTORE_KEY_NAME_MAX_LENGTH+1; + * ARM_CFSTORE_HANDLE_INIT(next); + * ARM_CFSTORE_HANDLE_INIT(prev); + * + * while(drv->Find(key_name_query, prev, next) == ARM_DRIVER_OK) + * { + * len = CFSTORE_KEY_NAME_MAX_LENGTH+1; + * drv->GetKeyName(next, key_name, &len); + * if(strncmp(key_name, "my.key_name", CFSTORE_KEY_NAME_MAX_LENGTH)) + * { + * printf("Found matching key-value with key_name=%s\n", key_name; + * // terminating walk of find results + * drv->Close(next); + * break; + * } + * CFSTORE_HANDLE_SWAP(prev, next); + * } + * + * @param key_name_query + * IN: a search string to find. This can include the wildcard '*' + * character + * @param previous + * IN: On the first call to (*Find) then previous is a pointer + * (the handle) to a buffer initialised to 0. + * On the subsequent calls to (*Find), a previously returned + * key handle can be supplied as the previous argument. The next + * available search result will be returned. If no further search + * results are available then (*Find) will return + * ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND. Once the + * file handle has been supplied to the function as the prev + * argument, CFSTORE close the open file handle. Otherwise, the + * client must call (*Close)() on the open file handle. + * @param next + * IN: pointer to client owned buffer of CFSTORE_HANDLE_BUFSIZE + * bytes to hold the + * OUT: Success: In the case that a match has been found then hkey + * is a valid handle to an open KV. The key must be explicitly closed + * by the client. Note this is a read-only key. + * Async operation: The storage at hkey must be available until after + * the completion notification has been received by the client. + * @return return_value + * On success (finding a KV matching the query) ARM_DRIVER_OK is + * returned. If a KV is not found matching the description then + * ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND is returned. + * See REFERENCE_1 and REFERENCE_2. + * ARM_CFSTORE_DRIVER::(*Find)() asynchronous completion command code + * (*ARM_CFSTORE_CALLBACK) function argument values on return: + * @param status + * ARM_DRIVER_OK => success, hkey contains open key + * else failure. + * @param cmd_code == CFSTORE_OPCODE_FIND + * @param client context + * as registered with ARM_CFSTORE_DRIVER::(*Initialize)() + * @param hkey + * ARM_DRIVER_OK => contains returned handle to newly found key. + * else, indeterminate data. + */ + int32_t (*Find)(const char* key_name_query, const ARM_CFSTORE_HANDLE previous, ARM_CFSTORE_HANDLE next); + + + /** + * @brief flush (write) the configuration changes to the nv backing + * store. + * + * @note all open key handles must be closed before flushing the CFSTORE to nv + * backing store. + * + * @return return_value + * See REFERENCE_1 and REFERENCE_2. + * ARM_CFSTORE_DRIVER::(*Flush)() asynchronous completion command code + * (*ARM_CFSTORE_CALLBACK) function argument values on return: + * @param status + * ARM_DRIVER_OK => success, hkey contains open key + * else failure. + * @param cmd_code == CFSTORE_OPCODE_FLUSH + * @param client context, registered ARM_CFSTORE_DRIVER::(*Initialize)() + * @param hkey, unused + */ + int32_t (*Flush)(void); + + + /** + * @brief Get configuration store capabilities. + * + * This synchronous function returns a ARM_CFSTORE_CAPABILITIES + * information structure describing configuration store implementation + * attributes. + * + * @return \ref ARM_CFSTORE_CAPABILITIES + */ + ARM_CFSTORE_CAPABILITIES (*GetCapabilities)(void); + + + /** + * @brief get the name of an open key handle + * + * @param hkey + * open handle of key to get the key_name + * @param key_name. The key name string is guaranteed to be terminated + * with '\0'. + * @param key_len, the length of the buffer available at data to receive + * the key_name string + * @return return_value + * See REFERENCE_1 and REFERENCE_2. + * ARM_CFSTORE_DRIVER::(*GetKeyName)() asynchronous completion command code + * (*ARM_CFSTORE_CALLBACK) function argument values on return: + * @param status + * ARM_DRIVER_OK => success, key_name contains key_name string, len + * contains length of string. + * else failure. + * @param cmd_code == CFSTORE_OPCODE_GET_KEY_NAME + * @param client context, registered ARM_CFSTORE_DRIVER::(*Initialize)() + * @param hkey supplied to the GetKeyName() call at hkey. + * @param key_name + * on success, the buffer holds the name of the key + * @param key_len + * on success, the supplied integer is set to strlen(key_name)+1, where + * the additional character corresponds to the terminating null. + * + */ + int32_t (*GetKeyName)(ARM_CFSTORE_HANDLE hkey, char* key_name, uint8_t *key_len); + + + /** + * @brief Get the status of the configuration store. + * + * @return return_value + * See REFERENCE_1 and REFERENCE_2 + * ARM_DRIVER_OK if the command has been accepted and + * enqueued by the underlying controller, else an appropriate + * error code. Getting a return value of ARM_DRIVER_OK + * implies that basic argument validation was successful, and the + * caller can expect a command completion callback to be invoked + * at a later time. + * + * ARM_CFSTORE_DRIVER::(*GetStatus)() asynchronous completion command code + * (*ARM_CFSTORE_CALLBACK) function argument values on return: + * @param status + * status of next command pending completion + * @param cmd_code + * next command pending completion. + * @param client context registered ARM_CFSTORE_DRIVER::(*Initialize)() + * @param hkey + * unused. + */ + ARM_CFSTORE_STATUS (*GetStatus)(void); + + + /** + * @brief get the value length from an open key handle + * + * @param hkey + * open handle of key for which to get value length + * @param value_len, the location in which to store the value length. + * @return return_value + * See REFERENCE_1 and REFERENCE_2. + * ARM_CFSTORE_DRIVER::(*GetValueLen)() asynchronous completion command code + * (*ARM_CFSTORE_CALLBACK) function argument values on return: + * @param status + * ARM_DRIVER_OK => success, value_len contains length value. + * else failure. + * @param cmd_code == CFSTORE_OPCODE_GET_VALUE_LEN + * @param client context, registered ARM_CFSTORE_DRIVER::(*Initialize)() + * @param hkey supplied to the GetValueLen() call at hkey. + * + */ + int32_t (*GetValueLen)(ARM_CFSTORE_HANDLE hkey, ARM_CFSTORE_SIZE *value_len); + + + /** + * @brief Initialize the Configuration Store + * + * This function: + * - initialised the configuration store service + * - allows the client to subscribe to event notifications, in particular + * the asynchronous completion events for the driver dispatch interface + * (see ARM_CFSTORE_OPCODE). + * + * The configuration store should be initialised as follows: + * drv->initialise(client_callback, client_callback_context); + * drv->PowerControl(ARM_POWER_FULL) + * where: + * - client_callback is a client implemented callback function. + * - client_callback_context is a client registered context that + * will be supplied as an argument to the client_callback + * when called. + * - PowerControl indicates that any underlying system services + * that are in the low power state should be powered up. + * + * The configuration store should be de-initialised as follows: + * drv->PowerControl(ARM_POWER_OFF) + * drv->Deinitialise(); + * + * @param client_callback + * this is a client implemented callback function for + * receiving asynchronous event notifications (see + * ARM_CFSTORE_CALLBACK). NULL indicates client does + * not subscribed to event notifications. + * + * @param client_callback_context + * this is the client registered context that + * will be supplied as an argument to the client_callback + * when called. This argument can be NULL. + * + * @return return_value + * See REFERENCE_1 and REFERENCE_2 + * ARM_CFSTORE_DRIVER::(*Initialize)() asynchronous completion command code + * (*ARM_CFSTORE_CALLBACK) function argument values on return: + * @param status + * ARM_DRIVER_OK => success, configuration store initialised, + * else failure + * @param CFSTORE_OPCODE_INITIALIZE + * @param client context registered ARM_CFSTORE_DRIVER::(*Initialize)() + * @param hkey, unused. + * + */ + int32_t (*Initialize)(ARM_CFSTORE_CALLBACK callback, void* client_context); + + + /** + * @brief Function to set the target configuration store power state. + * + * @param state + * \ref ARM_POWER_STATE. The target power-state for the + * configuration store. The parameter state can have the + * following values: + * - ARM_POWER_FULL => set the mode to full power state + * - ARM_POWER_LOW => set the mode to low power state + * - ARM_POWER_OFF => set the mode to off power state + * + * @return return_value + * See REFERENCE_1 and REFERENCE_2. + * CFSTORE_OPCODE_POWER_CONTROL + * ARM_CFSTORE_DRIVER::(*PowerControl)() asynchronous completion command code + * (*ARM_CFSTORE_CALLBACK) function argument values on return: + * @param status + * ARM_DRIVER_OK => success, power control set, else failure. + * @param cmd_code == CFSTORE_OPCODE_POWER_CONTROL + * @param client context, registered ARM_CFSTORE_DRIVER::(*Initialize)() + * @param hkey, unused. + */ + int32_t (*PowerControl)(ARM_POWER_STATE state); + + + /** + * @brief read the value data associated with a specified key. + * + * @param hkey + * IN: the handle returned from a previous call to (*Open)() to + * get a handle to the key + * @param data + * IN: a pointer to a data buffer supplied by the caller for CFSTORE to + * fill with value data + * OUT: on ARM_DRIVER_OK the data is (or will be when asynchronously + * completed) available in the buffer. The data will be read from + * the current form the current location (see (*Rseek)(). + * @param len + * IN: the client specifies the length of the buffer available at data + * OUT: the CFSTORE specifies how many octets have been stored in the + * supplied buffer. Note fewer octets may be stored than the input len + * depending on the CFSTORE internal representation of the value. + * + * @return return_value + * See REFERENCE_1 and REFERENCE_2. + * return_value == ARM_DRIVER_OK (==0) => asynchronous + * transaction pending. + * return_value > 0 => synchronous completion of read with the + * number of bytes read == return_value + * return_value < 0, error condition. + * + * ARM_CFSTORE_DRIVER::(*Read)() asynchronous completion command code + * (*ARM_CFSTORE_CALLBACK) function argument values on return: + * @param status + * >= 0 => success with number of bytes read as indicated by + * the value of status + * < 0 => error, data in the data buffer is undefined, len is + * undefined. + * @param cmd_code == CFSTORE_OPCODE_READ + * @param client context, registered ARM_CFSTORE_DRIVER::(*Initialize)() + * @param hkey, unused. + */ + int32_t (*Read)(ARM_CFSTORE_HANDLE hkey, void* data, ARM_CFSTORE_SIZE* len); + + + /** + * @brief Open a key-value object for future operations. + * + * @param key_name + * IN: zero terminated string specifying the key name. + * @param flags + * can open a RW key in read only mode. + * @param hkey + * IN: pointer to client owned buffer of CFSTORE_HANDLE_BUFSIZE + * bytes + * OUT: on success, hkey is a valid handle to an open KV. + * + * @return return_value + * See REFERENCE_1 and REFERENCE_2. + * ARM_CFSTORE_DRIVER::(*Open)() asynchronous completion command code + * (*ARM_CFSTORE_CALLBACK) function argument values on return: + * @param status + * ARM_DRIVER_OK => success, KV opened, else failure. + * @param cmd_code == CFSTORE_OPCODE_OPEN + * @param client context, registered ARM_CFSTORE_DRIVER::(*Initialize)() + * @param hkey now contains returned handle to newly opened key. + */ + int32_t (*Open)(const char* key_name, ARM_CFSTORE_FMODE flags, ARM_CFSTORE_HANDLE hkey); + + + /** + * @brief move the position of the read pointer within a value + * + * @param hkey + * IN: the key referencing the value data for which the read + * location should be updated. Note that this function can + * only be called on pre-existing keys opened with read-only + * flag. Performing a seek operation on a writable key will fail. + * @param offset + * IN: the new offset position from the start of the value data + * + * @return return_value + * See REFERENCE_1 and REFERENCE_2. + * ARM_CFSTORE_DRIVER::(*Rseek)() asynchronous completion command code + * (*ARM_CFSTORE_CALLBACK) function argument values on return: + * @param status + * >=0 => success, read location set, else failure. + * upon success, the function returns the current read + * location measured from the beginning of the data value. + * <0 => error + * @param cmd_code == CFSTORE_OPCODE_RSEEK + * @param client context, registered ARM_CFSTORE_DRIVER::(*Initialize)() + * @param hkey, unused. + */ + int32_t (*Rseek)(ARM_CFSTORE_HANDLE hkey, ARM_CFSTORE_OFFSET offset); + + + /** + * @brief Function to de-initialise the Configuration Store + * + * @return return_value + * See REFERENCE_1 and REFERENCE_2 + * CFSTORE_OPCODE_UNINITIALIZE + * ARM_CFSTORE_DRIVER::(*Uninitialize)() asynchronous completion command code + * (*ARM_CFSTORE_CALLBACK) function argument values on return: + * @param status + * ARM_DRIVER_OK => success, read location set, else failure. + * @param cmd_code == CFSTORE_OPCODE_UNINITIALIZE + * @param client context, registered ARM_CFSTORE_DRIVER::(*Initialize)() + * @param hkey, unused. + */ + int32_t (*Uninitialize)(void); + + + /** + * @brief write the value data associated with a specified key + * + * @note Note that Write() only supports sequential-access. + * + * @param hkey + * IN: the key for which value data will be written + * @param data + * IN: a pointer to a data buffer supplied by the caller for CFSTORE to + * write as the binary blob value data. + * Async operation: the buffer must be available until after + * completion notification is received by the client. + * @param len + * IN: the client specifies the length of the data buffer available. + * len must not exceed the value_len field specified when the + * KV pair was created. + * OUT: the CFSTORE specifies how many octets have been stored. + * Note that fewer octets may be stored than the input len + * depending on the CFSTORE internal representation of the value. + * Async operation: the len storage location must be available + * until after completion notification is received by the client. + * + * @return return_value + * See REFERENCE_1 and REFERENCE_2. + * return_value == ARM_DRIVER_OK (==0) => asynchronous + * transaction pending. + * return_value > 0 => synchronous completion of write with the + * number of bytes written == return_value + * return_value < 0, error condition. + * + * ARM_CFSTORE_DRIVER::(*Write)() asynchronous completion + * (*ARM_CFSTORE_CALLBACK) function argument values on return: + * @param status + * >= 0 => success with the number bytes written equal to the value + * of the return status + * ARM_CFSTORE_CALLBACK status argument < 0 => error + * @param cmd_code == CFSTORE_OPCODE_WRITE + * @param client context, registered ARM_CFSTORE_DRIVER::(*Initialize)() + * @param hkey, unused. + */ + int32_t (*Write)(ARM_CFSTORE_HANDLE hkey, const char* data, ARM_CFSTORE_SIZE* len); + + +} const ARM_CFSTORE_DRIVER; + + + +extern ARM_CFSTORE_DRIVER cfstore_driver; + +#ifdef __cplusplus +} +#endif + +#endif /* __CONFIGURATION_STORE_H */ diff --git a/storage/cfstore/doc/design/configuration_store_getting_started.md b/storage/cfstore/doc/design/configuration_store_getting_started.md new file mode 100644 index 0000000000..3e561b264b --- /dev/null +++ b/storage/cfstore/doc/design/configuration_store_getting_started.md @@ -0,0 +1,219 @@ +# Configuration Store Getting Started +Author: Simon Hughes + +# Overview + +## Executive Summary + +This document describes how to get started with the configuration store module. + +## Terminology + +The terminology used throughout this document is defined on the [CFSTORE Terminology](https://github.com/ARMmbed/configuration-store/blob/master/doc/design/configuration_store_terminology.md) page. + + +# CFSTORE : Getting started + +This is the link to the configuration store github repo, with links to further documentation from the top level readme.md is [here.](https://github.com/ARMmbed/configuration-store/README.md) + +The documentation explains how the API works. There are also a number of test cases in the repo which can be used as examples of how to use the API. + +This is the project plan is [here.](https://github.com/ARMmbed/configuration-store/blob/master/doc/design/configuration_store_project.md) + +* Milestone 1 (SRAM version) has been released and tagged MBED_V_0_1_0. +* Milestone 2 (CFSTORE Flash Journal Integration) has been released and tagged MBED_V_0_2_0. + + +# CFSTORE : Building the Module + +First take a clone of the configuration store github repository from the tag of the last release. For example: + +``` + simhug01@E107851:/d/sdh_dev$ git clone git@github.com:ARMmbed/configuration-store.git +``` + +Then cd into the configuration-store sub-dir and get a list of the tags + +``` + simhug01@E107851:/d/sdh_dev$ cd configuration-store + simhug01@E107851:/d/sdh_dev/configuration-store $ git tag -l + MBED_V_0_1_0 + MBED_V_0_2_0 +``` + +The current release is MBED_V_0_2_0 (CFSTORE-flash journal integrated version). Checkout this version for evaluation: + +``` + simhug01@E107851:/d/sdh_dev/configuration-store $ git checkout tags/MBED_V_0_2_0 +``` + +configuration-store depends on modules published in the private yotta registry and therefore you need access to this registry. To login to the yotta private use the following command: + +``` + simhug01@E107851:/d/sdh_dev/configuration-store $ yotta login --registry https://yotta-private.herokuapp.com --apikey=873_b8isfdns3684_327t2evut3r +``` + + +Set the yotta target: + +``` + simhug01@E107851:/d/sdh_dev/configuration-store $ yt target frdm-k64f-gcc +``` + +Now install the yotta dependencies (which will require access to the yotta private registry to succeed): + +``` + simhug01@E107851:/d/sdh_dev/configuration-store $ yt install +``` + +You should see something like the following for the output to yotta list, which shows the CFSTORE module dependency graph: + +``` + simhug01@E107851:/d/datastore/public/jobs/yr2016/2247/sdh_dev_8/configuration-store$ yt list + configuration-store 0.2.0 + |_ mbed-drivers 1.5.0 + | |_ mbed-hal 1.3.0 yotta_modules\mbed-hal + | | \_ mbed-hal-freescale 1.1.0 yotta_modules\mbed-hal-freescale + | | \_ mbed-hal-ksdk-mcu 1.3.0 yotta_modules\mbed-hal-ksdk-mcu + | | |_ uvisor-lib 2.1.2 yotta_modules\uvisor-lib + | | \_ mbed-hal-k64f 1.3.0 yotta_modules\mbed-hal-k64f + | | \_ mbed-hal-frdm-k64f 1.1.1 yotta_modules\mbed-hal-frdm-k64f + | |_ cmsis-core 1.2.0 yotta_modules\cmsis-core + | | \_ cmsis-core-freescale 1.1.0 yotta_modules\cmsis-core-freescale + | | \_ cmsis-core-k64f 1.1.0 yotta_modules\cmsis-core-k64f + | |_ ualloc 1.3.0 yotta_modules\ualloc + | | \_ dlmalloc 1.1.0 yotta_modules\dlmalloc + | |_ minar 1.3.0 yotta_modules\minar + | | \_ minar-platform 1.1.0 yotta_modules\minar-platform + | | \_ minar-platform-mbed 1.3.0 yotta_modules\minar-platform-mbed + | |_ core-util 1.8.0 yotta_modules\core-util + | \_ compiler-polyfill 1.3.0 yotta_modules\compiler-polyfill + |_ flash-journal-strategy-sequential 0.3.0 + | \_ flash-journal 0.3.0 yotta_modules\flash-journal + | \_ flash-abstraction 0.3.0 yotta_modules\flash-abstraction + | \_ mtd-k64f 0.3.0 yotta_modules\mtd-k64f + |_ unity 2.2.0 (test dependency) + | \_ utest 1.12.2 yotta_modules\utest + \_ greentea-client 0.1.8 (test dependency) + +``` + +Now build configuration-store: + +``` + simhug01@E107851:/d/sdh_dev/configuration-store $ yt build +``` + +The above command builds CFSTORE with support for asynchronous mode flash-journal. If you would like synchronous mode support then use +the following build command: + +``` + simhug01@E107851:/d/sdh_dev/configuration-store $ yotta --config='{"config":{"hardware":{"mtd":{"async":{"ops":0}}}}}' build +``` + +Having built successfully, you can now test with the following mbed-greentea command: + +``` + simhug01@E107851:/d/sdh_dev/configuration-store $ mbedgt -V +``` + +The test results should be similar to the test results form the [Jenkins CFSTORE Build and Test Job](http://e108747.cambridge.arm.com:8080/job/configuration-store-nightly-build-and-test/) the summary of which is provided below for reference: + +``` +mbedgt: test suite report: ++---------------+---------------+----------------------------------+--------+--------------------+-------------+ +| target | platform_name | test suite | result | elapsed_time (sec) | copy_method | ++---------------+---------------+----------------------------------+--------+--------------------+-------------+ +| frdm-k64f-gcc | K64F | configuration-store-test-acl | OK | 10.26 | shell | +| frdm-k64f-gcc | K64F | configuration-store-test-add_del | OK | 20.78 | shell | +| frdm-k64f-gcc | K64F | configuration-store-test-close | OK | 13.02 | shell | +| frdm-k64f-gcc | K64F | configuration-store-test-create | OK | 12.8 | shell | +| frdm-k64f-gcc | K64F | configuration-store-test-find | OK | 24.31 | shell | +| frdm-k64f-gcc | K64F | configuration-store-test-flash | OK | 11.27 | shell | +| frdm-k64f-gcc | K64F | configuration-store-test-flush | OK | 12.51 | shell | +| frdm-k64f-gcc | K64F | configuration-store-test-flush2 | OK | 12.53 | shell | +| frdm-k64f-gcc | K64F | configuration-store-test-misc | OK | 14.64 | shell | +| frdm-k64f-gcc | K64F | configuration-store-test-open | OK | 14.5 | shell | +| frdm-k64f-gcc | K64F | configuration-store-test-read | OK | 12.78 | shell | +| frdm-k64f-gcc | K64F | configuration-store-test-write | OK | 12.88 | shell | ++---------------+---------------+----------------------------------+--------+--------------------+-------------+ +mbedgt: test suite results: 12 OK +mbedgt: test case report: ++---------------+---------------+----------------------------------+------------------------------+--------+--------+--------+--------------------+ +| target | platform_name | test suite | test case | passed | failed | result | elapsed_time (sec) | ++---------------+---------------+----------------------------------+------------------------------+--------+--------+--------+--------------------+ +| frdm-k64f-gcc | K64F | configuration-store-test-acl | CFSTORE_ACL_test_01 | 1 | 0 | OK | 0.1 | +| frdm-k64f-gcc | K64F | configuration-store-test-add_del | ADD_DEL_test_01 | 1 | 0 | OK | 0.1 | +| frdm-k64f-gcc | K64F | configuration-store-test-add_del | ADD_DEL_test_02 | 1 | 0 | OK | 0.1 | +| frdm-k64f-gcc | K64F | configuration-store-test-add_del | ADD_DEL_test_03 | 1 | 0 | OK | 0.1 | +| frdm-k64f-gcc | K64F | configuration-store-test-add_del | ADD_DEL_test_04 | 1 | 0 | OK | 0.1 | +| frdm-k64f-gcc | K64F | configuration-store-test-add_del | ADD_DEL_test_05 | 1 | 0 | OK | 0.11 | +| frdm-k64f-gcc | K64F | configuration-store-test-add_del | ADD_DEL_test_06 | 1 | 0 | OK | 0.1 | +| frdm-k64f-gcc | K64F | configuration-store-test-add_del | ADD_DEL_test_07_end | 1 | 0 | OK | 0.25 | +| frdm-k64f-gcc | K64F | configuration-store-test-add_del | ADD_DEL_test_07_start | 1 | 0 | OK | 0.05 | +| frdm-k64f-gcc | K64F | configuration-store-test-add_del | ADD_DEL_test_08_end | 1 | 0 | OK | 0.54 | +| frdm-k64f-gcc | K64F | configuration-store-test-add_del | ADD_DEL_test_08_start | 1 | 0 | OK | 0.05 | +| frdm-k64f-gcc | K64F | configuration-store-test-add_del | ADD_DEL_test_09_end | 1 | 0 | OK | 4.94 | +| frdm-k64f-gcc | K64F | configuration-store-test-add_del | ADD_DEL_test_09_start | 1 | 0 | OK | 0.05 | +| frdm-k64f-gcc | K64F | configuration-store-test-add_del | ADD_DEL_test_10 | 1 | 0 | OK | 0.11 | +| frdm-k64f-gcc | K64F | configuration-store-test-close | CLOSE_test_01_end | 1 | 0 | OK | 0.51 | +| frdm-k64f-gcc | K64F | configuration-store-test-close | CLOSE_test_01_start | 1 | 0 | OK | 0.04 | +| frdm-k64f-gcc | K64F | configuration-store-test-create | CREATE_test_01_end | 1 | 0 | OK | 0.19 | +| frdm-k64f-gcc | K64F | configuration-store-test-create | CREATE_test_01_start | 1 | 0 | OK | 0.05 | +| frdm-k64f-gcc | K64F | configuration-store-test-find | FIND_test_01 | 1 | 0 | OK | 0.1 | +| frdm-k64f-gcc | K64F | configuration-store-test-find | FIND_test_02 | 1 | 0 | OK | 0.1 | +| frdm-k64f-gcc | K64F | configuration-store-test-find | FIND_test_03_end | 1 | 0 | OK | 10.53 | +| frdm-k64f-gcc | K64F | configuration-store-test-find | FIND_test_03_start | 1 | 0 | OK | 0.05 | +| frdm-k64f-gcc | K64F | configuration-store-test-find | FIND_test_04 | 1 | 0 | OK | 0.09 | +| frdm-k64f-gcc | K64F | configuration-store-test-find | FIND_test_05_end | 1 | 0 | OK | 0.05 | +| frdm-k64f-gcc | K64F | configuration-store-test-find | FIND_test_05_start | 1 | 0 | OK | 0.05 | +| frdm-k64f-gcc | K64F | configuration-store-test-flash | flash_journal_async_test_01 | 1 | 0 | OK | 0.22 | +| frdm-k64f-gcc | K64F | configuration-store-test-flush | initialize | 1 | 0 | OK | 0.03 | +| frdm-k64f-gcc | K64F | configuration-store-test-flush2 | CFSTORE_FLUSH2_flush | 1 | 0 | OK | 0.17 | +| frdm-k64f-gcc | K64F | configuration-store-test-flush2 | CFSTORE_FLUSH2_init_on_entry | 1 | 0 | OK | 0.06 | +| frdm-k64f-gcc | K64F | configuration-store-test-misc | MISC_test_00_end | 1 | 0 | OK | 0.04 | +| frdm-k64f-gcc | K64F | configuration-store-test-misc | MISC_test_00_start | 1 | 0 | OK | 0.05 | +| frdm-k64f-gcc | K64F | configuration-store-test-misc | MISC_test_01 | 1 | 0 | OK | 0.04 | +| frdm-k64f-gcc | K64F | configuration-store-test-misc | MISC_test_02 | 1 | 0 | OK | 0.04 | +| frdm-k64f-gcc | K64F | configuration-store-test-misc | MISC_test_03_end | 1 | 0 | OK | 0.4 | +| frdm-k64f-gcc | K64F | configuration-store-test-misc | MISC_test_03_start | 1 | 0 | OK | 0.05 | +| frdm-k64f-gcc | K64F | configuration-store-test-misc | MISC_test_04_end | 1 | 0 | OK | 0.24 | +| frdm-k64f-gcc | K64F | configuration-store-test-misc | MISC_test_04_start | 1 | 0 | OK | 0.05 | +| frdm-k64f-gcc | K64F | configuration-store-test-misc | MISC_test_05_end | 1 | 0 | OK | 0.05 | +| frdm-k64f-gcc | K64F | configuration-store-test-misc | MISC_test_05_start | 1 | 0 | OK | 0.05 | +| frdm-k64f-gcc | K64F | configuration-store-test-open | OPEN_test_01_end | 1 | 0 | OK | 0.26 | +| frdm-k64f-gcc | K64F | configuration-store-test-open | OPEN_test_01_start | 1 | 0 | OK | 0.04 | +| frdm-k64f-gcc | K64F | configuration-store-test-open | OPEN_test_02_end | 1 | 0 | OK | 0.05 | +| frdm-k64f-gcc | K64F | configuration-store-test-open | OPEN_test_02_start | 1 | 0 | OK | 0.05 | +| frdm-k64f-gcc | K64F | configuration-store-test-open | OPEN_test_100 | 1 | 0 | OK | 0.1 | +| frdm-k64f-gcc | K64F | configuration-store-test-open | OPEN_test_101 | 1 | 0 | OK | 0.1 | +| frdm-k64f-gcc | K64F | configuration-store-test-open | OPEN_test_102 | 1 | 0 | OK | 0.09 | +| frdm-k64f-gcc | K64F | configuration-store-test-open | OPEN_test_103 | 1 | 0 | OK | 0.1 | +| frdm-k64f-gcc | K64F | configuration-store-test-open | OPEN_test_104 | 1 | 0 | OK | 0.1 | +| frdm-k64f-gcc | K64F | configuration-store-test-open | OPEN_test_105 | 1 | 0 | OK | 0.1 | +| frdm-k64f-gcc | K64F | configuration-store-test-read | READ_test_01_end | 1 | 0 | OK | 0.05 | +| frdm-k64f-gcc | K64F | configuration-store-test-read | READ_test_01_start | 1 | 0 | OK | 0.04 | +| frdm-k64f-gcc | K64F | configuration-store-test-read | READ_test_02 | 1 | 0 | OK | 0.1 | +| frdm-k64f-gcc | K64F | configuration-store-test-write | WRITE_test_01_end | 1 | 0 | OK | 0.04 | +| frdm-k64f-gcc | K64F | configuration-store-test-write | WRITE_test_01_start | 1 | 0 | OK | 0.04 | +| frdm-k64f-gcc | K64F | configuration-store-test-write | WRITE_test_02_end | 1 | 0 | OK | 0.04 | +| frdm-k64f-gcc | K64F | configuration-store-test-write | WRITE_test_02_start | 1 | 0 | OK | 0.05 | ++---------------+---------------+----------------------------------+------------------------------+--------+--------+--------+--------------------+ +mbedgt: test case results: 56 OK +mbedgt: completed in 177.39 sec +simhug01@E107851:/d/datastore/public/jobs/yr2016/2247/sdh_dev_8/configuration-store$``` + + +# FAQ + +## Q: What version has been published in the yotta registry? + +A: Version 0.1.0 is the latest version published in the yotta registry. + +## Q: Does Configuration-Store work with mbed OS 16.3? +A: Yes + +## Q: Does Configuration-Store work with mbed OS 15.11? +A: Yes + + diff --git a/storage/cfstore/doc/design/configuration_store_hld.md b/storage/cfstore/doc/design/configuration_store_hld.md new file mode 100644 index 0000000000..58625b6ba7 --- /dev/null +++ b/storage/cfstore/doc/design/configuration_store_hld.md @@ -0,0 +1,1096 @@ +# Configuration Store High Level Design +Author: Simon Hughes + +# Overview + +## Executive Summary + +This document is the High Level Design for the first version of the +Configuration Store (CFSTORE). The configuration store is a secure, +associative key-value (KV) store C-Language Hardware Abstraction Layer. +CFSTORE's main function is storing and managing (key, value) pairs in +persistent storage media. It implements a subset of the requirements as listed +in the supported requirements section. + +CFSTORE provides the secure and persistent storage for: + +- Storing encryption keys data. +- Storing configuration data. +- Storing firmware, firmware updates and incremental firmware blocks for assembling into a firmware update. + +i.e. CFSTORE is a general purpose registry for storing code and data objects. + +These services are presented to clients with: + +- A conceptually simple, file-like interface for storing and managing data using (key, value) pairs in + persistent storage media. +- A simple, hardware-independent API to promote portability across multiple platforms and a low attack surface. +- A very small code/memory footprint so CFSTORE is capable of running on highly-constrained memory systems (~10kB free memory) + where typically available SRAM << NV storage. +- A simple (low complexity) storage capability such CFSTORE only supports the storage of binary blobs. + + +## Terminology + +The terminology used throughout this document is defined [here] [CFSTORE_TERM]. + + +## Document Scope + +The scope of this document is the High Level Design (HLD) of the +Configuration Store (CFSTORE) component. + +The scope of this document is describe the CFSTORE high level design for the +following features: + +- The creation of new key-value (KV) pairs in the store for writing. + The values are binary blobs with no type structure. +- The opening of pre-existing KV pairs for reading/writing/deletion. +- The searching of KVs with keys matching a search string with wildcards. +- The synchronous and asynchronous completion of the above functions. +- The committing of KV pair changes to non-volatile backing stores. +- The secure storage and management of KV pairs according to access permissions and uvisor supported security features. +- CFSTORE alignment with the CMSIS-Driver Model. + + +The [overview](#Overview) section provides an introduction to this document including a CFSTORE executive summary. + +The [use cases](#Use-Cases) section describes the important CFSTORE client use cases, in particular the +FOTA use case. + +The [software architecture](#Configuration-Store-Software-Architecture) section describes the +entities in the CFSTORE software stack including the CFSTORE clients (e.g. FOTA), CFSTORE, the +[flash-abstraction layer][FAL], the CMSIS-Driver Flash driver layer, uvisor and the hardware/software +interface. + +The [CFSTORE API](#Configuration-Store-Application-Programming-Interface-(CFSTORE-API)) section describes the +application programming interface to the CFSTORE component. This includes sequence diagrams +describing the client-CFSTORE API call sequences to use the interface to accomplish common +operations e.g. CFSTORE initialisation/de-initialisation, creating a key and finding KVs +that match a given search specification. + + +## Outstanding Issues With This Document + +The following is a list of outstanding issues with this document: + +- The list of supported requirements needs updating. +- Security considerations need defining. +- The usage of keys needs defining. + + +# CFSTORE Motivation, Design Considerations and Key Concepts + +## Rationale/Motivation + +CFSTORE provides the secure and persistent storage for: + +- Storing encryption keys data. +- Storing configuration data. +- Storing firmware, firmware updates and incremental firmware blocks for assembling into a firmware update. + +i.e. CFSTORE is a general purpose registry for storing code and data objects. + +These services are presented to clients in the following way: + +- A simple, hardware-independent API to promote portability across multiple platforms and a low attack surface. +- A very small code/memory footprint so CFSTORE is capable of scaling from highly-constrained memory systems (~10kB free memory) + where typically available SRAM << NV storage, to less constrained systems with more memory. +- A simple (low complexity) storage capability such CFSTORE only supports the storage of binary blobs. + + +## CFSTORE Security Considerations + +For security reasons the uVisor security model allows applications (general purpose code) +only restricted access to NV (flash) storage. This ensures modifications to OS or application +code are tightly controlled so ensure: + +- Malware cannot become resident in the system. +- Security measures like Access Control Lists (ACLs) cannot be modified or circumvented by malicious code. + + +## Low Complexity of CFSTORE and the Implied Security Benefits + +The design concept behind the secure key-value storage one of simplicity to ensure a +low attack surface. The design reflects the smallest possible common denominator +for storing data and code blocks in a mutually-distrustful operating system. + +Complex access restrictions are implemented in additional uvisor boxes as +CFSTORE clients i.e. "on top of" the secure CFSTORE key-value storage. An example of a complex +access restriction is given as follows: + +> The following key can be only updated from Monday to Thursday by a remote +> server matching the following valid public key + +The additional secure uvisor box is used to wrap values with box-specific +ACLs and marks these keys as accessible only to the owner box. +Restricting access in this way guarantees domain-specific +key-access restrictions can be reliably enforced by each security context. + + +## CFSTORE Implied Shifting of Complexity to Other (Higher Layer) Components + +The same is true for supporting custom or complex data types beyond the simple octet blob supported by CFSTORE. +For sophisticated configuration storage +systems arbitrary types can be supported by wrapping values with a type identifier. +This ensures that every programming language can be adequately and safely supported by +the key-value storage. + + +## Key Value Storage + +The CFSTORE KV storage has the following characteristics: + +- The only supported key-value payload type is a binary blob. +- All values are referenced by a globally name-spaced key string. +- The key_name is required to be unique on a device. +- Although by design the key_name format does not provide the notion of hierarchic key-trees, + key-hierarchies can be reflected in key path strings. +- Allowable characters in a key path directory entry are only ASCII letters, digits, and the '-' character. +- Path directory entries are separated by the path delimiter ('.'). +- Path directory entries are indicated to be part 'lists' by adding one or more list indexes enclosed by square brackets ('\[ ]'). + Index names are composed with allowable characters (see previous point). +- Key name sizes are limited to 220 bytes (excluding zero termination). + +The following illustrates valid name examples: + +``` + + 'com.arm.mbed.wifi.accesspoint[5].essid' = 'AccessNG' + + 'com.arm.mbed.wifi.accesspoint[home].essid' = 'HomeSweetHome' + + 'yotta.your-yotta-registry-module-name.your-value' = 'XYZ' + + 'yotta.hello-world.animal[dog][foot][3]' = 'dirty' +``` + +Note that the key-path-prefix 'yotta' is reserved for modules in the [yotta registry](http://yotta.mbed.com/). + + +## Key Ownership + +Key ownership is tied to the name of the key. + +- If a client security context (uvisor box) needs to create CFSTORE KV entries, it must + have a (mandatory) key name prefix. This is called the security_prefix_name. +- When a client security context create a KV pair, the security_prefix_name is "enforced" + for created values i.e. the security_prefix_name must be the prefix of the key_name. +- Therefore, the CFSTORE key_name namespace owned by a client security context is defined by the + clients security_prefix_name. + +Consider the following example: + +- The client security context (uvisor box) has the security_prefix_name "com.arm.mbed.tls". + This security_prefix_name is registered with uvisor as part of box creation. +- The client security context creates a CFSTORE KV with client_key_name='com.arm.mbed.tls.cert[5].key'. +- CFSTORE queries uvisor for the client security_prefix_name and computes the client_key_name_prefix by + post-pending '.' to give "com.arm.mbed.tls.". +- CFSTORE only creates the KV if the client security_prefix_name (i.e. "com.arm.mbed.tls.") + matches the leading characters of the client_key_name (i.e. "com.arm.mbed.tls.cert[5].key"). + In this case there is a match so CFSTORE creates the KV. +- The client "com.arm.mbed.tls" uvisor box is regarded as the owner of the newly created key. + +Uvisor box security_prefix_name's are not allowed to overlap. + + +## Access Control Security ### + +Access control lists (ACL) enforce access for the following security groups + +- Owner. +- Other. + +The permissions for these two groups are: + +- Reading. +- Writing. +- Execution. + +The resulting matrix can be represented by a 6-bit binary field: + +- Owner (i.e. the caller during key creation: + - Read permission bit. + - Write permission bit. + - Execute permission bit. +- Other (i.e. everybody else): + - Read permission bit. + - Write permission bit. + - Execute permission bit. + +Note the following: + +- A writable field is not allowed to be executable. +- The executable bit is not supported till further notice and is reserved for performing modular firmware updates at a later point. +- The high level API provides a function for listing accessible values, but ensures that only values with + read or write access will be listed to the caller. +- The caller is able to choose between listing just the values he owns, or values of others he has read or write access to. + + +## Finding Keys + +Whenever a key is read, the CFSTORE is scanned for active keys with suitable access permissions key-by-key. +Wild card searches are explicitly supported. The reserved character asterisk ('*') is used to indicate a wild +card search to the API. Wild card operations are only supported for finding keys, not for accessing keys. +The wild card operator can occur once at any point of the search string: + +The following shows examples of valid key_name query strings to the Find() method: + +``` + + 'com.arm.mbed.wifi.accesspoint*.essid' + + 'yotta.your-yotta-registry-module-name.*' + + 'yotta.hello-world.animal[dog][foot][*]' + + 'yotta.hello-world.animal[dog][foot]*' + + 'yotta.hello-world.animal[dog*3]' + +``` + +Note that whenever a search returns a key candidate, the search can be resumed to return further matches. + + +## Creating & Opening Keys for Writing + +Keys must be explicitly created using Create() with the following parameters: + +- Security ACLs (owner & others). +- The intended retention levels. +- The expected Device Data Security Protection Features +- The value size +- Mode flags + +Note the following: + +- Pre-existing keys are opened using the Open(). +- The returned handle allows write access to the value by default. +- Wild cards are not allowed for creating or opening keys. +- Failing to meet expected retention levels or security levels result in the API call failing. +- An executable key is always treated as 'continuous' by the API even if the 'continuous' flag is not set by the caller. +- Non-executable values can be optionally 'continuous'. + + +## Error Handling + +### Overview of Error Handling + +The following provides general notes on the handling of errors: + +- CFSTORE is intended to "Fail-Safe" i.e. if errors occur then the system should be recoverable from such errors. +- "Fail-Safe" requires CFSTORE storage backends must support the flushing of data in an atomic operation. This is so + that the loss of power during a flush operation to the CFSTORE backend does not result in the stored data being in + an indeterminate state. +- Supported backends may include non-volatile storage (flash) and SRAM for example. +- For exmaple. tf a non-volatile storage (flash) backend is supported, then the flushing of data to the NV store must be atomic. + This may require that flushing of data to falsh is commited using an atomic write operation e.g. of a CRC32 value for the + commit data. If power loss occured during the atomic write then the CRC32 would be invalid, the previously written data would + not be value, and the system would have to revert to a previous version of the data that has successfully commit the correct CRC32 + value. + + +### Synchronous/Asynchronous API Calls and Error Handling + +The CFSTORE has 2 modes of operations: + +- Synchronous (SYNC) mode. +- Asynchronous (ASYNC) mode. + +The mode is determined by inspecting the results of the GetCapabilites() API call. + +All CFSTORE API calls (apart of specific exclusions listed below) return an int32_t return code designated ```RETURN_CODE```. + +- A ```RETURN_CODE``` < 0 always indicates an error. +- A ```RETURN_CODE``` >= 0 always indicates success. + + - In SYNC mode the operation has completed successfully. + - In ASYNC mode the transaction has been queued successfully, pending completion sometime in the future. + The transaction status of the completed tranaction ```RETURN_CODE_ASYNC``` is supplied to the client + registered callback handler (if such a callback handler has been registered). +- Specific API calls may assign meaning to ```RETURN_CODE``` or ```RETURN_CODE_ASYNC``` when >=0. For example ```RETURN_CODE``` or ```RETURN_CODE_ASYNC``` + for a successful Read() call may be interpretted as the number of octets read. Consult the documentation for specific API calls + for further details. + +In ASYNC mode: + +- The client may register a callback handler for asynchronous completion notifications i.e. to receive the final + return status code ```RETURN_CODE_ASYNC```. +- API calls may return synchronously. A client may be able to determine whether an operation has completed + synchronously through knowledge of the assigned meaning of the ```RETURN_CODE```. For example, if ```RETURN_CODE```=100 + for a successful Read() call with a supplied buffer length of 100 bytes, then the client infers the call + completed synchronously. +- If a callback handler is registered then it will receive asynchronous notififications for all API calls irrespective + of whether they completed synchronously or asynchronously. + +CFSTORE API calls that do not return int32_t return values (i.e. exclusions to the foregoing) are as follows: + +- GetCapabilities(). +- GetStatus(). +- GetVersion(). + + +### Recovering for Errors + +CFSTORE clients must check all ```RETURN_CODE``` values for errors and act accordingly if an error is detected. + +Some API calls may return values < 0 as a part of the their normal operations. For example, when iterating over +a list of Find() results matching a wildcard, Find() may return ```RETURN_CODE``` < 0 to indicate no more matches are found + +If an ```RETURN_CODE``` error indicates a system failure the the CFSTORE client should implement the following +recovery procedure: + +- Call Uninitialise() which returns ```RETURN_CODE_UNINIT```. If ```RETURN_CODE_UNINIT``` < 0, abort any further action. + All client maintained state variables (e.g. hkeys) are the invalid. +- Call Initialise() which returns ```RETURN_CODE_REINIT```. If ```RETURN_CODE_REINIT``` < 0, abort any further action. +- Proceed to use CFSTORE. + + +## Known Limitations + +### CFSTORE Is Not An OS System Component. + +Note the following: + +- The notion of CFSTORE being and OS System component supporting +- CFSTORE is not re-entrant. +- CFSTORE does not support concurrent access from multiple clients. +- If the above are required then a abstraction layer above + CFSTORE_OS providing sequential access to the CFSTORE_API (e.g. implementing a queue with a mutex) should be implemented. + This is currently not supported. +- The current implmentation envisages only 1 instance of the CFSTORE per System. + +### Max Storage Data Size Limited by Available SRAM + +Note the following: + +- CFSTORE currently loads all KVs stored in a backend into SRAM. Hence, the backend storage size is limited to the maximum available SRAM for storing KVs. + +# Use Cases + +The design addresses the requirements of the following use cases: + +- CFSTORE Initialisation and Factory Initialisation +- FOTA + +## FOTA Use Case + +- FOTA received new firmware image incrementally in data blocks. +- Firmware image sizes are in the range 32-512kB. +- FOTA may choose to manage an image in blocks e.g. size 16kB chunks + so a 512kB image would be made up of 32 data blocks i.e. 32 x 16kB=512kB +- FOTA is responsible for receiving the 16kB blocks. +- FOTA may have 32 keys in the registry each storing 16kBs. +- A number of CFSTORE keys may be open simultaneously. +- FOTA may be writing incrementally to the key values, as data is received. +- FOTA block data may be stored in memory initially + + +# Configuration-Store Software Architecture + +```C + + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Configuration Store Client | + | e.g. FOTA | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Configuration Store | | uvisor | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | + | Flash Abstraction Layer | | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | | + | Flash Driver Layer | | | + | e.g. CMSIS-Driver | | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + SW + ----------------------------------------------------------------------- + HW + + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | NV Storage Media e.g. Flash | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + Configuration Store Software Architecture + +``` + +The above figure shows the following entities: + +- NV Storage Media. These are the physical storage media. +- Flash Driver layer e.g. CMSIS-Driver. +- Flash Abstraction Layer, portable across the driver layer. +- Configuration Store, the associative KV pair store. +- A Configuration Store client e.g. FOTA. + + +# Configuration-Store Application Programming Interface (CFSTORE-API) + +The main API methods for creating, reading and writing CFSTORE KV are as follows: + +- (*Create)() creates a new KV in the store. +- (*Open)() opens a pre-existing KV in the store. KVs can be opened read-only or read-write. +- (*Read)() permits the random-access reading of the value data from the 'file-like' read location. +- (*Rseek)() permits the setting of the 'file' read location, the offset from the start of the value data where the next Read() will read from. +- (*Write)() permits the sequential-access writing of value data with the start of the write always starting from the beginning of the data value storage area. +- (*Flush)() permits the writing of CFSTORE changes to the backing store. + +Note that the above methods show similarities with a file system interface, but CFSTORE is not intended to be a +file system e.g. CFSTORE does not implement volume management or directory structures required for a file system. + +Additionally, the API supports also includes the following support methods: + +- (*GetCapabilities)() to get the capabilities of the CFSTORE implementation (e.g. whether CFSTORE is synchronous or asynchronous). +- (*GetKeyName)() to get the name of a key given an opaque handle. +- (*GetStatus)() to get the status of an in-progress asynchronous transaction. +- (*GetValueLen)() to get the length of the value data area of a KV pair. +- (*GetVersion)() to get the version of the CFSTORE API. +- (*Find)() queries the CFSTORE for keys matching a search string. The function returns an opaque handle to the first matching search + result. The function can be used to iterate over the entries, supplying a previously returned key handle to retrieve the next, until + the null handle is returned, indicating there are no more matches. +- Initialise() permitting the client to initialise CFSTORE for use and to subscribe for asynchronous event notifications. +- PowerControl() permitting the client to set the power control level.. +- Uninitialise() permitting the client to de-initialise CFSTORE. + +The API is aligned with the CMSIS-Driver Model in which the CFSTORE API functions are presented as `ARM_CFSTORE_DRIVER` dispatch methods. + +## CMSIS-Driver Model + +The CFSTORE is aligned with the CMSIS-Driver Model pattern as follows: + +- The interface is implemented using an `ARM_CFSTORE_DRIVER` structure with dispatch functions for the API interface methods. +- CMSIS-Driver common methods and CamelCase API naming conventions are adopted as follows: + - (*GetCapabilities)(). + - (*GetStatus)(). + - (*GetVersion)(). + - Initialise(). + - PowerControl(). + - Uninitialise(). + +This document refers to invocation of the `ARM_CFSTORE_DRIVER` dispatch methods using a notional pointer 'drv' to the `ARM_CFSTORE_DRIVER` object instance. +Thus drv->Initialise() refer to the invocation of the CFSTORE API Initialise() method. + +See the [CFSTORE low level Design][CFSTORE_LLD] for the detailed specification for function prototypes. +See the [CMSIS-Driver Documentation][KEIL_CMSIS_DRIVER] for more information. + + +## CFSTORE API Function Use Opaque Handles (`Cfstore_Handle_t` hkey) + +In common with a file interface, CFSTORE API functions return an opaque file handle for accessing a particular KV. In general terms: + +- Create() causes CFSTORE to instantiate in-memory data structures (context) for accessing a KV. On success, CFSTORE returns an opqaue handle + to these data structres by setting the `Cfstore_Handle_t*` hkey argument to a valid handle. The client then "owns" the CFSTORE context, which + CFSTORE updates in response to other API calls using the handle. The client returns ownership of the handle to CFSTORE by calling Close(hkey). + This causes CFSTORE to free in-memory data structures associated with accessing the KV. +- Find() causes CFSTORE to instantiate in-memory data structures (context) for a KV matching the key name query string. On success, + CFSTORE returns an opqaue handle to these data structres by setting the `Cfstore_Handle_t*` next argument to a valid handle. + The client then "owns" the CFSTORE context, which CFSTORE updates in response to other API calls using the handle. + The client returns ownership of the handle to CFSTORE in the following ways: + - By calling Find() again but this time supplying the previously returned 'next' handle as the 'previous' argument. + - By calling Close(next). + + +## API Call Sequence Diagram for GetVersion(), GetCapabilities() + +

+ +

+ +The above diagram shows the client-CFSTORE call sequence demonstrating how the client discovers API and CMSIS-Driver versions supported by the API. + +1. The client calls drv->GetVersion() which returns an `ARM_DRIVER_VERSION` structure. GetVersion() is a synchronous function. +2. The client calls drv->GetCapabilities() which returns an `ARM_Cfstore_Capabilities_t` structure + which reports whether the CFSTORE implementation is either: + - Synchronous or, + - Asynchronous. + +### Synchrononous Mode + +In synchronous mode `ARM_CFSTORE_DRIVER::Dispatch_Method_Xxx()` will return: + +- `ARM_DRIVER_OK` => CFSTORE Dispatch_Method_Xxx() completed successfully +- otherwise CFSTORE Dispatch_Method_Xxx() did not complete successfully + (return code supplies further details). + + +### Asynchronous Mode + +In asynchronous mode `ARM_CFSTORE_DRIVER::Dispatch_Method_Xxx()` will return: + +- `return_value` = `ARM_DRIVER_OK` (==0) => CFSTORE Dispatch_Method_Xxx() + pending. Dispatch_Method_Xxx completion status will be indicated via + an asynchronous call to ARM_Cfstore_Callback_t registered with the + `ARM_CFSTORE_DRIVER::(*Initialise)()`. +- `return_value` > 0 => CFSTORE Dispatch_Method_Xxx() completely + synchronously and successfully. The `return_value` has specific + meaning for the Dispatch_Method_Xxx() e.g. for the Read() method + the `return_value` is the number of bytes read. +- otherwise `return_value` < 0 => CFSTORE Dispatch_Method_Xxx() + completed unsuccessfully (return code supplies further details). + +The client registered asynchronous callback method ARM_Cfstore_Callback_t is +registered by the client using: + +```C +ARM_CFSTORE_DRIVER::(*Initialise)(ARM_Cfstore_Callback_t callback, void* client_context) +``` + +The registered callback has the following prototype: + + +```C +typedef void (*ARM_Cfstore_Callback_t)(int32_t status, ARM_Cfstore_OpCode_e cmd_code, void *client_context,ARM_Cfstore_Handle_t handle); +``` + +Before an asynchronous notification is received, a client can check on the +status of the call by calling `ARM_CFSTORE_DRIVER::(*GetStatus)()`. + + +See the [CFSTORE low level Design][CFSTORE_LLD] for the detailed specification for function prototypes. + + +## API Call Sequence Diagram for Initialise()/Uninitialise() (Sync, Success) + +

+ +

+ +The above diagram shows the client-CFSTORE call sequence for Initialising/Uninitialising the CFSTORE for a synchronous CFSTORE implementation +(drv->GetCapabilites() has returned an `ARM_Cfstore_Capabilities_t` structure with the synchronous flag set). + +1. The client calls drv->Initialise() without supplying an asynchronous callback method or client context. +2. CFSTORE returns OK, which in this case means success. +3. Once initialised, the client can call any other CFSTORE methods, as required. +4. After all client operations have been performed, the client calls drv->Uninitialise() to terminate use of CFSTORE. +5. CFSTORE returns OK, which in this case means success. + +See the [CFSTORE low level Design][CFSTORE_LLD] for the detailed specification for function prototypes. + + +## API Call Sequence Diagram for Initialise()/Uninitialise() (Async, Success) + +

+ +

+ +The above diagram shows the client-CFSTORE call sequence for Initialising/Uninitialising the CFSTORE for an asynchronous CFSTORE implementation +(drv->GetCapabilites() has returned an `ARM_Cfstore_Capabilities_t` structure with the asynchronous flag set). + +1. The client calls drv->Initialise() to subscribe to command completion events by supplying the following arguments: + - a callback method `Cfstore_Client_callback()` which will be invoked by CFSTORE for asynchronous notification of command completion events. + - a client context which will be supplied as an argument to the `Cfstore_Client_callback()` call. +2. CFSTORE returns OK, which in this case means the CFSTORE operation is pending asynchronous completion. +3. CFSTORE completes internal initialisation operations necessary to initialise. +4. Once internal initialisation has been completed, CFSTORE invokes `Cfstore_Client_callback(OPCODE=INITIALISE, status, client_context)` + to notify the client of the completion status. The previously registered client_context is supplied as an argument. +5. Once initialised, the client can call any of the other CFSTORE methods. +6. After all client operations have been performed, the client calls drv->Uninitialise() to terminate use of CFSTORE. +7. CFSTORE returns OK, which in this case means the operation is pending asynchronous completion. +8. CFSTORE completes internal operations necessary to de-initialise. +9. Once internal de-initialisation has been completed, CFSTORE invokes + `Cfstore_Client_callback(OPCODE=UNINITIALISE, status, client_context)` + to notify the client of the completion status. The previously registered client_context is supplied as an argument. + CFSTORE will not invoke the callback method again. + +Note this example is the pathological case where all CFSTORE methods return OK i.e. the transactions are pending. +In reality, some calls will be completed synchronous and successfully, indicated by returning a value > 0. + +See the [CFSTORE low level Design][CFSTORE_LLD] for the detailed specification for function prototypes. + + + +## API Call Sequence Diagram for Create() Key (Sync, Success) + +

+ +

+ +The above diagram shows the client-CFSTORE call sequence for creating a KV for a synchronous CFSTORE implementation +(drv->GetCapabilites() has returned an `ARM_Cfstore_Capabilities_t` structure with the synchronous flag set). + +1. The client calls drv->Create(key_name, value_len, key_descriptor, &key_handle) to request CFSTORE to create the KV pair. +2. CFSTORE returns OK, which in this case means the Create() has been completed successfully. +3. The client calls drv->Write(key_handle, data, len) to set the data value in the KV. +4. CFSTORE returns OK, which in this case means the Write() has been completed successfully. +5. The client can call any other CFSTORE methods for the KV using key_handle, as required. +6. When the client has finished KV pair operations, the client calls drv->Close(key_handle) to return the opaque key context to CFSTORE. +7. CFSTORE returns OK, which in this case means the Close() has been completed successfully. +8. The client can repeat operation (1)-(7) to create all KV pairs, as required. +9. Once all CFSTORE KV changes have be made, the client calls drv->Flush() to commit the changes to backing store. +10. CFSTORE returns OK, which in this case means the Flush() has been completed successfully. + +See the [CFSTORE low level Design][CFSTORE_LLD] for the detailed specification for function prototypes. + + +## API Call Sequence Diagram for Create() Key (Async, Success) + +

+ +

+ +The above diagram shows the client-CFSTORE call sequence for creating a KV for an asynchronous CFSTORE implementation +(drv->GetCapabilites() has returned an `ARM_Cfstore_Capabilities_t` structure with the asynchronous flag set). + +1. The client calls drv->Create(key_name, value_len, key_descriptor, &key_handle) to request CFSTORE create the KV pair. +2. CFSTORE returns OK, which in this case means the Create() is a pending transaction. +3. CFSTORE completes internal operations necessary to create the KV pair. +4. Once internal create operations have been completed, CFSTORE invokes `Cfstore_Client_callback(OPCODE=CREATE, status, client_context, key_handle)` + to notify the client of the completion status. The previously registered client_context is supplied as an argument. For status == OK, key_handle + is an opaque handle to the newly created open key. +5. The client calls drv->Write(key_handle, data, len) to set the data value in the KV. +6. CFSTORE returns OK, which in this case means the Write() is a pending transaction. +7. CFSTORE completes internal operations necessary to write to the KV pair. +8. Once internal write operations have been completed, CFSTORE invokes `Cfstore_Client_callback(OPCODE=WRITE, status, client_context, key_handle)` + to notify the client of the completion status. The previously registered client_context is supplied as an argument. For status > 0, the value + of status indicates the number of bytes successfully written. +9. The client can perform other operations on the KV pair using the key_handle. +10. The client calls drv->Close(key_handle) to close the recently created key. +11. CFSTORE returns OK, which in this case means the close is a pending transaction. +12. CFSTORE completes internal operations necessary to close to the KV pair. +13. Once internal close operations have been completed, CFSTORE invokes `Cfstore_Client_callback(OPCODE=CLOSE, status, client_context, key_handle)` + to notify the client of the completion status. The previously registered client_context is supplied as an argument. For status == OK, the + key has successfully been closed and key_handle is NULL. The previously used key_handle should no longer be used. +14. The client can repeat operation (1)-(13) to create, write and close all KV pairs, as required. +15. Once all CFSTORE KV changes have be made, the client calls drv->Flush() to commit the changes to backing store. +16. CFSTORE returns OK, which in this case means the Flush() is a pending transaction. +17. CFSTORE completes internal operations necessary to flush the changes. +18. Once internal flush operations have been completed, CFSTORE invokes `Cfstore_Client_callback(OPCODE=FLUSH, status, client_context, NULL)` + to notify the client of the completion status. The previously registered client_context is supplied as an argument. For status == OK, the + flush operation was completed successfully. + +Note this example is the pathological case where all CFSTORE methods return OK i.e. the transactions are pending. +In reality, some calls will be completed synchronous and successfully, indicated by returning a value > 0. + +See the [CFSTORE low level Design][CFSTORE_LLD] for the detailed specification for function prototypes. + + +## API Call Sequence Diagram for Open()/Read() Key (Sync, Success) + +

+ +

+ +The above diagram shows the client-CFSTORE call sequence for opening and reading a pre-existing key in the CFSTORE for a synchronous CFSTORE implementation +(drv->GetCapabilites() has returned an `ARM_Cfstore_Capabilities_t` structure with the synchronous flag set). + +1. The client calls drv->Open(key_name, flags, &key_handle) to request CFSTORE to open the KV pair in read-only mode. +2. CFSTORE returns OK, which in this case means the Open() has been completed successfully. key_handle is now set to a valid opaque handle to the open KV. +3. The client calls drv->Rseek(key_handle, offset) to set the read location within the value data. The Read() method supports random-access. +4. CFSTORE returns OK, which in this case means the Rseek() has been completed successfully. +5. The client calls drv->Read(key_handle, data, len) to read the data value in the KV. +6. CFSTORE returns OK, which is this case means the Read() has been completed successfully. +7. The client can call other CFSTORE methods (except Write() as this key_handle is a read-only) for the KV using key_handle, as required. +8. When the client has finished KV pair operations, the client calls drv->Close(key_handle) to return the opaque key context to CFSTORE. +9. CFSTORE returns OK, which in this case means the Close() has been completed successfully. +10. The client can repeat operation (1)-(9) to read all KV pairs, as required. + +See the [CFSTORE low level Design][CFSTORE_LLD] for the detailed specification for function prototypes. + + +## API Call Sequence Diagram for Open()/Read() Key (Async, Success) + +

+ +

+ +The above diagram shows the client-CFSTORE call sequence for opening and reading a pre-existing key in the CFSTORE for an asynchronous CFSTORE implementation +(drv->GetCapabilites() has returned an `ARM_Cfstore_Capabilities_t` structure with the asynchronous flag set). + +1. The client calls drv->Open(key_name, flags, &key_handle) to request CFSTORE to open the KV pair. +2. CFSTORE returns OK, which in this case means the Open() is a pending transaction. +3. CFSTORE completes internal operations necessary to open the KV pair. +4. Once internal open operations have been completed, CFSTORE invokes `Cfstore_Client_callback(OPCODE=OPEN, status, client_context, key_handle)` + to notify the client of the completion status. The previously registered client_context is supplied as an argument. For status == OK, + key_handle is a valid opaque handle to the newly opened KV. +5. The client calls drv->Rseek(key_handle, offset) to set the read location within the value data. The Read() method supports random-access. +6. CFSTORE returns OK, which in this case means the Rseek() is a pending transaction. +7. CFSTORE completes internal operations necessary to rseek to read location. +8. Once internal rseek operations have been completed, CFSTORE invokes `Cfstore_Client_callback(OPCODE=RSEEK, status, client_context, key_handle)` + to notify the client of the completion status. The previously registered client_context is supplied as an argument. +9. The client calls drv->Read(key_handle, data, len) to read the data value in the KV at the read location. +10. CFSTORE returns OK, which in this case means the Read() is a pending transaction. +11. CFSTORE completes internal operations necessary to read the value data. +12. Once internal read operations have been completed, CFSTORE invokes `Cfstore_Client_callback(OPCODE=READ, status, client_context, key_handle)` + to notify the client of the completion status. The previously registered client_context is supplied as an argument. +13. The client can call other CFSTORE methods for the KV using key_handle, as required. +14. The client calls drv->Close(key_handle) to close the KV handle. +15. CFSTORE returns OK, which in this case means the Close() is a pending transaction. +16. CFSTORE completes internal operations necessary to close to the KV pair. +17. Once internal close operations have been completed, CFSTORE invokes `Cfstore_Client_callback(OPCODE=CLOSE, status, client_context, key_handle)` + to notify the client of the completion status. The previously registered client_context is supplied as an argument. For status == OK, the + close operation completed successfully, key_handle is null and the previously stored key_handle value is no longer valid. +18. The client can repeat operation (1)-(17) to create, write and close all KV pairs, as required. + +Note this example is the pathological case where all CFSTORE methods return OK i.e. the transactions are pending. +In reality, some calls will be completed synchronous and successfully, indicated by returning a value > 0. + +See the [CFSTORE low level Design][CFSTORE_LLD] for the detailed specification for function prototypes. + + +## API Call Sequence Diagram for Open()/Write() Key (Sync, Success) + +

+ +

+ +The above diagram shows the client-CFSTORE call sequence for opening and writing a pre-existing key in the CFSTORE for a synchronous CFSTORE implementation +(drv->GetCapabilites() has returned an `ARM_Cfstore_Capabilities_t` structure with the synchronous flag set). + +1. The client calls drv->Open(key_name, flags, &key_handle) to request CFSTORE to open the KV pair (read-write access is the default access mode). +2. CFSTORE returns OK, which in this case means the Open() has been completed successfully. +3. The client calls drv->Write(key_handle, data, len) to set the data value in the KV. Note that Write() + only supports sequential-access and that len must not exceed the value_len field specified when the KV pair was created. +4. CFSTORE returns OK, which in this case means the Write() has been completed successfully. +5. The client can call other CFSTORE methods for the KV using key_handle, as required. +6. When the client has finished KV pair operations, the client calls drv->Close(key_handle) to return the opaque key context to CFSTORE. +7. CFSTORE returns OK, which in this case means the Close() has been completed successfully. +8. The client can repeat operation (1)-(7) to create all KV pairs, as required. +9. Once all CFSTORE KV changes have be made, the client calls drv->Flush() to commit the changes to the backing store. +10. CFSTORE returns OK, which in this case means the Flush() has been completed successfully. + +See the [CFSTORE low level Design][CFSTORE_LLD] for the detailed specification for function prototypes. + + +## API Call Sequence Diagram for Open()/Write() Key (Async, Success) + +

+ +

+ +The above diagram shows the client-CFSTORE call sequence for opening and writing a pre-existing key in the CFSTORE for an asynchronous CFSTORE implementation +(drv->GetCapabilites() has returned an `ARM_Cfstore_Capabilities_t` structure with the asynchronous flag set). + +1. The client calls drv->Open(key_name, flags, &key_handle) to request CFSTORE to open the KV pair. +2. CFSTORE returns OK, which in this case means the Open() is a pending transaction. +3. CFSTORE completes internal operations necessary to create the KV pair. +4. Once internal create operations have been completed, CFSTORE invokes `Cfstore_Client_callback(OPCODE=OPEN, status, client_context, key_handle)` + to notify the client of the completion status. The previously registered client_context is supplied as an argument. For status == OK, + key_handle is a valid handle to the open KV. +5. The client calls drv->Write(key_handle, data, len) to set the data value in the KV. Note that Write() + only supports sequential-access and that len must not exceed the value_len field specified when the KV pair was created. +6. CFSTORE returns OK, which in this case means the Write() is a pending transaction. +7. CFSTORE completes internal operations necessary to write to the KV pair. +8. Once internal write operations have been completed, CFSTORE invokes `Cfstore_Client_callback(OPCODE=WRITE, status, client_context, key_handle)` + to notify the client of the completion status. The previously registered client_context is supplied as an argument. +9. The client can perform other operations on the KV pair using the key_handle. +10. The client calls drv->Close(key_handle) to close the KV key_handle. +11. CFSTORE returns OK, which in this case means the close is a pending transaction. +12. CFSTORE completes internal operations necessary to close to the KV pair. +13. Once internal close operations have been completed, CFSTORE invokes `Cfstore_Client_callback(OPCODE=CLOSE, status, client_context, key_handle)` + to notify the client of the completion status. The previously registered client_context is supplied as an argument. For status == OK, the close + operation was successfully, key_handle is NULL and if the key_handle value was previously stored it is no longer valid. +14. The client can repeat operation (1)-(13) to create, write and close all KV pairs, as required. +15. Once all CFSTORE KV changes have be made, the client calls drv->Flush() to commit the changes to backing store. +16. CFSTORE returns OK, which in this case means the Flush() is a pending transaction. +17. CFSTORE completes internal operations necessary to flush the changes. +18. Once internal flush operations have been completed, CFSTORE invokes `Cfstore_Client_callback(OPCODE=FLUSH, status, client_context, NULL)` + to notify the client of the completion status. The previously registered client_context is supplied as an argument. + +Note this example is the pathological case where all CFSTORE methods return OK i.e. the transactions are pending. +In reality, some calls will be completed synchronous and successfully, indicated by returning a value > 0. + +See the [CFSTORE low level Design][CFSTORE_LLD] for the detailed specification for function prototypes. + + +## API Call Sequence Diagram for Find() Key (Sync, Full and Part Walk Success) + +

+ +

+ +The above diagram shows the client-CFSTORE call sequence for finding pre-existing keys in the CFSTORE for a synchronous CFSTORE implementation. +(drv->GetCapabilites() has returned an `ARM_Cfstore_Capabilities_t` structure with the synchronous flag set). The example shows a complete +walk of all the find results. + +1. The client calls drv->Find(key_name_search_string, &next, prev=NULL) to request CFSTORE to find matching KV pairs. +2. CFSTORE returns OK, which in this case means the Find() has been completed successfully. next points to an open key + handle for the first KV with key_name matching the key_name_search_string. +3. The client decides this KV requires no new changes so iterates to get the next match. It sets prev to be the previously return key handle i.e. prev=next. +4. The client calls drv->Find(key_name_search_string, &next, prev) to request CFSTORE to find matching KV pairs. Calling Find() with the open key handle prev + returns the key handle to CFSTORE which closes the handle. +5. CFSTORE returns OK, which in this case means the Find() has been completed successfully. next points to an open key + handle for the second KV with key_name matching the key_name_search_string. +6. The client decides this KV requires no new changes so iterates to get the next match. It sets prev to be the previously return key handle i.e. prev=next. +7. The client calls drv->Find(key_name_search_string, &next, prev) to request CFSTORE to find matching KV pairs. Calling Find() with the open key handle prev + returns the key handle to CFSTORE which closes the handle. +8. CFSTORE returns OK, which in this case means the Find() has been completed successfully. next points to an open key + handle for the third KV with key_name matching the key_name_search_string. + +For the top alternative "Use Case for Full Walk of All Matching Results": + +- 9. The client decides this KV requires new changes and calls additional operations on this KV to change the value data, for example. +- 10. The client repeats operations as indicated by (6)-(8) for other matching keys. +- 11. After the penultimate call to Find() the client sets prev to be the previously return key handle i.e. prev=next. +- 12. The client calls drv->Find(key_name_search_string, &next, prev) to request CFSTORE to find matching KV pairs. Calling Find() with the open key handle prev + returns the key handle to CFSTORE which closes the handle. +- 13. CFSTORE returns OK, which in this case means the Find() has been completed successfully. However, next is set to NULL + indicating there are no more KVs matching key_name_search_string. The iteration has completed. + +For the bottom alternative "Use Case for Partial Walk of All Matching Results": + +- 9. The client has found the desired KV and performs operations on the KV as required. +- 10. To terminate the iteration, the client calls drv->Close(next) for CFSTORE to close the open file handle. +- 11. CFSTORE returns OK, which in this case means the Close() has been completed successfully. + + +See the [CFSTORE low level Design][CFSTORE_LLD] for the detailed specification for function prototypes. + + +## API Call Sequence Diagram for Find() Key (Async, Full and Part Walk Success) + +

+ +

+ +The above diagram shows the client-CFSTORE call sequence for finding pre-existing keys in the CFSTORE for an asynchronous CFSTORE implementation. +(drv->GetCapabilites() has returned an `ARM_Cfstore_Capabilities_t` structure with the synchronous flag set). The example shows a complete walk +of all the find results. + +1. The client calls drv->Find(key_name_search_string, &next, prev=NULL) to request CFSTORE to find matching KV pairs. +2. CFSTORE returns OK, which in this case means the Find() transaction is pending. +3. CFSTORE completes internal operations necessary to find the next matching KV pair. +4. Once internal operations have been completed, CFSTORE invokes `Cfstore_Client_callback(OPCODE=FIND, status, client_context, next)` + to notify the client of the completion status. The previously registered client_context is supplied as an argument. + For status == OK, next is an open key handle to a KV matching the key_name_search_string. +5. The client decides this KV requires no new changes so iterates to get the next match. + It sets prev to be the previously return key handle i.e. prev=next. +6. The client calls drv->Find(key_name_search_string, &next, prev) to request CFSTORE + to find matching KV pairs. Calling Find() with the open key handle prev + returns the key handle to CFSTORE which closes the handle. +7. CFSTORE returns OK, which in this case means the Find() transaction is pending. +8. CFSTORE completes internal operations necessary to find the next matching KV pair. +9. Once internal operations have been completed, CFSTORE invokes `Cfstore_Client_callback(OPCODE=FIND, status, client_context, next)` + to notify the client of the completion status. The previously registered client_context is supplied as an argument. + For status == OK, next is an open key handle to a KV matching the key_name_search_string. + +For the top alternative "Use Case for Full Walk of All Matching Results": + +- 10. The client decides this KV requires changes so it makes other CFSTORE calls to modify the KV. Operations (6)-(9) are + repeated to find and operate upon other matching KVs. +- 11. Operations (10)-(15) are repeated to find and operate upon other matching KVs. +- 12. After the penultimate call to Find() the client sets prev to be the previously return key handle i.e. prev=next. +- 13. The client calls drv->Find(key_name_search_string, &next, prev) to request CFSTORE to find matching KV pairs. Calling Find() with the open key handle prev + returns the key handle to CFSTORE which closes the handle. +- 14. CFSTORE returns OK, which in this case means the Find() transaction is pending. +- 15. CFSTORE completes internal operations necessary to find the next matching KV pair. +- 16. CFSTORE returns OK, which in this case means the Find() has been completed successfully. However, next is set to NULL + indicating there are no more KVs matching key_name_search_string. The iteration has completed. + +For the bottom alternative "Use Case for Partial Walk of All Matching Results": + +- 10. The client decides this KV requires changes so it makes other CFSTORE calls to modify the KV. +- 11. To terminate the iteration, the client calls drv->Close(next) for CFSTORE to close the open file handle. +- 12. CFSTORE returns OK, which in this case means the Close() transaction is pending. +- 13. CFSTORE completes internal operations necessary to find the next matching KV pair. +- 14. Once internal close operations have been completed, CFSTORE invokes `Cfstore_Client_callback(OPCODE=CLOSE, status, client_context, key_handle)` + to notify the client of the completion status. The previously registered client_context is supplied as an argument. + +Note this example is the pathological case where all CFSTORE methods return OK i.e. the transactions are pending. +In reality, some calls will be completed synchronous and successfully, indicated by returning a value > 0. + +See the [CFSTORE low level Design][CFSTORE_LLD] for the detailed specification for function prototypes. + +## API Call Sequence Diagram for PowerControl() (Sync, Success) + +

+ +

+ +The above diagram shows the client-CFSTORE call sequence for setting the CFSTORE PowerControl() setting. The call is synchronous. + +1. The client calls drv->PowerControl(level) requesting the desired power level. +2. CFSTORE returns that the power control level has been set. + + +## CFSTORE Client Increases/Decreases the Size of the KV Value Blob + +In order to increase the size of the pre-existing KV={key_name, value1, len1} to +{key_name, value2, len2} where len2 != len1 then the client should +call Create() on a pre-existing key, supplying NULL for the key descriptor argument +and the new length for the value_len argument. + +The procedure can be realised in the following way (in the synchronous case) to double +the size of a pre-existing KV value blob to hold a duplicate of the data: + +```C + ARM_Cfstore_Handle_t hkey + ARM_Cfstore_Fmode_t flags = 0; + const char *key_name = "mykeyname"; + uint32_t len = 0; + uint32_t value_len = 0; + void* data = NULL; + ARM_Cfstore_KeyDesc_t kdesc; + + // Open a pre-existing KV to find the length and read the value data + drv->Open(key_name, flags, &hkey); + // store key_name and value + drv->GetValueLen(hkey, &value_len); + data = malloc(value_len); + len = value_len; + drv->Read(hkey, data, &len) + // Read() returns bytes read in len. Assume that Read() call has read all the data + drv->Close(hkey) + + // Call Create() with kdesc=NULL to grow the value length to increase + // the blob size. + drv->Create(key_name, 2 * value_len, NULL, &hkey); + // store the data. This first Write() writes bytes 0 to value_len-1 in the + // value blob (sequential-access). + len = value_len; + drv->Write(hkey, data, &len) + // Write() returns bytes written in len. Assume write has written value_len bytes + // write supports sequential access. The second Write() writes bytes + // value_len to 2*value_len -1 in the value blob. + len = value_len; + drv->Write(hkey, data, &len) + // Write() returns bytes written in len. Assume write has written value_len bytes + drv->Close(hkey) + + // de-init + free(data); +``` + +## CFSTORE Client Writes KV Value Blob Size > Available SRAM + +Consider the case where a client needs to write a value blob whose size exceeds the +available SRAM. When writing a data buffer of size N bytes, CFSTORE may require +N bytes SRAM plus some additional overhead for setting up the storage transaction. +In the case that N exceeds the available SRAM remaining, the client can s +split the writing of the value into M writes, where N/M is smaller than available memory. + +In the case the the Write() call fails with return code `ARM_CFSTORE_DRIVER_ERROR_OUT_OF_MEMORY` +then the client should retry the write transaction with a smaller length (less bytes). + +Further, a client of the Write() function should alway check the returned value of the +len argment as this records the actual number of bytes written. CFSTORE may be able to +write a number of bytes less that the total number in the data buffer supplied by the +client. The unwritten bytes should be supplied to a second call to Write(). + + +## CFSTORE Client Changes the Access Permissions of a KV + +In order to changes the Access Control Permission permissions of the pre-existing +KV={key_name, value1, len1, kdesc1} to +{key_name, value1, len1, kdesc2} where kdesc1 != kdesc2 then the client should use the following +procedure: + +- Open the pre-existing KV1 +- Read and store the value length, value data and permissions (if required) +- Delete the pre-existing key KV1 +- Create a new key KV2 with the same name as KV1 but with new permissions kdesc2. +- Write the saved value data into KV2 +- Close KV2. + +The procedure can be realised as illustrated in the following example code: + +```C + /* @brief function to changes the permissions on KV pair + * + * @param key_name + * pre-existing KV key name for which the permissions will be + * changed. + * @param kdesc + * key descriptor describing the new properties including + * permissions. + */ + void myclient_change_kv_perms(const char *key_name, ARM_Cfstore_KeyDesc_t kdesc) + { + + ARM_Cfstore_Handle_t hkey + ARM_Cfstore_Fmode_t flags = 0; + uint32_t value_len = 0; + void* data = NULL; + + // Get KV data from store + drv->Open(key_name, flags, &hkey); + // store key_name and value + drv->GetValueLen(hkey, &value_len); + data = malloc(value_len); + drv->Read(hkey, data, value_len) + drv->Delete(hkey) + drv->Close(hkey) + + // Re-create new KV with same name and new permissions + drv->Create(key_name, value_len, &kdesc, &hkey); + // store key_name and value + drv->Write(hkey, data, value_len) + drv->Close(hkey) + + // de-init + free(data); + } +``` + + +## A CFSTORE GetKeyDesc() Method is Not Supported + +The Create() method uses a key descriptor to request storage properties for the KV pair. +For example, the descriptor may include the following attributes: + +- The NV storage retention level e.g. whether the KV is stored on internal or external NV storage, + battery backed or internal SRAM memory. +- The access control list for the supported groups of owner and other. +- The NV storage security settings e.g. whether the storage should implement hardening against + side channel attacks. + +Associative store APIs often include a GetKeyDesc() convenience method permitting clients to +retrieve the KV descriptor after creation. This is not included in the CFSTORE API for the +following reasons: + +- On Create() the key descriptor specifies options for KV creation e.g. the + descriptor may include both of the following options: + - The KV may be created/stored in internal NV storage with software hardening. + - Alternatively, the KV may be created/stored in external NV storage with software hardening. + + Upon KV creation the CFSTORE may elect to store the KV in internal NV storage. However, over time + internal storage space may come at a premium and CFSTORE may decide to move the KV to a less used + external NV store. The movement of the KV from internal to external storage requires: + - Greater software support (locking against race conditions) to ensure a client always receives + correct information about where the KV is currently stored. + - The storing of the descriptor settings supplied to Create() and the subsequent current descriptor + settings. +- The actual utility of the KV descriptor information to a client after KV creation is limited. The + design philosophy is that the client trusts CFSTORE correctly stores and manages the + KV and that the descriptor attributes should change after creation. + + +## CFSTORE Cancel() Method For Terminating In-Progress Async Transactions is Not Supported + +Associative store APIs often include a Cancel() method for terminating in-flight asynchronous +transactions. This is not supported in the current API to simplify the implementation. All +asynchronous transactions will have associated guard timers to guarantee the termination of errored +transactions. + + +# Contributors + +This document was made possible through the contributions of the following people: + +- Rohit Grover +- Simon Hughes +- Milosch Meriac + + +# References + +* The [CFSTORE Product Requirements][CFSTORE_PRODREQ] +* The [CFSTORE Engineering Requirements][CFSTORE_ENGREQ] +* The [CFSTORE High Level Design Document][CFSTORE_HLD] +* The [CFSTORE Low Level Design Document][CFSTORE_LLD] +* The [CFSTORE Terminology for definition of terms used in CFSTORE documents][CFSTORE_TERM] +* The [Flash Abstraction Layer][FAL] + + +[FAL]: https://github.com/ARMmbed/flash-abstraction +[CFSTORE_PRODREQ]: https://github.com/ARMmbed/configuration-store/blob/master/doc/design/configuration_store_product_requirements.md +[CFSTORE_ENGREQ]: https://github.com/ARMmbed/configuration-store/blob/master/doc/design/configuration_store_requirements.md +[CFSTORE_LLD]: https://github.com/ARMmbed/configuration-store/blob/master/doc/design/configuration_store_lld.md +[CFSTORE_HLD]: https://github.com/ARMmbed/configuration-store/blob/master/doc/design/configuration_store_hld.md +[CFSTORE_TERM]: https://github.com/ARMmbed/configuration-store/blob/master/doc/design/configuration_store_terminology.md +[KEIL_CMSIS_DRIVER]: http://www.keil.com/pack/doc/CMSIS/Driver/html/index.html \ No newline at end of file diff --git a/storage/cfstore/doc/design/configuration_store_lld.md b/storage/cfstore/doc/design/configuration_store_lld.md new file mode 100644 index 0000000000..9139115f36 --- /dev/null +++ b/storage/cfstore/doc/design/configuration_store_lld.md @@ -0,0 +1,17 @@ +# Configuration Store Low Level Design +Author: Simon Hughes + +# Revision History +20160127: first version. + +# API + + +## CFSTORE Client API interface + +The CFSTORE client API interface is represented diagramatically in the following UML digarm + +![CFSTORE_UML_HLD_01](https://github.com/ARMmbed/configuration-store/blob/master/doc/design/pics/configuration_store_hld_api_summary.jpg) + + +The above UML diagram shows the low level design of the CFSTORE API. diff --git a/storage/cfstore/doc/design/configuration_store_product_requirements.md b/storage/cfstore/doc/design/configuration_store_product_requirements.md new file mode 100644 index 0000000000..1614130a78 --- /dev/null +++ b/storage/cfstore/doc/design/configuration_store_product_requirements.md @@ -0,0 +1,107 @@ +# IoT\Product Requirements\IOTPREQ-334: Design of the mbed OS Configuration Store + +The Configuration Store forms a building block of mbed OS. It forms a central repository where configuration for many modules can be placed. This hides the complexity of implementing a similar system from each module owner and it encourages rich configuration interfaces for the developer. + +## Background +Configuration is a common operation in embedded systems. It happens at compile time, and run time. Sometimes runtime configuration is persistent across resets, sometimes it is not. Frequently, configuration data is sensitive, such as WiFi passwords, API tokens, encryption keys, and the like. Some configuration is only accessed once in a while. Other configuration must be changed and accessed very frequently and with very little overhead. + +## Sample Use Cases +Several sample use cases were used to derive the requirements of the Configuration Store + +### Network Configuration +Network configuration varies by network type. As a result, presenting a common interface for network configuration is difficult. Using a pointer to a configuration blob simplifies the Network API and concentrates complexity and knowledge about the network implementation in the network driver and the configuration mechanism in the application. + +Networks need hierarchical configuration. A flat model starts to fail when multiple interfaces with similar parameters are used. Most networks need non-volatile, runtime configuration, but Wi-Fi demonstrates this need the best: configuring a Wi-Fi network on a device requires, at minimum, selecting a SSID and entering a password. These must persist past power cycles. Network configuration needs to support overrides. When configuring a network device, it should be possible to recover old configuration until new configuration is committed to non-volatile storage. A network device should ship with sensible default configuration (e.g. DHCP), but this should be overridden when necessary. + +Network configuration requires many kinds of value: integer (Channel number), string (SSID), binary blob (hashed password). There is an argument for floating point (transmit power), but this can be done via integer and fixed-point. + +### Credential Storage +Storing credentials requires secure access to the storage. As a result, it must be possible to apply permissions to parts or the whole of the tree. Exactly how these permissions work is TBD. + +### System initialization +It is conceptually possible to reduce the number of code versions by using more configuration. For example, clock configuration can be done using the config mechanism. If this is the case, then the permanent config store must be accessible early in the boot process, when clocks are configured. + +It is necessary to provide a list of modules that explicitly require an init function to be called. To make this possible, those functions could be listed, in order in the configuration store. This has some advantages over conventional approaches, such as linker sections, in that it provides a much more readable way to inspect the modules that are being initialized. + +### Resource Management +In the future, a resource manager may be an integral part of mbed OS. In this instance, the resource manager needs in-depth information about how peripherals are connected to clocks and power domains. The Configuration Store should contain this information. + +### Peripheral Configuration +If the system interface API (mbed-drivers) were aware of the Configuration Store, then it would be straight-forward to encode defaults via config. This would allow the interface API to extract application-dependent, but still sensible defaults from the config store when they are omitted. This could be combined with Resource Management to automatically correct for clock scaling of buses or the core. + +## Design Goals +A number of design goals must be met for the configuration store to be used widely. These design goals are brought out of +The configuration store must: + +* hierarchical + * configuration data must be groupable + * groups of configuration data should be handled as a unit +* support multiple degrees of persistence + * permanent + * non-volatile + * volatile +* allow config overrides between persistence levels (volatile being the highest priority and permanent the lowest) +* support multiple sources of configuration + * yotta config + * application configuration + * runtime configuration + * remote configuration (e.g. CBOR blobs returned by a server) +* support multiple kinds of values + * integer + * floating point + * string + * arbitrary binary blob +* be compatible with [yotta config](http://yottadocs.mbed.com/reference/config.html) output + * Any format to which JSON is convertible fulfills this requirement +* globally accessible by any module +* able to enforce permissions on entire branches of the config data +* accessible early +* Low memory footprint for parsing +* Low CPU overhead for data accesses + +## CBOR +The simplest approach to guaranteeing interoperability with yotta config is to ensure that the format of the Config Store is convertible to JSON. There are several options for this, but the most promising is CBOR. CBOR may not be appropriate for an in-memory representation, but it is likely appropriate for both permanent and non-volatile representations. + +Selection of CBOR as an intermediate representation also satisfies the hierarchy requirement and multiple value requirement. CBOR may require a significant CPU/memory tradeoff to be made during parse operations, but there are several mitigation strategies that can be employed. + +## Applying permissions +It may be very difficult to apply permissions to a CBOR tree directly. A review of permission management with the uVisor team is necessary. + +## Configuration Overrides +To ensure that the correct configuration is always used, permanent configuration must be overriden by non-volatile configuration. Likewise, non-volatile configuration must be overridden by volatile configuration. + +The exact method of overrides is TBD. + +An initial assessment of this suggests that it would be feasible to accomplish overrides by using only two layers instead of three. On boot, the non-volatile storage is parsed into the volatile storage area. When a node is deleted and its parent is a non-volatile storage element, the key of the deleted node should be re-parsed from non-volatile storage into the location of the deleted node. + +## Early Accessibility +Configuration Store initialization must occur after C library init, but before static object initialization, so that static objects can access the Configuration Store. It is possible that a limited version of the Configuration Store could be used prior to C library init, but it would need to be written very carefully. + +## Configuration Sources +In some cases, it might be desirable to treat configuration delivered by a server as non-volatile. Changes can be applied locally or requested remotely, but the server is always queried on startup to obtain the configuration data. In general, yotta config will aggregate all configuration data and supply it to the build system in a single JSON file. + +Where credentials are provisioned at time of programming, it might be desirable to supply an alternative method of installing a source of configuration. The method for using this alternative source is TBD. + +# Low Level Design +The Configuration Store is built in three tiers: +* Permanent Storage +* Non-volatile Storage +* Volatile Storage + +## Permanent Storage +Permanent configuration is generated as a CBOR translation of the JSON file created by yotta config. It is linked into the final executable. Parsing permanent storage requires a CPU/memory tradeoff to be made. Indices into the CBOR object can be retained either in RAM or ROM to reduce parsing time at the expense of additional memory. Parsing could be done on-demand or in advance. + +## Non-volatile Storage +Non-volatile storage has no specific format requirements, however reusing CBOR parsing from permanent storage may be a good solution. When a change is committed to non-volatile storage, the non-volatile portions of the Configuration store must be re-encoded for storage to flash. + +## Volatile Storage +There are two possibilities for implementing volatile storage: either a document object model, or a flat key-value store with recognition of prefixes. The document object model will present a familiar interface for web programmers, and occupy less memory than a flat key-value store. Therefore, a document object model is the preferred solution. + +### Objects containing constant data +For most operations, the Configuration Store must copy both keys and values into its own storage. In some cases, it may be advantageous to only retain a reference to external data, such as in cases where external data has been stored in a nonvolatile medium. While this is not an immediate requirement, care should be taken not to prevent this future optimization. + + +# References + +- IoT\Product Requirements\IOTPREQ-334 ![CFSTORE_PROD_REQ_REF_01](http://jira.arm.com/browse/IOTPREQ-334) + diff --git a/storage/cfstore/doc/design/configuration_store_project.md b/storage/cfstore/doc/design/configuration_store_project.md new file mode 100644 index 0000000000..03c6c3897b --- /dev/null +++ b/storage/cfstore/doc/design/configuration_store_project.md @@ -0,0 +1,99 @@ +# Configuration Store Project Documentation + + + +# Feature 1 (FT1): SRAM-backed CFSTORE (Complete) +This feature includes the following: + +- CFSTORE API implementation backed by SRAM (non-persistent). +- Synchronous mode implementation. +- Supported on the K64F target. +- mbed greentea tests demonstrating how to use the API. +- High Level Design Document present. +- Alpha grade code quality (testing giving ~50% code coverage). +- area_0 SRAM initialisation using target.json generated CFSTORE_SRAM_START_ADDR & CFSTORE_SRAM_SIZE #defines rather than malloc(). + + +## Features Not Included in this Feature (Complete) + +This feature does not including the following: +- Integration with the Flash Abstraction Layer. +- Integration with uVisor. + + +# Feature 2: CFSTORE Flash Ping-Pong Alpha (Complete) +- CFSTORE API implementation backed by SRAM and Non-Volatile (NV) storage. +- Flash-jounral asynchronous mode support. +- Flash-jounral synchronous mode support. +- Flash-jounral supported on the K64F target. +- High Level Design Document present. + + +# Feature 3.0: CFSTORE+SRAM with mbedOS Q2 Release (Complete) +- CFSTORE SRAM version ported to mbedOS Q2 Release. + + +# Feature 3.1: CFSTORE + Flash-Journal + mbedOS Q2 Release. +- CFSTORE with Flash-Journal integration ported to mbedOS Q2 Release. + +# Feature 4: CFSTORE + uvisor + mbedOS Q2 Release +- CFSTORE with Flash-Journal integration ported to mbedOS Q2 Release. +- uvisor integration working + + +# Guidance for Submitting Issues + +Here are the guidelines for submitting issues to the configuration-store repository: + +- If you have an issue with configuration-store then please file an issue at github.com/armmbed/configuration-store.git +- The issue should be filed with a stand-alone testcase or sample application that only depends on configuration-store and shows the fault on the target platform. +- The issue should include the following information under separate SUMMARY and DETAILS headings: + +``` + + SUMMARY + ======= + APPLCIATION/Library NAME: + OS VERSION: + TARGET: + TOOLCHAIN: + DESCRIPTION: + MODULE DEPENDENCIES: + + DETAILS + ======= + +``` + + + +# References + +## Useful Documents + +- [KeyValueStorage.md](https://github.com/ARMmbed/device-security/blob/master/KeyValueStorage.md) +- [uVisor README.md](https://github.com/ARMmbed/uvisor/blob/master/README.md) +- [FlashAbstraction](https://github.com/ARMmbed/device-security/blob/master/FlashAbstraction.md) + + +## Useful GitHub Repositories + +- [device-security](https://github.com/ARMmbed/device-security) + + +## Useful References + +- [mbed Coding Standard](https://developer.mbed.org/teams/SDK-Development/wiki/mbed-sdk-coding-style) +- [Security Ref](http://resources.sei.cmu.edu/asset_files/BookChapter/2005_009_001_52692.pdf) +- [Security Ref](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1255.pdf) + + +## Useful Jira Tickets + +- [Configuration Store for mbed OS IOT Product Requirements IOTPREQ-334](http://jira.arm.com/browse/IOTPREQ-334) + + diff --git a/storage/cfstore/doc/design/configuration_store_requirements.md b/storage/cfstore/doc/design/configuration_store_requirements.md new file mode 100644 index 0000000000..e537a47ea4 --- /dev/null +++ b/storage/cfstore/doc/design/configuration_store_requirements.md @@ -0,0 +1,410 @@ +# ENGINEERING REQUIREMENTS + +## Definition of Terms + + +https://github.com/ARMmbed/configuration-store/blob/master/doc/design/configuration_store_terminology.md + +The [CFSTORE Terminology][CFSTORE_TERM] defines terms used in this document. + + +## Secure Key Value Storage\Rationale (REQ-1.xx-SKVS-R) Requirements + +##### REQ-1.01-SKVS-R: +The CFSTORE must provide a non-volatile, hardware-independent secure storage +service that can be used by CFSTORE API clients for storing data owned +by a client security context (uvisor box). + +##### REQ-1.02-SKVS-R: +Clients of the CFSTORE API must be security contexts (boxes) so that security +policies can be enforced. + +##### REQ-1.03-SKVS-R: +The CFSTORE design values simplicity over complexity to promote security by +minimizing the attack surface to secure data. + +##### REQ-1.04-SKVS-R: +The CFSTORE must be implemented as a uvisor secure box. + +##### REQ-1.05-SKVS-R: +The CFSTORE must support the use of Access Control Lists for policing access to +secure data. + +##### REQ-1.06-SKVS-R: +The CFSTORE must support the storage of a {key, value} tuples where +- the key is a zero terminated string of arbitrary length. +- the value is a binary blob of data of arbitrary length + +The {key, value} tuple is a CFSTORE object. + +###### Discussion +A null key (i.e. "" which includes a terminating null) is not a valid because the null string is not a valid security_prefix_name. + +##### REQ-1.07-SKVS-R: CFSTORE Stores Binary Blobs +The CFSTORE must provide support so that other (client) components can implement +more complex storage types other than a binary blob e.g. by +wrapping the underlying CFSTORE {key, value} tuple with additional +type information. + +##### REQ-1.08-SKVS-R: CFSTORE Key Structure as Name Strings +This requirement has been removed as it is a subset of REQ-1.06-SKVS-R [REQ-1.06-SKVS-R]. + +##### REQ-1.09-SKVS-R: Key Creation and Ownership Part 1 +CFSTORE keys must be owned by the security context. A security context (box) +is identified by a unique security_name_prefix and this identifier +must be used when the key is created. CFSTORE must support the use of the +security_name_prefix as the leading substring of the CFSTORE key string, in which +case the key_name_prefix is the security_name_prefix and identifies the +owner of the key. + +##### REQ-1.10-SKVS-R: Security Context +In order to create objects in the CFSTORE, a security context (box) must have +a security_name_prefix. + +##### REQ-1.11-SKVS-R: CFSTORE object +This requirement has been removed as it is a duplicate of REQ-1.10-SKVS-R + +## Secure Key Value Storage High Level Design (REQ-1.2.xx-SKVS-HLD) Requirements + +##### REQ-1.2.01-SKVS-HLD: +The CFSTORE must be able to detect the available types of storage media +in the system and report associated storage media attributes. + +##### REQ-1.2.02-SKVS-HLD: +The CFSTORE may report the following storage media data retention level attribute, +when available: +- only during device activity +- during sleep +- during deep-sleep +- battery-backed, device can be powered off +- internal non-volatile memory +- external non-volatile memory + +##### REQ-1.2.03-SKVS-HLD: +For a particular storage medium, the CFSTORE may report the following device +data security protection features, when available: +- no security, just safety +- write-once-read-only-memory (WORM) +- against internal software attacks using ACLs +- roll-back protection +- immovable (for internal memory mapping, to stop relocated block to move). + This attribute must only be set provided: + - the device memory is mapped into the CPU address space + - access is only granted to specific CFSTORE API system clients e.g. FOTA, + DMA. +- hardening against device software (malware running on the device) +- hardening against board level attacks (debug probes, copy protection + fuses) +- hardening against chip level attacks (tamper-protection) +- hardening against side channel attacks +- tamper-proof memory (will be deleted on tamper-attempts using board level + or chip level sensors) + +##### REQ-1.2.04-SKVS-HLD: +The CFSTORE may be used to implement KV storage protection services +(e.g. flash image roll-back protection, confidentiality) for off-chip +(external) storage media (e.g. SPI/I2C/NAND Flash). + +##### REQ-1.2.05-SKVS-HLD: +The device data security protection immovable attribute may only be set + + +## Secure Key Value Storage\High Level API Description\Key Value Storage (REQ-3.1.xx-SKVS-HLAPID-KVS) Requirements. + +##### REQ-3.1.01-SKVS-HLAPID-KVS: CFSTORE Global Key Namespace +The CFSTORE must implement a system global hierarchical tree name-space for +keys. The namespace is shared by all software components operating within +the system. Examples of key names include the following: + - 'com.arm.mbed.wifi.accesspoint[5].essid' + - 'com.arm.mbed.wifi.accesspoint[home].essid' + - 'yotta.your-yotta-registry-module-name.your-value' + - 'yotta.hello-world.animal{dog}{foot}[3]' + The key name string forms a path where 'Path Directory Entries' are + separated by the '.' character. + +##### REQ-3.1.02-SKVS-HLAPID-KVS: CFSTORE Key Name String Format Max Length +For CFSTORE keys The maximum length of a CFSTORE key is 220 characters excluding +the terminating null. + +##### REQ-3.1.03-SKVS-HLAPID-KVS: CFSTORE Key Name String Allowed Characters +CFSTORE key name strings must only contain the following characters: +- [a-zA-Z0-9.] +- '-' + +##### REQ-3.1.04-SKVS-HLAPID-KVS: Key Name Path Directory Entry List {} +Path Directory Entries may have list indicators designated by {}. For +example, + - 'com.arm.mbed.wifi.accesspoint{5}.essid' + - 'com.arm.mbed.wifi.accesspoint{home}.essid' + - 'yotta.hello-world.animal{dog}{foot}{3}' +In the above the list item specifiers are respectively: + - '5' + - 'home' + - 'dog', 'foot, '3' +As list item specifiers are part of the key name string, the list item +substring must be composed of allowable characters. + +##### REQ-3.1.05-SKVS-HLAPID-KVS: CFSTORE Global Key Yotta Namespace +The key name prefix 'yotta' is reserved for use by the yotta module. Other +prefixes may be reserved. + +##### REQ-3.1.06-SKVS-HLAPID-KVS: CFSTORE Key Names Mapable to Common OS Filesystem Name +The CFSTORE key names must be mappable to common OS Filesystem file names. This requirment +permits a CFSTORE backend to map individual KVs to files with the filename being the +key name, for example. Supported OS Filesytems must include DOS, NTFS, EXT3, EXT4 and +JFFS. + + +## Secure Key Value Storage\High Level API Description\Access Control Security (REQ-3.2.xx-SKVS-HLAPID-ACS) Requirements. + +##### REQ-3.2.01-SKVS-HLAPID-KACS: +The CFSTORE must enforce security policies as defined by Access Control Lists. + +##### REQ-3.2.02-SKVS-HLAPID-KACS: CFSTORE Key Creation Part 2 +The CFSTORE objects must be created with an ACL. The ACL is attached to the object +so that access permissions to the KV data can be enforced. + +##### REQ-3.2.03-SKVS-HLAPID-KACS: +The CFSTORE Access Control Lists must support the groups for 'owner' and 'other', +with optional permissions read, write and executable. The owner group +permissions describe the access permissions of the owner of the object. The +other group permissions describe the access permissions for entities other +than the owner. The writable and executable permissions are mutually +exclusive. + +##### REQ-3.2.04-SKVS-HLAPID-KACS: +A CFSTORE API client must be able to query the CFSTORE for a list of KV pairs provided +the KV pair ACL permissions allow the client access. The query result must +contain all client owner KVs. The query results may include non-client +owned KVs provided the other group permissions grant access. + + +## Secure Key Value Storage\API Logic\Finding Keys (REQ-5.1.xx-SKVS-APIL-FK) Requirements. + +##### REQ-5.1.01-SKVS-APIL-FK: Key Searching/Finding Scoped by ACL +The CFSTORE must provide an interface to query for active keys in the global +storage. The query must: +- return results based on the ACL provided by the client +- support wild card searches using the '*' character. The '*' character + can occur at most once any point in the search string. For example: + - com.arm.mbed.wifi.accesspoint*.essid + - yotta.your-yotta-registry-module-name.* + - yotta.hello-world.animal{dog}{foot}{*} + - yotta.hello-world.animal{dog}{foot}* + - yotta.hello-world.animal{dog*3} + +##### REQ-5.1.02-SKVS-APIL-FK: CFSTORE Global Key Namespace Reserves Character '*' +The character '*' is reserved in the CFSTORE global key namespace. The current +functions of this character as follows: +- a wild card character in searches. +- a wild card character used in the delete operation. + + +##### REQ-5.1.03-SKVS-APIL-FK: Key Searching/Finding Resume +In order to support the return of a large list of key query results (perhaps +exceeding the ability of the caller to consume in a single operation), the +query interface must support the ability to restart/resume the query to +retrieve a subsequent set of records to those already received. + +##### REQ-5.1.04-SKVS-APIL-FK: Key Searching/Finding Internals (key versions) +The CFSTORE must be robust against incomplete, corrupted or aborted write +operations to NV store caused for example, by loss of power during the +write. + + +## Secure Key Value Storage\API Logic\Get Storage Information (REQ-5.2.xx-SKVS-APIL-GSI) Requirements. + +##### REQ-5.2.01-SKVS-APIL-GSI: storage_detect +The CFSTORE must provide an API so that clients can discover the CFSTORE storage +capabilities. Storage capabilities may include: +- write-block sizes for O_BLOCK_WRITE mode (sequence of writes into the + same value) +- supported Data Retention Levels +- supported Device Data Security Protection Features + +##### REQ-5.2.02-SKVS-APIL-GSI: Minimal Storage Support +The CFSTORE must provide minimal storage media services including the following: +- SRAM/SDRAM memory with no security guarantees. + + +## Secure Key Value Storage\API Logic\Creating & Opening Keys for Writing (REQ-5.3.xx-SKVS-APIL-COKFW) Requirements. + +##### REQ-5.3.01-SKVS-APIL-COKFW: storage_key_create with O_CREATE +CFSTORE keys must be explicitly created using 'storage_key_create' with the following +parameters: +- security ACLs (owner & others) +- the intended retention levels (bit mask to allow caching if needed) +- indicating the expected Device Data Security Protection Features +- the key pointer (zero-terminated) +- the value size +- alignment bits of the value hardware address (only for O_CONTINUOUS). + The structure start is aligned accordingly to ensure that the value + blob is aligned on a multiple of the 2^alignment_bits +- mode flags (O_CREATE, O_CONTINUOUS, O_LAZY_FLUSH, O_BLOCK_WRITE, + O_ALLOCATE_AT_OFFEST). + - O_CREATE. The call will create the KV pair. If a + pre-existing KV with the same name is present in CFSTORE then the + storage_key_create will fail with FILE_EXISTS. + - O_CONTINUOUS. The KV value will be stored in a continuous range + of hardware addresses. + - O_LAZY_FLUSH + - O_BLOCK_WRITE + - O_ALLOCATE_AT_OFFEST + +###### Discussion +The following should not be included in the API (e.g. because the principle of encapsulation is broken, or specific to a particular clients requirements): +- optionally the offset address (restricted feature, ideally only granted + to the FOTA security context) + +##### REQ-5.3.02-SKVS-APIL-COKFW: storage_key_create without O_CREATE +Pre-existing CFSTORE objects can be updated by calling the storage_key_create +API with the O_CREATE not set. +In case a pre-existing key is updated (O_CREATE not set) and the previous +ACL allows writing to the caller: +- all key-value fragments of the previous key are set as inactive +- the new key is allocated (in fragments if permitted) +- all permissions and settings are copied from the previous key +- the version number is incremented compared to the previous key (see + REQ-5.3.05-SKVS-APIL-COKFW). + +##### REQ-5.3.03-SKVS-APIL-COKFW: O_CONTINUOUS for executable objects +CFSTORE will manage an executable KV as though the mode O_CONTINUOUS flag +is set. + +##### REQ-5.3.04-SKVS-APIL-COKFW: O_CONTINUOUS for non-executable objects +A CFSTORE client may specify the mode O_CONTINUOUS flag for non-executable +objects. + +##### REQ-5.3.05-SKVS-APIL-COKFW: Versioning of KVs +KVs in NV storage should have version numbers. When writing an updated +KV (with changed value data for example), a new copy of the KV data with +updated version number should be written to NV store. The earlier version is +left as a fallback copy of data that may be deleted at some point in time, +when the NV storage is required, or more than a certain number of +versions is exceeded. + +## Secure Key Value Storage\Updating and Settings and Permissions (REQ-6.1.xx-SKVS-USP) Requirements. + +##### REQ-6.1.01-SKVS-USP: +CFSTORE does not permit the updating of KV pair permissions or settings. This is to promote security. + + +## Secure Key Value Storage\Updating and Settings and Permissions\Deleting Keys (REQ-6.2.xx-SKVS-USP-DK) Requirements. + +##### REQ-6.2.01-SKVS-USP-DK: +Only the owner of the CFSTORE KV pair can delete the object. The wildcard +'*' character can be specified to delete an owned subtree of the CFSTORE +global key namespace. + +##### REQ-6.2.02-SKVS-USP-DK: +This requirement has been removed. + +## Secure Key Value Storage\Updating and Settings and Permissions\Opening Keys for Reading (REQ-6.2.xx-SKVS-USP-OKFR) Requirements. + +##### REQ-6.3.xx-SKVS-USP-OKFR storage_key_open_read +CFSTORE objects must be explicitly opened with storage_key_open_read(key_name) +before operations on the KV pair can be performed. The KV must +pre-exist in the store before it can be opened. + + +## Secure Key Value Storage\Updating and Settings and Permissions\Seeking in Key Values (REQ-6.3.xx-SKVS-USP-SIKV) Requirements. + +##### REQ-6.4.01-SKVS-USP-SIKV storage_value_rseek +The function storage_value_rseek can be used on a opaque reference to a KV +to change the read position inside a value i.e. the storage_value_read +method supports random-access. + +##### REQ-6.4.02-SKVS-USP-SIKV storage_value_write has no write location +storage_value_write does not support the concept of a write location that can be modified i.e. random access write support is not supported. + +##### REQ-6.4.03-SKVS-USP-SIKV storage_value_write sequential-access +storage_value_write supports sequential-access. Random-access to the value data is not supported. + + +## Secure Key Value Storage\Updating and Settings and Permissions\Writing Keys (REQ-6.4.xx-SKVS-USP-WK) Requirements. + +##### REQ-6.5.01-SKVS-USP-WK +CFSTORE KV values can be written in one or more operation. For example, if a value blob has size n bytes, then 2 n/2 byte write operations have the following effect: +- the first write sets bytes 0-n/2-1 in the value blob. +- the second write sets bytes n/2 to n-1 in the value blob. +This may require a write position to be maintained, for example. The ability to seek the write location must not be supported. + +##### REQ-6.5.02-SKVS-USP-WK +This requirement has been removed. + +##### REQ-6.5.03-SKVS-USP-WK +The KV stored in NV store should have an associated CRC so that: +- the integrity of the data can be protected +- the corruption of the data can be detected e.g. if power is lost during the flush to NV store. +The CRC should be stored at the end of the KV so it is written last. The CRC write transaction is termed "finalising" the KV. + +##### REQ-6.5.04-SKVS-USP-WK +KVs that have not been flushed to NV storage should be flushed at reboot time. + +##### REQ-6.5.05-SKVS-USP-WK +KVs may be fragmented into several smaller pieces for NV storage. In the case that a KV is fragmented, each fragment should have a an associated CRC as per REQ-6.5.03-SKVS-USP-WK. + +##### REQ-6.5.06-SKVS-USP-WK +A KV value or KV fragment can only be finalised by its owner. + +##### REQ-6.5.07-SKVS-USP-WK +Closing of a written KV in the finalization of all open value-fragment for that KV. + +##### REQ-6.5.08-SKVS-USP-WK +Flushing of the KVs causes finalisation of the store. + +##### REQ-6.5.09-SKVS-USP-WK +Non-finalised object must not be readable. + + +## Secure Key Value Storage\Updating and Settings and Permissions\Executable Keys and Firmware Updates (REQ-6.6.xx-SKVS-USP-EKFU) +Requirements. + +##### REQ-6.6.01-SKVS-USP-EKFU +To facilitate modular firmware updates in future, executable keys are supported by the API + +##### REQ-6.6.02-SKVS-USP-EKFU +For immovable & O_CONTINUOUS keys, the absolute hardware address and the relative address of a value key can be queried using the API +This API feature is restricted to boxes that require that function (FOTA, DMA). By keeping most key-value pairs movable the flash can be de-fragmented. + + +## Secure Key Value Storage\Miscellaneous (REQ-7.1.xx-SKVS-M)Requirements. + +##### REQ-7.1.01-SKVS-M +The CFSTORE will implement a C Language interface. + +##### REQ-7.1.02-SKVS-M +The CFSTORE does not support hot-pluggable storage devices e.g. SD flash. + +##### REQ-7.1.03-SKVS-M KV Value Data May Not Fit into Available (SRAM) Memory. +CFSTORE must be capable of writing a KV to NV backing store where the value +data length >> size of available SRAM. This requirement therefore implies +that CFSTORE must support the case that the whole of the KV value data cannot all be +resident in SRAM memory at one time. + + +# Outstanding Issues With This Document + +##### REQ-5.3.01-SKVS-APIL-COKFW: storage_key_create with O_CREATE +- How does the offset-address work? +- What is the definition of O_LAZY_FLUSH +- What is the definition of O_BLOCK_WRITE +- What is the definition of O_ALLOCATE_AT_OFFEST + +##### REQ-5.3.02-SKVS-APIL-COKFW: storage_key_create without O_CREATE +- To which "previous ACL" does this requirement refer? +- Is an implementation internally creating a new copy of the key? + +##### REQ-6.5.01-SKVS-USP-WK +- Are there any additional requirements arising from these statements? + + +# Contributors + +This document was made possible through the contributions of the following people: +- Rohit Grover +- Simon Hughes +- Milosch Meriac + + +[CFSTORE_TERM]: https://github.com/ARMmbed/configuration-store/blob/master/doc/design/configuration_store_terminology.md diff --git a/storage/cfstore/doc/design/configuration_store_terminology.md b/storage/cfstore/doc/design/configuration_store_terminology.md new file mode 100644 index 0000000000..91526db06f --- /dev/null +++ b/storage/cfstore/doc/design/configuration_store_terminology.md @@ -0,0 +1,34 @@ +# Configuration-Store Terminology + +## Defintion of Terms + +###### ACL +Access Control List + +###### CFSTORE +Configuration Store + +###### FOTA +Firmware Over The Air + +###### HLD +High Level Design + +###### KV +Key Value Pair, also represented as {key, value} + +###### Key Name Prefix +This is indentical tot he Security Name Prefix. + +###### LLD +Low Level Design + +###### NV +Non Volatile + +###### OS +Operating System + +###### Security Name Prefix +If a client security context (uvisor box) needs to create CFSTORE KV entries, it must have a (mandatory) key name prefix. This is called the security_prefix_name. + diff --git a/storage/cfstore/doc/design/configuration_store_test_plan.md b/storage/cfstore/doc/design/configuration_store_test_plan.md new file mode 100644 index 0000000000..166b1138de --- /dev/null +++ b/storage/cfstore/doc/design/configuration_store_test_plan.md @@ -0,0 +1,64 @@ +# Test Plan + +This document describes the test plan and test cases for the configuration-store project. + +# x86 Testing + +The x86-linux-native target is supported and the tests can be run on a linux PC, for example. + +# FRDM-K64F-GCC Testing + +The frdm-k64f-gcc target is supported and the tests can be run on the k64f target. + +# Overview of Test Cases + +## Access Control List() API Tests + +Currently, the ACL tests are not implemented as the uvisor integration is still outstanding. + +## Close() API Tests + +These test cases are to be documented. + +## Add and Delete() API Tests + +These test cases are to be documented. + + +## Create() API Tests + +These test cases are to be documented. + + +## Find() API Tests + +These test cases are to be documented. + + +## Flush() API Tests + +These test cases are to be documented. + + +## Misc API Tests + +These test cases are to be documented. + + +## Open() API Tests + +These test cases are to be documented. + + +## Read() API Tests + +These test cases are to be documented. + + +## Write() API Tests + +These test cases are to be documented. + + + + diff --git a/storage/cfstore/doc/design/pics/cfstore_hld_seqdiag_find_full_part_async.png b/storage/cfstore/doc/design/pics/cfstore_hld_seqdiag_find_full_part_async.png new file mode 100644 index 0000000000000000000000000000000000000000..d8c48e6ab363e0811b2f2418c12892fd58a87761 GIT binary patch literal 102517 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

Xn<)hs_3}%7I*?y=)q49LKV(g@R#sDMODG~g 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%0AK*%bTn%+whYF84@97)X*6OllRqA+i9bF# z53d0LDFj4pe;Z5>%OMxBOz6WWxqr*XTgCSK$k$l`K|h`q+i{$41qk>3cxH8A<&Cjm z)5bONe_-@OA?iATQ~}V%2y5DS3_F3K>`i!BX!%!fw6a6hsiLZC;B*lR0b&`kuA=Dd zJ979iu(K=&QG$hVz zFkSzdKcf?+T*GM?7gR~Q316den(jR`C{518?=_Cw%|C35PveIcn3JM(yd-afBP&19 zOl6pXq-xe4__e7JzWHR?8&pRAjZexeWGodG?tK~3w>~RyHdV<)|3ixTN_bb!d@J4F z7WFtJQ71GuWp}=yiHlQQquQhAV^tB8v6}~Tv~NX6^Ua+*mm@8ty6)YMw!!*LrFP(@ zotQY@h?&MPE<*n7HE+ty%xnaru&NIqKD6fD&umnqs0F~S{_5)L+{IpA3kwSh*xP{) zWdPRj{e;qjed*E@)wlfpi=bwkzPxakWoKu5Pe6BzaYJOQy2I^&K$vqqwWY1QH(m(- z>=t`mr_uabLYgO%nFsLEn+R>tM|7;R_YJgKa6@a`ga_M+lw;^KFx_~_bsx=G|nsAy3|jrh*-UQuX1ZzG|AGU$r2?FX){vJ~oP4h;`? zqHTYJYFOI|%=ep$^>&;4@nnGZnp7Nmf8~1F_Z|Q|&`7k*S|XE+5M%c4Gm}O_SNUNm3R9KY~K6;(`K34#UNsrGH|=CNj2ry(D^2@b?X=3P<+4% z=LOD&D;=mS#s>%MZxFVTk-Yr;hhbq`YX7>H(5QpbwKnxw8f&JBuD0&`Vsm~LD{tQO zj*e1vJ84^3nTg0k6>4C8`VDYgln}-E6!Ec!;)>`*9kZpRnx_pP>gw&5t2b=e5P-rD zOA{G$m7BIBuy$q(w$g52U8rgBuMUt5h``&Co|XWP?3mMXib+!$x-^gT%*f$j{)wl< z%_ns%q>~Pd_a^N?O)Cs+y&i1v{(bwHNMD%edHuS5saT!R=FJ|cfIp%ElEj?FHqMh5 zitVw5F)mu}+?VEiD4u>GazxR0aZfUyxNdC+l&@SwVK*dqFqil8+9zqnH3YBRllYKnAK6mBJ4naw>ZEyc`E^eqK+c`Kvjw zYr#SA2^QdBcFuTPROAM&R4~rU5RH6T`M|cfY?Gwd7w>Ih69YM!ZjtH`Km$enfaUyVcGyAiUJGWCYWXP6 zrPZxWO*b!DBUODWQCC~rjH&S(7B5h*$DFUCQL~~xd%6AAyH>NEO*Q9U$~GF{I}aZ| zk>&ElrLoLQ#Q@RJCx56__(`quEa1Fgo0Oh@7fajPadoftkVIyZ()m+mKVr%QT>S3b z5!t@oA6KT5nE_%{oRF#9Tl?jWWdErUF`4ar{QOkJ`Zt{YBPQlsx=T~PEH3rdl9ac{ zg8JRx*QY!XGxhGV)44xSqTTmY>9G6ujXRLnkTvi-sqJKesmH`o_8U%B&hkG`E9=d4oc&R*|l*;=|8D;mtJ)+9(j6L;VC$WS*hUxlmR z$L*W;9u%tYHR?9pkZDcLlxvdQUSLbEb7i-dPUl+G0ic5?iewHkQUVx!RWuKU9% zW9k0NXm@dX`g;%>GHWjX^Jn_4?rtOLM zPCyI~?f5K2U&@Xz4Q{l2R{AP*jqpvw1w|VyyowDkM|k7)wJY^F^k9w9TmQepz;1g1 zad&sOclWi%qhMiKf@ee!TkHD&9!Og*?c$QPqrOF;bXPXb`qB zWF=fYJacfV>_?c4dVNXBK~h=4{J{XxFN6~qJg~z$v+^@WPhb`H!U${9^kDnYcvJ)} zxMs+gV&|G*Nj{=b+MjTKpT%%d}1B z!R0@0d*gg5v2JqtST%1EUxp|cWKMmX!Q@1VBejMQbXJe<2 zxwC3*QOBp{{sw{-E9%tVN3_nR>I?|qQz(dNxDLoCIdru|+XF6Y1$>f@bkhV3do>8f z`FRpuFPy^+9CtL`2KBVW`wrZzUdSL=!OF@iP!YbO>UM&eBKjy2??9`WZ2!i;M+@Ha z_J>hD2DSt9W36JZSgM*v;9-$az|YT*ay?;p@hXQ%mKYh5{--tBETFt7@TIv$Me_iH zFL5v~W&W3zX9E#@LhE@ZZN1SDRzkI&Cv?K7B~`!C_^Et{EXx4$0*2t^jUl?-pwgj{vy5CYGoUCv;7A}7Cc;}G zX1&Z*Z9(BV7ZX<&F-{ZHsAk zgj0uN6R;K@TnCq=`_pHU{sO1cVHK52_piwzn+xfXW zM*n(d>mgqJGOgHN*VgR>9>VNgxL)c7Gy#wPkQNiG=|1)p8-gT=uAEid1;>MXRC_i6A@w4F?RJTIH!Z!hm ziFdQfI;As5ZOeBY0G5O=D=aD!1uVgkfHK$fdGdFy8tb7DYm+v3K31d97zNn7oG~#m z@wu;0iP4LkP32&T-IYUH&-P3&-nw8c-ns)icvm*_eJx+}YIFIY@-#PV?78U~c;PU* z;on@Lv9UJI0q;GNvM^5*6y$aNI&oyURd)@vdZYokn%RQF-Q>0&YN8om(JhIkW`moa zor}eFm7tMgz$%y&4b%%FH+CbqulIss-+$nMElOA23>zK-G<`o|Q7JHB2HtdIwd5Y( zCy|jYu(l{OoKR!wt`7Ia+I(aSbi^8Tt`FL51pewm=4@_eW)HbTGjNsJx!7PFMypnt zYbF;gaC3LpGAm1YF4<%7(kUz>WA^6|r?7AvkJR*t)NIa-$c%Y4sQLi)2!5&45^;eh zW@Za+iY+CzwY4-=2OdOzZ;M6B_W_~yYHDgCvEn9t49jPG6wQv zEl#V_3GTD4Q~N{kV8Th+ieTN#XOGKP9LbQ=(N!H3_cI0-vd7L&3>`?Io+hX`n$blJ zMMRM03uN~`g~#`<;zk;!i@3iFhuCme zaa3vB&_0k;=vZcPle6V?1oh>2?u11~M#@|5Gu?z~pTkYIOW-0uC3Bk?d=kKeka<$$ zq4GFAos9w7`(0Nj>~V7$h|6ixzaS^~SHUnvJPJP7kLtfvSxC9sz#x32)owg1ihdqZ z`2LIx+NT)|q!L?tBW5H2POYy3qraF}TLjDYw%7Kmmb@#3WRR#6zx_t3&6liii%BC% zxsL#^QjZEk`v3^~1&O24U=Wc*f~Jd8!xs$zqL4X4apSET7qH6b+O`FiGF$=8c*10O zCuen(!hTeW9vH^hVC+0}NKmI~hsI!vVG~XpfvA*E%UmzuATEwm!7&LfurwCrnyk@| zpmdM{vA#Nt$f&4109|gNF6C})biA)I zo)g1;jc&xe!Imigp;3=lN{Rz$(hgEV#^emBW321cSp3ur$Z7)59uJy+aqrKNwWsOV zGxWHld#jOKdFSqK(|)$gz)E1NxW%}8_wFkk9`Jiy1ys2B!uPJ-j9vgA_;n_|Rqqc*iti306hc>s)&4CQGR|;^ftYSOU3|sG4N4L z@9oVPn=Fx?l?5xJY47pj@3y9SBlQYsrMTBdqPM8VT^!8(5+11 zx_2SyI=^*YHVk*pt#;8dG4oyVU{j@QHs8OU zvQ2h}mG4OvJPvWZj?-nu*0;mozO~^1EydgR97y$L(!mJ^@%zAlNH=U4?U3Z!1N?i~ z1gXB)&SeZ&^soD~K}^K%TL^R{b!_j`2i^XV<2rz{0kG_7pEdE9x$)6g1d##J0Ksg^AOR`g8g z(z~U`f3UJXfK(6@rU;RVoz#6MN^IoF*OO|Rnh#M$i-$U4nA>bKb8|$M8!?3nu@)&f z9QDjPS=r~s6BxEGr=r3FgoI`7TB{!iU$1Er)9^O+NVo7#+0Y+ifE7BH{!RPC&y(dZ z>AFuisQK8fuFO-{URf&4ax+!AZcO2!fKO6$1ecNxFey5C5BYy-Op9mEv!ep~6Bo4| zcrgVQY41DEj^eXw!IQAcbEkh5+?lBqzGyOY?|=MpqW{MV`u{^=`)_>qh`p3+ZLXn+ zgA|6xvt+#49Qt>J(9K7WuaJzEC1cr7{yihCy1Lq4>Msp%?l;Cs%IG-{jv9 za0AjdL@)PzKCB%JLcsvNI>Qx8p_g@aE7AE6o>8;#_qC=UXQ~DWpxJp?4|rX1)q~`t z&A?q-Jwq0gzg_z=T+AFG-lpxBq@2UKzu)E@ZchxfV8a?#GMfl1s?28W)W1=DdS zWGkcOWt{9NC==ZuSS~~lPnH;h%OOD_X)PK@78sE63}!Nbub!?wTGt7%n+#y|X3-78 zq4N~f4=IO?lh~oiJ+$`OwO;Q!ys)Q8wqGsl#D-ja*r$>uR>b8St)#~8G#l9G&Nl%- zQZXG}R93cmWb)!<=S6BoGO~45+tw8m&b;vV-&?_PqDnneSXgKSmXNy`Ec{XiKH}2j z0I#yz@94Zkb!=>6a*G@3LAceFn~|7C+4c@K>YCPI2=+@4bwlGK{_@3(5sY2)!J*Ir zPQM&1yAL;&Yz!GlGF9r#1Xt*1Rr0uPXUn_mKE0;Jcm}-f+ z$GJR`H*c+kT`x!C_G83*ze6?(Fhma=wZ^zKb0&s#JPkgc*7f6{ zxWZG->wKUk+aTX;^I8D$u+JM`i;0oxQ3xOwNKN4(XQXSvpY>7xoHH`G4z5x2Z4M(<7T0ib_M+XNcSb}x(8tUptxl??6QG4Uzr!q%T4;LYG zk8N;#WJE|*v}(i&3Uwz;7w)aaCt^w8h-!C(e2DaU9~3#>8{6ROKLPCU=2PEKxWCI_ z=nmi>#n7@U5E*|C0HZC(64T~sE0_7UP(Cp;v%&J7owEy4r{sN&lLElEVqn%f)WU!I zVzk9hV23?l--#JoWsx8QeFgN6t3peIC2v7JNJXin;DNK{B;|Rx4R9=N49Fw$0q}a@ z*XYCVLh-*UP|*rFwg?GY|j~0dMJ$2mKE=HFODISN)t$$PZ1|L zs%A21&K^=7NOZ`cu`8e|j@H=r#HP(;05@A*JD-8rz8MVUf2|i5Mk0ZiE0AZFD)eQH z-2MdfSIzdZIMFD8EB@kyd0P_nF0&!#pxCR|){x87)ILN*-<4L01rNH91;-QG0s&79J)0@U;VSa%`bj-P~p| zKs{bXhSW*4!<2AAlM3889e<<9DtN}vAonlGZY>I9BnGW$M2pwwBhWJuweo^p-Hm6+ zUo12M4iXs~JLe2DWHi&II!a+-U(G!Pk*6Ggc_Ft4_c)G-StOE2DMPI}NhHzY&0yU2 z_orq-KeTY!$FU_>q@tI*GJ_dsm`nI;-apeDc7880)K&4aBO&Iv+e2n_WaQJkYZ*lL zFm_p6Csgp7wAuW;@ZO1GInjAZRW|kpz*#RKJIl#W1O=|n6J6C-jCXe}HrxZ}81w!o zNMx8;@LWIXNro%-BwMi-bi0Zhmy@X&22$LNEyUF`7;pvVk#ZCXA=y*+u0N9ECAnJPKd>P=aIA|>qcJ?ji{vX{cPj$de2q>W=ho=23YYFae9z{y?EWz zx@bA>J@3?nv!9QUbCO)=7?8|pLD<|5jHQ^#=xWZErrE-t!tan=^gew}&F9}Q6!oK% zvUSX&SBU3+)TVmmi1Yi~`i*^X4X34bU3}uNBS*}KE%7u z!P*tJJV4J9MldYI-r9R1A(T^3EFME}<2c#eyoc~Fn7wfs1pTb^k+noIza43+Pq$!4 zpAD6;_Yf`;CUhlji1Rwv!@1K%COSI$DVlo5%H<7oEqSNXSOrABt=h>`R$5vB;mi$) zNMEX{gNw%Sa!3FkEMBoSbFY8l(#0 zp8B@#6H!XIji3+v22FyYwY9K(VruFgQR6o!AnZm0=^GplOkjc$^{3Bi4WkJm@_7IL z{a^)s0WYT7>y#Xy99W6sUPwkJ7&j3DP9q9Bp&%R9xRp7EOf^%dDM&~tEET}6;h8f+ zBq0Osc28H=shIKmeKi*1LDo{_mWJ9(UvIpLy#s-ig(w z#xhY1UdFNda(pUi@3h48&jt3Vf?|D{sasI5p|LHZ6@^XNirXg-FPquwxm7zWd;gZt zGY(;W++2Yw(G#D%gOr!TMjX`8f)wBZT?R(F8tlFOP`!yTcyVR7+UU=`ZCLMI(2V}S ez}Ev)GpZkaxz8Js+Rng#^7{_S#qBw9`F{c0>$4pI literal 0 HcmV?d00001 diff --git a/storage/cfstore/doc/design/pics/cfstore_hld_seqdiag_find_full_part_sync.png b/storage/cfstore/doc/design/pics/cfstore_hld_seqdiag_find_full_part_sync.png new file mode 100644 index 0000000000000000000000000000000000000000..003dbeaeae3066d1feb28addf99284ad26c9ec7b GIT binary patch literal 80867 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 Xbz@d)!^XP`KVRB^Wp`@k;%)x{ZCR|I literal 0 HcmV?d00001 diff --git a/storage/cfstore/doc/design/pics/cfstrore_hld_seqdiag_create_async.png b/storage/cfstore/doc/design/pics/cfstrore_hld_seqdiag_create_async.png new file mode 100644 index 0000000000000000000000000000000000000000..9304b299ab71800c29a7ed48065d6626d9aa3099 GIT binary patch literal 80397 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

~O+Usy&-&8l9c>KHRVu!bf>bltQihv^V|L2b7 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 E6L6Aiw*UYD literal 0 HcmV?d00001 diff --git a/storage/cfstore/doc/design/pics/cfstrore_hld_seqdiag_create_sync.png b/storage/cfstore/doc/design/pics/cfstrore_hld_seqdiag_create_sync.png new file mode 100644 index 0000000000000000000000000000000000000000..453ea9ee4e1bb9f037c53952b854631e25b207e2 GIT binary patch literal 48422 zcmce;cR1Jm|2O<8T1p`yqpW0)vPsG&dzD!vE6EB;RLE9YWoFAPTcIK{Qg#`UY-NO0 zO0LKI{Cf^`uT0$3skh^ zoAjwpP^oENdTSq&PV?w)Fq!5Bi()A=x2Jb)jKuA-EHrnv*YAiu*+IMSo&mFq;sx>( z`(xB}ZnzDP9Q^aP&ekp4_mgnTn(RC8l+yQQBR|X=p8YU!To7Pq-+b%kSz(6F9rjL} z7UppO(ZXTl9@iygH*iqZJ4>L2#xwyC%S67?(ifcA=aAZtM z7pi-wXJojH)^DMrHZwC5wrQmuA0KBudUP*I*rA8}^y$-ORTtY^zJGZ?n0ejM&@ebG ztRaF)LdVEx>(Qe}SLO!kuV23|EFxm>^sOw2YhC_~d3mq2fs%;{wY4>2F|ok>e7>(=zj}R(7qV2obV-nOw)qa*bXS%}w9O?) zYoo-#gd3%{@9xFN({H--+hcAZc6I*aAajmkOV1o2g)oxR7SAKr8&a$T$vMA_K?n*5x5)2Fo(DCpPi?{77IAiwb+t_QStWwY8IFy=gL(BkJ)~HuYGFG+XT7w{IUCH}`g3UEKk>a=rQC+OYNCKgdW01qF+^ zkg;}&5yc<#A5BjMO>(laZ7M1%`tbN1nS+Cai79ieS?$$*`Z-!ky1LY)7ehnLf`Wp= z;^JFLG4b&noSfu`wNu6?9JQr4JCz=^JE{LQIW{&B-|q5y&q2BIHA`!%u*RR?-&=~f zO}Gbg6ua3^y-f}q z7%*{4vEbRVWy{cp#K^V1iQ-Q6+Q-+)NvEqWvk|KXZy?=sVOW4Ys-oI;fTFu49uZ1yqF>ff21 zRC!9d?&Yzl;}osW?7O+fCniSUCd*V^Uze`0uV~-kP7ll`vWQt&7pWFEo`^?nx{n443mMrf-KSg%4 zNC!B+FG|bHqo}?5{p8uRtVzkq-cxGo>L=CJDcn6gM68>3WoBia8>#cH@?1E8^-e`Y zQ{V1#K+2UoBqYRaI6QpU*AGv~Qc_YFBrmg4?A%!$^x>JO^L(gr>r8hJ_1?X=UPm1q z3#7M@*U_QE4cx{LFfcH%N=h=2?%cm0jQ=IQh~d#c>)_BDOHECEBO!s&eSToT+!x>do4B6S)mpwgS z=NH#e@bU4HUWDvDeEIJm?|CyU21UF?F3p4h{QCT!VyUl%kp%_(^M1HnclX(1)9~={ z$Co}zziMoJ+1wl~F`e73yVpEm;BS54PRVOOh4BW@Iy*T+8cDBnr?G(8>MnW2&|OW*PHDNR=pX>?AN$=AHwO`Or`tq0{n zxunExHD2G+>qW6>49v{<>92qNAQHGdgp#m=RkGCeHc=vqbSEv1&FSOQ*p=_!y}d79 zyvTj@XmoIJ(60UIms4D^lod0t)tzR)+aa@1!x6vGNN<_h5`EZhc|q^|)alaFQtu^` z)2FFOORKAs^_w?u-cFK|k?F>>Y@PVNw8YMy{`s@j(#nbfw@P}ef(%YSmETp@z*!jyJsdhL~!<^5M7x4{7|*4O^719NsX6? z8YfM;w0OlqyQkS{Aq5FNY0^IVpQDcd{nRC7{xk*;@+FJV>BsWt4)lvfe0=8F*4VaM zxVU(^T6iX*Y3y}WwXmO`UwH|QSY1)icT3G#Wm8{sCMVQcRl|-|4dPF zW&YX1z1z39(a(SSB!6q$p6rF^8!5ptp3T^^E~9jGbfTW~W(gwJTk#&g)n|$J+2eyY z&(iOVh=`a86RKlnPk(UK)^!4vp|ixM&8{a`*X#opc5txW-#@?3J3GG%{4w2mtERSg zW_4~*{kx-?GzgSbi@^lr}%#PDWTY>}6^H1x2wRlP_sMj$xfl@UAhJoZy# zs*Go3aM_e7qp9)iS}~VLMqyo1L7n6}5Rt{ec(@0H8d25*7Gq#sHS;~*VflT2mF?tbj^&GORH(lJR% zZvq$kOI7l<$Vjzov-t+5rW)vc21Z88ii#WS3w}JJqA^AVr(aGy%FpLuVq%h7?<=-^ z7wa+I!B)N|R$1HYGTX!B>h2!n#@scMsTQ4ERu&Vl@*px{HobKgpnqu$F= zy@|x35~--HycLV*Hfn5J|1$Q^i}3wN6U^!ToqwaE#>B>MB3WFWIfOTm4hWN#mBk=) zg`e~Z6>#Y2-dVf1O5Gaqf?_6plha2@kF8(t?&y1aKLjrg*My*k z(bCbmj;^nLS2%w@v$f{w)2H{3`G{Y5mm*+yOd&42$FSjVzWqnLjADtbV|Jl^boJj? zR?a#(MQq!1;30a7jg8G?yh#n?)2FxZ+_}?zwr2wZl#1vgqT%Uxr5^ytxL zH#bLdb5h;h^73-^hH2%cMts}8$(GjEn_*#L^;N{yvJWk2@3i$_la8lB_jddn`Ab-pj}yb_q+ zYr-JwCG08o;LaU?e}7W7=uSF*`BSHMHAOJp?#(w|zOtX^Y1gBIg7Lq6S9wd%DcrmC z&XJ<)BZd6Bxr#!MllR`R#+tDl?bN(eLXKoSxWm_Y+nY$%uOkETJBdChG3-T#aujie zvCw{@tW31#&r%yVH}{KAFK>C@3P&-k`?I7$OHa=sE6Xfj%b`0Vnvkc_a0Gq5dV_51 zF8PhW>-#2W2FmmG9{4wXC-Zm~%GgDFCNbk3Cnx7(%B-Br=YX!V<9~m0V7C?v&lgq> z*E2cSbe{JPNRN2x@WD^4kjZJq!>Qby4d{t{+cvj-i&&}6$FBQLwC-b;cHb^0CMJ3L z6RB=(mQPYr@T=T z(!Lt~GUDP!TFx9C9A4huX%!W8Qc_Z<%N=5e3=_Vx-1tgn6zbj+Bv?}6>ESW)_s5s_ zdj>0=ry@}pD6OrnC8eeF$~~>uZe-hO7}?k*Xs`ak0+TI1kogC2k(C`!SLo-T<#$ZJ z@mZQ>y2g~h|5a0mhvrVu6&Bf(Z`pG0(~BFV*%8XIFJHn~WUjCZ3hw^WSJ-f0#JcJR zCos?3w{JVTyT?*I2>e%O-+kxq-5b~}XXggWCA}6|NiW*kb}HQ7-J4y-yMvN)i;kts zUanIwMjLK_14umEm8s^sM{v`p_BM^;hX;>e4?m<4XLs#Vzto$qF1>j_MMZK60WKL< zCPqfr4QFiNq$Fko0|RdUXIWq8Mn`Y_UH`p&{nDjN+js3ECm9$UTfez4@}bUGhJdXf zKAgtoyJ+7uH8ouxHqKOijrvnK`x!{_JgbsbTCX2CaA0L|R6$T1A6Z>p&7W?};*3~vouBN6onmp3q|6q`ZHB01K&iu%8ZQz9X=q&8!@lT&vE5|;6ZVVd|q<#3; zR}9?k{MoZFoTBwBeDX%M(r{0+eT7W)BgK}-m%e>tdwAWEm2~9jQI034Pbn&@L>-8Y z#$wzs$g^}CG~MUz?VYq9vkttl4*Xwpt@U4hIVvJz;vzpyNUrU>l$yC`$NwzeVm-#x zy+`z;Yd#=NUs|4c?;S8c-k}G*cg&w%ahVCCWNHe`_t8?I9vE=d=&5?D*BcZZ@IFHP z_tT1jBI&X^pVpR^9k{jAWp>ogP9)NsH*bXf{$9iS4x+a`ckV`JCTGpY-`~O#5>xda z?(Uzarf!3U+5ZSp-t=K$;PaaYN4HZ@+|0^4bV^f`nu^LFRV&d{HRk&ocKM5J&BUs~ zC2XA!gM%E{9%H{8us@h3FZ(}pt-3PD2tx40s*$3=v~sunI_-V;VXu|xPOphrV=o(3 zPd)B*vAK`6KAvV(mp2`~@a9fp3RQ?Af%VafM10rWEs~C~loz&Dxr|YdQwrB zl$7Wg8gALPZQI3dsKTBMiHg+v<~oXeus!3`PHslBp;w3s7Vqr6a@Z zU3_opcMjCP@DMvhjxx!wZpG^NkJ|1gFw?OiVa>_LGImLkNE(X*b6n+bXr z8WzSz6LQwpHYZkFgZLdj0aBD(@fq8LG_^$_oG1vtu^0a5>%d3;;kT+98V!Y}l_b)Y zD_3gX8*Lv2q!=Pomy?sDuoSsG-b_6o7zm!haQu3W(eOssX`rv0#OnlbX`1cLuU^c{ z;{|ORMMvZ2>F!%A9v1z(QLX_NEFsbAC#xHHbuRliojDJ=eJp8Mm4?bDQ z{lwwCWfa>wf3~>&y9)a~_~mgmH8r#Yl_0)O>F-1{D=OlcnVD6!wYBH>iLu<+{Y4ZN z!FwTev;6ZvOJT}3xvq>O*MAGp=VU2E&)68giw2jzxZcRk0Fa@Q`&Gwto|Esc$V z;SmwuOR17B>9JYHr`)6?Rxc%1yaf}@h58_Cs{Y)S=l9;Vi5GF_zt8rP`=f&o52Tk# zvRu&|%SpX{&&RazX>sTd8nZ!S#`xAiThg<5YiQg}Nr}97k7mBll>IItC0rD%Hr;t4aWbQ(hPgXib8PtOQ?GAUKmi$OtY9Zz z>)+p3m!W((^%b*<2lbcQlI8k+^wHDP`$ExO@7^p%`Q&ssdKW2ogX`A+LuhlC@~ut= zhlCKKMT=DCLf!AkAN#w4h^hd zKU6v&%z2HAD_D`$PLX|C;WS7hfs*mk3;uSx^Wug4{Ks`=W#!YAmsmc3{(ScQ`B!d_ z6Ix?pVgi6cr)Ouan!@)Ji?z=8_vMA*V^vjEtel*RqoqRV4@BR@3&WNTmGfQugidWN z^)4BG6>T8{cp424?Kh~t_{okmk%~?JuU;w6@4QGkxA*@gHaL{kC1e`DZ^|5c?spI! zSrLUGMb4K3Waa1Dn$=L1i|fJ7U7UsN&{rZ+OG)3!h;7>5=<%hG66;J=Q?s$$@%>pF zo4}qPgL#c`4-b#v$Vg>Z*CW`KL_I-itN}Nou;k5sRB-a^#P~S5v$HcHWub$RZQXOA zz-Y=gsIRuup5^b)u|4yBo-&AC%1=1YdvqSCt z?f19F>`X!{C(8#Vc53JrjKKW@P$#ager<_ehECvW(=6@b=H`|l<;JD?;7H(aBmdgk zW5y~a;J?3q{ptjLQ=OlmH@lzbESsAyQo+_WWN(*V%w-=~@dU)Xq`dqPX?${0`OEv_ z9H+sG&Q~FOtIP6@3cDl=dEd0R@5mitO>gm+ahp6fFMHy|iL#6RM;OH%Xz9hFH47GI zmr#_))AsMogh0K$FRiwFG^q(>2?Y!~P*l_&dci>k&$)p^x%_8x(xxlX+5>+PyjhCD z*x2}OHF|2N|0c5Sxf`sJE3K0UH-2v0^iV5VT31PF3w5twjneG2as*?RQ6Dvj^5x_- zwj8ZwcJ#umtEUn~)#eqBCNy)(JZ{_l3B+UQ0=bZokl?kBhbJJtgtuBq`7N~^CilO( zGJWFPw{NaC=+cQArh0nyl$lU>jU5l#h&G8QNK`O3;7LSXKZFC#%I$_3sSLgI; zhIL?T_pv5QcJ_!a-VBswK800<3nzar_-$yUrKQ!>8G@{fi;KI?sqQ@^HW#g^2;JjT z>&WACx0J7z*-9sM6X?7;^zZ7RbM<0Xm878AD*A@bxajb;Wz9=#N+|J{9Bu?pL)w|_ zdiUVyZLGlRkysiT>UrJA+OiCW)7Z7^_iDqXXh0XnqqDtD42bIUS4iNK{!2^=_+=C zw~O8}(8sJkxx9`Z@dQacg#fJ(uq&#a%wl+vSPY3xF zoO3L$%{J2NFJY3l(>$)kN9$1m#tA6vrKLcWhJ1Ub!6(++Jhu%mO1O@z4xfFbW@4i{ z$no%}+atyAT4|#OE;crY3QfvGAv4pajI_5$#9QPRBn*V*4)drr*yI?edPw)oKMDvS z&&e|nK`-TE0f z!kA;>bG>#I*Bao#j??^5(2FkI!yGOBKE}Bw1il%ZS1PKqjk|Do05oRGmM6{s>?D zdAa6W6B9~6{2(P%AI-Tf{)3T}@^kU4DLf|q_T}7cY-~fZFF|g!Ih4ci{8n?`2;>jW zzgo2b!eLkt6;Qb3=U>a4@RYpuJN%G~h)|kJ}l7}*OpCe>+U*k8f;Dqbm3Wf<1GhNZ3{-#qc74ZW{S8DA3kjH6Ib*$ z_Q#OhyG|gRY0xpkR0}JusK^FFmSPEP&J5{hWls=yVqBzRkIxvZ z%^Ux{@O=ni;W^bcmCaThrLwyxnI* zv*Cmmorl(~U^}RbW{i9H?j5eTyLgd*!Fw|aih?|lzTs&jBO^Lz;d{QS+ALVtdRGk% zbadpwhd;5C6Za!q=@Q)s0X8>BD6-)3vU=K`T^I<>^j+p4V1wLvOiov zK^aPy(DB>COi!j`6i|4n_F0`U}wG6&VQ#0{EGw4cJ z3Ttj{4KT zu}VnLLqUIBQ4v&Hdem80EAG#qYm!n@C)n>kw0wTO>gxAA<*9GqzbonK(a`aq_6O5w zZhYUx|rHzDP{eXFsYUH>0hfVaZJ!W|C3PTGe% z<>lw!O-P`?gIs}w+u<$RX&ha4a`3d1lK|oK0zG5%y=ZJyn%PRG*_D@3RJ0pl!t3WE z8%plzCemAgroCKhWLTx(`-4$t!jR{0pjaH^tdzE=9)@MN^qs#nXfm?S+mE$G}=5~d8i`$6lm}`$}D+Lu^;WeedQIB0u;}>?Z(dA z*rY*5tPzId1&j0L(2!Y1iG!mf%+V0Evm`lRMksMk9uFA8SDT;z{Vw!pv0)FiD=7f$ z!GX_Z+$^iT({q9IAD=C!*eotB)#Lp!iAjF>@?{JhX_L;z>cANQC>gJYKT)YRkH2mQ414NS| zU>IbV8*kp6I(_C0o2V!)L^-D|k4(2|Ui4V~dIsIc3d(9nXXneno%DB7Q=?qQnqGEv zJl>aSE1Ympb8Y*JCfbOHTph2zDk@?(DmMgCa*$k)gBpg0hJMbX4{KbB^80fu9*f)O z<~w73eFbQ~8K9pMXIA5s^-Za%BjB--Iw0YP1lui*w=fPCJh5x&8?dtuUp?U%eppeH zNq=C>tII&9GOwGE#~(a+09t>b7S1Gkgeo`%fs0K_FHkURmv<7_cQYATwIoOt5mmXhmGUOchDjtJ@c5=@X3}6M zk)S_rL*I*dr!lw4Arw&_%N{3S+NWn#sbP9_;IQTlhvt5LX)7jYv79G9KQ3XTvB4cP zepynp)XH~X_}u1_(o&Z%eF8*mMnr^~bQ$+Xgb0R*hZnzn+e9M%URs)Q|Ni}`DTF%^ z1%==r^XT&0iaoJ0NtY+z?8nux2@6xfnkD(S#S4usjy6>JZOA>nG8c*f3XwVZ)Z+g6 z)egKeD?pE*h?VG?nT7Az%XRiuFtu3%>N*=QF9ja%<0nsE2JF}?Y}fISuH5kX^>y0p zu&5{%2vRq1-XzqBu)XX*fToEbfB2AR! zdb2zNPzI+@t12oUI&?_X<+I{udGzP8t~J~SM7{ojfiCPM9&zzFfLu*QMPv#%NTSGA zJ%uqzO^u2eJbeAP(`I=~-|w+OMtM0;D%fczfoNn{S^c5b_xJaA!fPPFC$!v|2#H}< zQW@}{U?IDyBZV6y%k4e}?cnj(G1-xa6`g!e*;i^cKm^&fYnSNToMwBtr_==L;}j}X zWKV;>qYE%V-}m^Qqk}{9&`=V3A^-bN2aa7;glr1?UJ+3yMFY#1r0JTF#c&7*pzdPT{BTmee0(_McDTwK(8dJc?}rz5H_{<^Cf9o=HeWp>DkR z_>l#OO;t;4@;d0WJV>Fgp59Gt4*P;sai`upO|2hw{7?=^FHpbA1vze|MOGY1AVB#7-s3?msT zdr0y~ZwU=GH3fMlrKav75f?@`xz7dR5mIYCDuUGH4C=rQEW++=(<6`oNQGzgz+2iq8ro<@@_+P*N61X&wqGKfwsUTpErTW5x0?7uAky6g@!(eTsS-vWmp^~oS+b<1Oy=+U3 ziwhd@+hD;OR!{Z0W98@==J#jpU=^+eT)^7}FvjcGMEti_zG6{_w}y!o4r95)(C$EIVv&ZeH^E@k1is z6M68s7L)kJhhPTLk&(NVR8-u4Wy!G6)&`9YRlC6lluwrSNGGfUpfTlVSLWCyBqTP= zW6e0|Vp|R#%L*Cl`l#PEC6Wm`MMGi~u?kQ(byU|MWXM?WU>w_V_p?YA&sa#=n+oY{ z(cZU(f9vZ(JP5V%5#;om+vib1xY6mBmY2O}Vx=Mgl?lo>Gd+FTX8Ow){mYkyk9jTn zYXBiM9NSLrkG)duisX;ik(Dp+wdc>V8SXo!xB~y88$ID2-|OLF3%-Ty&K@Jh`h)X( zc`LcJ6dn|c-H?iiR3Jb@=syLl%XRSceISRhzt8U|!~H2+o!8YgE2# zD|da`1F2B30$>Q^*3toc)jg$P2`GRBKsBw|Qiy-S|2MpSyE`&6GNSMB@#6>K6(C%? z6STJ)*!`h^DNnl8xX}eiHoMXYkpb~{pYeukMY0}UxpWjETpe;pYnE+B?*$a}=Y}rG z)%WNE;MV_Ip4yV*2MkiZZ3_4`qx_s!Mqsu33{Cc_2kesTXbQp}vppALf&pd&8nSa3 zoEZC>q<0q-nFeJKRQINI6Bt+d_pSf1vHlOgX16S)bgdY^2a-*K)m4p-JFB z5nuS;lJ3(~XrF~81&|;Ju}i3Sg+?nyHU!F`6|%JVWjrsH)}&m8o>_J6SBbKB=GyQx z&pkJ8+%SoMRLD^#xPOkps*Hi9eF#BhPQdATNePMgrl^D3h+0CtZqi6Z$c|8T&kUP7 z*D49sEN&)*p>u$3KzvFFRhh&l2R9>2ENE86Dp^}l2a?B9RF}2=QJZaG`)Ikgy*w68>Hx@=^y7Z@{JU^5-Mni9YoT!Ua0tPQe z<(8e9NuYks1kn%#v!}s13Bs$TrB!zIy8|yb_rvC9Rk-em&hP{Az}@EnGf7ANk;bR& zXJF_+ttWm8j<@pd-7M+I3dT-wcNwp0Sx>aaj?c`fp^_^q^0o~;_dAa4XS5dxcs<&_(2Zf9O`7$!s3kvfj=_B<@wV@8=AVvkXEHp}BZxVp3^HG#O;O?RYG zv<>1S9wa8_%i1D@yy+pnN$@M)J_j7Myu!kX>%@l>y#om$c$t=F1EB7+!?iLH0H~?` zuBsbKg|5U(M-Y`Bk^z92;+<2F5e}gjs;jCZsOh~t*$GL-U{=7VuBJv-5O6JG_W@be zf87f75q5SsY;>C*LaM+YVGrRMZZEk-Yv|FRLVDQc;+`odpj2#l$(iAu?4AR%{y?qp zez#0LDJy#gRd-*Ll%ynncr%b8k=bb6M@N?q512%PQi+t2s|yHT^P4vT$;m82+K}j> zd$_ExdGMbpA;T{Y&-!Ccenom1lGuk* z+daf{?YR*8l`{*!1L1ZOtLl3Q)0;?@E@@b0nBp)uFJkt%awk1caFFTm-@k;9+kBV9 z)HFtXlN)3Bg_m7jG*(X-;LMJ0b@xDI=mh}ExuF*~$j-sf%+2L~lOz>QUkM!xsi846 zr`xKWHzVI}#LeQ0h$Q83(lt21pc$7JKb;5&3}nMKWTiAQ4qPeaai&{rd7xu(uOd0tW5?F=) z{de!)?ZLprBwZuouA|6hK^cO7(9qw%AFt{*g44SX%7tSY^z`(QNNC|z`8LFJe~-Ze z^hPDv{fH&7=JFprco4BCYpigDAS=%PesnUq=%nu9XT+*Fa929==g*&gbXni+=YBnj zR8%?o1B}uRSKvC@+9#?U&Ts;*tl^nS3=JrlKXqrrEXWa2QBD{(#2%&YEw+cx-8z9# ztq=$hkwo^GA9_G=KHPl<+PSNz=V5w!dc>B}h|Sg%$)a)Y+&M)>T1G~7k{zf3Z<}tW zbAv!75a%IOfJ^60%+HMY{$L@hh>Ob;bstsTvc~s=gNdsPBidN%?}NPev9t{sCVy3| zpDj5?^8axZfz(15_cA%nS9JBJF_C>QFzI6db8+-$*KoDlZKNcoQDYstft68oKG8V@ zvffpNycGqfXkQSY$>YO$mhy4)YkG#e?_OBT<8y@CDGJT^rH#F-oXu15Y<{H@N4ZNqGHQA(@XoqR|8c!>p^8=q{AaW#07+81}h~mt~&VKUCl(UA6 zBGQ;o&=W5X*X&1Ftws_!6UCw0ISx>h15(P5g%M+uB6g-q6;UTL{A6%wsDpBd$-=e6 zT1oOqQ2DQ|MMOqky1OjbCY;l$^%H_Bw7PdJi2l=JFRCEGn5~@}3HgnPZvGb#Q|^ZP z&4OLrXW|`^_4Fwt3SA@NqA@XrA0Nbsbn`#aXat8H!jgVG$hJAIHvGiCpc?Jd&CKl!y(LjnJZt>O5i!ojy(74-tyOvpPzpk?c0Q}_({$B>frd;m;%6v z*=amhV&1^Qdt%=_1IfJFH840B3Rnx6(Bzv33N#^#_WiiD;m%A-)Fp|hPU1mvvZ-K- zU@&`ieV>bniuO4CVsY7S$!WTuiJHZ4>h;dq~jAF?@VNLVMu-{aoqR1|quw3QtCYL`n_O3hngguU{_Ray#h-6#*B&=4&Xs}o1nD~P@ZhV zV4LnovYw!fLfTN&lp~o#kcPg9WYdK42gZTZ56tpbw)rFH0|&Iew|5_0jER;^eys;{ zfge=QB;|=ej1+V1I}1>ho1d@GGh&C0M~vjL=`{(%Sh^}$U%e>5&5mC8BNg547Bp|N@Wyw6wZ}P)6Bl{#rQ$BD5SZk z?lUJbH-oMYmAdoH=Dl(DrsLX_BXH;yViAO}c zf4>@RBFINd7yvtj0xt~=ZfIo0TVoP!(ayswbL?31%F2ozGU_pq^Z;r((V5jXHM4NN zI(T>7Vq&paWA@NARxnY+(<1`QA6-?IpN=p5$I?4fUgo zOuv6D9L7h@@1BR_c;3-b176C_w-{AWtaKj9#?Z+fKpV*A5y8RmESoVO1^ST-X)BUh z>g3j~Tip@#j-7i1OA{E%9^KCU$Go`-5v|ej%1Kif(wq)fuzTHIwNJPA1z?KOKYF~Y ztLt_W$^*}vc&O>%n^54Jc8*jyF;TKe8wmRTFHs*Af$);M?M_#?`!~0>jb$B2{tL)Y zml#a~Vllvj0PIr#{%5XogaFwTW5K}|*S;xXHf<~^2ntW_@>?0aT2&odA=6`}Q{~`Y=nt_mF_&HP2AUww zwhRm;VB!lyJ}4xF(f4vHTAGVJ9Z3;ANa@tnv2gD&h}YOSF*&IR7{>#<)y4-?hI?xl z>vx)YX=+mTfB3-d&Nw?zqa&T(eYRWQ$scdd^jMcXuy++5d!;KV&erhJ7g7mvydR4_&)z1IowE)BH^s zt$BR*3cq@@hYHz}dDenubW77&=IHz=n> z!U~fC))0nsA3b`Br!4HVdJ#|QV@$^*{licrTwP&9vJg`;aKkWsrlYI-GSNY=Ck4N= zqtsSg(9F`(^6liw6|3AJsR$$G*ap(9%pKee*rC@bo(qwNsQW!HQ(#uDCuoTj6VUX& zI3AjihZ)Py^D1$l4^Q0EK?rI6(nwtd;crg#c6Q!4%|97PY)%1F@ftQFln4b}# zhi3)0rr3e*J+ z*9H;B#tW;df90f8dtroAB=fO4TN}DQ>e|SP zx2T7vaT$pa(u=vl%5O+&-3pFrfT@2y5TD1YsmY%z=2tN+B`5?*VsLOr@``a6?w4%{I)TSJ+Z0 zakTH-9kI%GZmO*PiA}*edmEDD`qdjulLkY?aCHtI;S5{ZEv0}QhP`Tku z5WNK!7e)cKv1)mpkl40x_3$`^9fA+wl97>F!<(ya{19Y%$z~b3LtKAuy{nB=ftH}n z+FoiruPDSZ5t)pJ$JOd|%V=Lt>uTP4-NUvG;-7#>2s2Yawtu zP9bt6dcK)zcCfOzOQ3Rgh32FR^GTVMro!N|8;@KWLK)AwyNBxbJ^zm^fGFlx%@(~0 z3k%5^Vpu$4JX)2LaD^Zdxw^oNtVt#&1c`1D(Q2#=Zfj#}>)3M+0?!O|3UyC?`%reK z{CgU)f8l(g^$@7*=9odhMKXWrXWH@`!1M!kzR&8HdehYF00+7;Ou%GV^mLhLkRdG; z!G92xj%nG}uSJoO)1n_#?we4}_sg#Bq@8twe zXBCCLOqCw^e253zk*SR{J!r@OzoQ)a*N!|t)=7Q5{#BClP7oRC^BmT~DK^q3etnKk zo1_^5#4h#_7~Re%_iEdVQi{Q2z4hT3j)5mZk@^f0XL!YKH^xGe8#5%*+IsBjm(1Jn z?NLCToJDko$gina%c-`0NbGp%_HU5}9bF>mN{4krrqVCX&2M)XgL8zgu08m}k1 zPr28`-QBwGO(FTGzsB+I2r3rTzwle7sybst4 z6ohO6o%%8$A`!m>)FAmA<{OP#Zmh-Emmr`;%m^mR2=en2oCC1&Hs&)gkM7v9gRn;S z#f`#)f_FDB$;G9-n5?W|&ajIop^U@ODXCNPez#Z9>F3vv!Dg4qH^F?KXeC?_ya3p9n@K;R!Vqo`5pn?3o9IHI=~Jw+1>EzA3E1uA z*tze$wX12#q?^2h8LNW<1%TwYet)4Qi<&iFr9KoL_n z3|1rD{C@%MotVZSug9pBFznl^>gqJVjlVyM>Q#k~bt+Mu5@droH3PlP+dKN+Jz<2Q z5C&p$>?_cfBIT9b;A4eqDl!7AyWFve`7mVjhYc>lX?0859)+=(LC&-9LUb0*sl(#o9Q0AU!yEduUYDlzSaK zXF#jYG=(4L^gXH=k*8&+2EpSo>8n7(1({|IH5ug0Wk&)yFXCOk!C!VD1U zOg#Lqy*&%fL*KxFR>&E$U3}BObzN9|>GT#}H+B|3dc=m$y0bD2tPhG~g zLVhE=_UGGc2OIiX(FFEHUZ&jWsA<1BRaF!AUMDjaA`X4}5p*A|TbkO(I0#D?_<+K) z_>!&dZB!+4Sdqja+dn~00+l1omR5fx>kA`T$<4sPEyURHKWSY&mzKnYd(hR$hyk-D zgcR9vbPNFJ&;mdVJTtvV8ek5%kJ}JoPuM_tCJxJhU3n5*0SU!hnApjW)m8_ht|oB( zNyO^@tsn0?Aj{C#*SCH9c6sQ>L!!~{COQem*kIUJL}au6`}gls&m62cJRqTtA{X%j z?;r@}W0aU6FE~?5-c}Tu-JIRJHKF;iXknhXU;sKPs7UFfybYD&@-1iWwn0S2JT)fn z$?>~4lVB{5!4n`(Kk;9S&;O3myT-;wvpNLWFw2Vtf`QNba=y~wi#MNGzjhr3y>G;D z$!#>nPtn?PqZ630=;+k-6R^VE_=#Iv+2EJ#l~5}IfUH~Md8euGo8q@w1gcLu_7nt^6VdM z{CejH;JLB!L1y`JUf%k~^HJe2S1M}SSX$~6n3yW!;N{sps+xV}Xe&?cg@jm>kvAnr zmbuJt^Xq2_?oJD4dmDNo>jLAfA*bRUHEP;p+u64-5C=s?HtfIKUuyBrEoCZ6?0TPV zVeN=5pzDAEH?6}jv{Hk5P;&0*mdugZ1$!_o8WN@gRPPZN3zAh^Q}dz5+f6G`JOT-> zt`Bjo|I}*i8^mOKOzG5M<;9CiNZ4v=MfOz~DR#RtqQXvrjXi*}15*!&l-vc0Vn+5J zN=z#;gWdjRY^(tu+`V!1|9*TrI!Xza*4M7Au)Zl#_wu%ehFeg=s^4BIIQ`^idxBW> z{GOT8TGw^($aJte8TaWIAdaQ@nR|t6*NS#J$#vKs{PjcfDiZQ5*@wPIxtNo5ejC)h zJ{O*&Gv?@WOmC2kpNlJqFkpB3Av#-Z{;Y{0;)@t6>c%W0Y^hwsXT0~~<6onW%y?p$ zy1TpkL27F8JuOpH_q0O(duAB7dmX{_!%O)~u10q~nF2RI|9L1_v9ozYMJRaJf6rAK z7CpcC`cb4vO_Z17wn%7@*A9IaJ$j*wXs3H{02CS4 za;-f*!o*nP)+kx!4&7sVu@!b4hYoGQJ|aT2#26hWJvWgsz#Rp>qwp76P^RnN8n&f> zAO8e%%-lDTy|d$w34YZ~T?`E>H5i(H(8sQ z*%O~Y=e{H8344*~ES2>iV|FUp7KSkqfg<7)<P=AFaK|Yn{?&LLGdV&;pQ>8AY1P;Tz}^ED$4~c=ZbxxQMgJkpGI9m|b$V&Zube ze|U*Hoh_Gcp=NnEG`ZgTv9U3cvoA9T1~A!%!p5^ zW36OoWvQJ*3=`hlIP4#TdeS0>@Hy4sdPDk(Maur{nKKWXO3Hs#is*M+KdkfainLdt zGG?RpxM+_AOPp_lj6ec=-Vgy`1JK~_3I3}8EW!<_yG?d)?#l-y06 zkcN}5$VtRVDI^VyvV{PW+0WWS#3Rnn_}X9U0tklLaVwZ#yf$^nts+}o)>KkjQbHhJ z!U2IEfe+q>_0BOtxpQX&loCqFDL7Ms%yWK7xAYg@84Ar&;?+T;S06;rT^!fnLc zRuHgsaNvdBMI0K36okc>!BNp)#?j_a2a1Rj&){d=K!_n|H%p#Xe1)V_-TNsH^SW-a zt>h5_YeoXrCsUsRelxZok1r`Xf~e;bE}D0A+ivDhxR7>K0uX%j3H4i?Q|*bbrQ9ZS zW8?4Kkq6#^Z0-i3_Dys1Sy(cI<&LlM%8u~yg~8Bxh%rW@kc5Zt!hvNm03BA>ugeKp z)Zj^J#2!IbiDB>Fj3-|qrYAgjAcCwDXbxu4b53ztTUoIah!YtO>`V;gM#GXE!zfJe z#mJD5G-!MH2(h(h_>Y)$WdHRewh63?@I0ZM81+9N_}bNbPHzNTnR9EIiSX&e%TkT|MTS(ESgUSnzB;&wWPYdKE4M3oua zzL`V^&pg`t0?0@hWDeD>uaal0+wWDU=JQ8BeE6Vx4)z6Ppy?Z!NccMP{2)c(W}J;e zys=DC*J`sdgFU4C2?=?pmVv`K5Hkcc=mKFqR^{=u1SlUQ6 zGK0HOmiM)sW!M}0(cDEn?{kibj)8$95+wG#>U$Hib70RL(|T}3NxT36GL487PWg%EMC8N!(~C{_CiJb3JP3zM%Ap1qgvMX=m|^wBi4_AS z990E4-a;G+1Uz;Du~;=%e4D$AOXr6s;uJC@Ol`cpBoE46Yep+S0M-Z%b&@#BEi1p~ zYA7fAx;@SpLqx{3&`k4h?}hlH3cfG)U70%|YxDei3dgGE`ufv8jLl2_>vh$2i*IG* zh?wvyR0}U|{I1%#DO*#Rv740{spt3qjk-61=CXbJy|3ocT^glPbDAh=Bt=4siWEuG zfT$EIC7Pt7L6inVnLIzw5lt^EkfKLDtW>B}c5=0}@g)naqkVzc=SUFP{4A60-JBb@d+$nS+A_SkepQ zG9N)X1rj^q2K1h$g;$6zyn5|gHrg=kygcx4Db0^_&Ge5gRSBQQ zE_D}7sOPB$ffHBXz~CJmwakI+(kW5wH`+IZ+UMYV&7h_e3?w+zO+9glptw?VPUbudE zN0m-qU#<*y2+MRA9V4b&*OUCI=BBbH@=l)04Z~$y2QK&e;@{0go>HctlAOZ-^51w% z%aNz;2aL6P{z|{!CLiS0ni?7!t|#ZN_3T-kxJ&tEzs~%HB)exjghm>Ik;Y6*L&JS; zpLffC7iR765qm@X-nvbjJ8Xd!g{NGmd3tE{>u9tcidc7om+bGCG@Rj^Y>AY@(WKY! za_W_`;m01U?B*N)^Ht;o;}s*46@FK4QQPC&?DvgfZcV!gj^fv%g?ABzL;_5af!sHadjR zkgwE2s4_uP%s;8-4sv?Y;IWJ54IoNnzm@Cf$6L*8-&g%tnrqp?9j2!hu6|3*Ut$HC zp<9JPG?X@hJuCFF2t5nyO(skFr*tV8p%Cxx5wCQSVkm*L2&Aj=={Gelg;H;LV@;f! znsbkX!p2ND6Cd`1tElhxi7CxqVI4P0R{!y)b9(9eqrSdVj(S5^ zU|V=^RT}dbWo;NPqU@}!(DSJ4;EmTqlg#r+{)S&y^TIcS6CMRd$BgWzrlo#dWfgq7 zcjLIUBZU`S!cWVbK<2WZyqB!CR2GOrPk|IZc>FluKb4jW&t;}ugsut+Rh}G`##2)^kGXsI?lW@9D5e5a|uqLD8xQB{$dU`sNyT3(1@W8HZTg=wiM?||S zX?6Yqf-_G|-Z&~FJ>94ZCgmWpxS0!AuE-RI%vBFh+(#|%GZ13tS*-bFG(o;}`p@z4 zfB5iWGj@f+0|!3A6oY;2`Gpnj#*P_7J)%d^;jw4WSGUHWeM{F*M7Q$@_ZV4_Pq2GX zZ4J~-{KW|uf}559WKd0xGEMMglPHCeCOhbFjp zdunC{{pe(+=yf^ixt( zO`drW_F!seHWqOO{PlCPX-1A1QHy!U)*j&xmBVT`K-kO&54=#$=z@~(#i8Xoz=7yi~dscy5szDYV4Xrr@pFhUM#Ar9dSzlz>r$q7C3 zS%?6zekg(J3@Q@K=+asX?-fmh*#HoMh|kt^(V}>W1)oFY^%4?yg!hoOD&2S3V#0tr zck0v{cS@w<3UJ4&C#N+<7Tq&IE5FN6o*3TzR{l1clS;w(P1+0MWv>-h+blN6w@ zOVt;!tP2xt?h>>c^I=Hj#aq7RG*V#`h@UEdX^KdUqn(m+j$)U#{Lki;>Pq>nFBaLJ zx%0IJzpHR0ZK;)2Gs!wXwl}be!u@O4u35dlw^wX~BA;^D;!($hliM@{2!9xw+m?K= zf0wRzeE(E-%<=Zpp;M>4P*@?mjDFLD7F4=T)+6;=?!qEHsh$1DxCPmFpcGru`{#Mf;mrOAAXSWbG`ugJJ0v;ebIL&@|ZPLtNBs z$QMOt_>5v4Bj+z&it~|Kf29{I_TG*b?beZ^gWPobX~Qz}7RzHfBf$NxOP4M^n$)6Z&!)?dTOZ0OMGx^iulf}dv4z*1WAsiS&(<~a z9onTW7aUXSvU&5JqN2W7es=8HvuB{3#*e+{{^x2~&b?~I)q3h^P}(g1_nj6e~$w%dhr^k0t@4lUD~$5|1q$h{y>}NFWOF% zW98_GMLW<@_ZvRE9Z0}VqI_N^$ro6h0EAAa$w!7Ka|*L1|K?!n+G#HowC=WE=isoN zR*q7vW$-U4aH<>Kfch~#Y@YFW8hwB3SZkcCe9ozd)H9We02|yVY#3L>{ zi>6c%6&Yi}RM3-{TWx-F-X&_xe+n)x`_mhkx|FKP`26A`*@1_a3PRF1c6~#7hQ+x0 zJR^%0W+Ify(sCO3)}+akH=xK@+}~`vre+&=z-;+r&&A<`AJ6sux2Xqa>rLLVb7y&R z@igwXpYeL*c%;z#iQmRRJD~p8uL;iY7lLgVU3EJXU0+Z)>qyX__CnWZgreeWk;hb4 zro%abyW|AwhTO6ae6bB>lf0YBf#|jJ1z#+Vc;?^8>m>7G+@USs-rr$cJb)ZlZ9ybn^R&iC3pDD@`ptep-4e%stpAr5VD#|en*4y~EGPVt z?S8I9ScrL4vnIF-`d?*r-h)>WxzX9%H0`cpdm%)6S|^tG4lp}YHRJec$CHrj%e%%# z*XNeUQR=*=)Uhs1ib+>lWfdkWg}oiUP0uL&b>hD+yxa6Sw(pFB^#qlBCAY#mepm4l zXN@JTh)Xs)7g6A0DTrzo-8^^NsAKIcyXOphtrv21lTV|-_g+j%OTBeDi^90+_B*XJ z|9k)SG+(p&aOyJ+15vP#nXY2nX7=iYpf`zyO}8sA^GZ$d5A5`R^!NU|ult|;UXDD_ zS}i@4aWaak&!9uaB!T!jx5Bw{n;o#d;#W#@LEe6WRWITH+ty$&&++;)>Fm>3=v=Lt zGxJ>n^eQgggxKykd2&zp;+rvg7H#E+P=6<;(1$hyRx1BaQ!kJ-dQ*WgZ2I|=9o!BL(N6MRz2>UV%3(e~4ff{Jlvv?z#z8Z1j^ z!NW^+byd2_{s(LZ0VNv_7ZensPlvYkRdeYAI4ic-X`QIygqn&?rIjQUQZ$|jk zUf{D9I@r-SYnwvu&AUv|kc@e#xcGFY2X1w%U$tM#o?jUYT_H47Iu1PQoA5CSg90a= zNNS!ZYDzx7=5P-54g&i%Ei^t(3v7u1kdV&9kJbx}hTzUQgFaEf=Y&5`h^H4}pS_E2 z0IvOTGSQh{?*g~{MQQuFrsh6)dXd5V1m?e6(v2qXuf`Bq0MG2^Y-`1l#n>2Bv19~&XA1H|bK#f$O>L+j> zbAu;U#?-E@bk;V3ql@)v4lIxoe|EJ~Dz%&49QJHd+S1ef2ZR7i=(=Z?} zx#m3E>Y8H1@7nwslPXrOT2(n>&p^Z|nAg*RL4DqEWXwTFK?hQ17joey=h0^_nZtYt z1>ESxmv8@9rJvsBhYudeG1~xZ3Z?7(!ABq}4pZRU<(=yRB=Q(Y^mo#JPOM6G;w%db zRaKxz$CREK%I30yk6AXN*@%CtzJ9xftDcpyIDT1+{rmO_twuKVKTF;(%kJsqD*omdCj!Y3?EmXXm6Yd2}uxpT_S5 z>iC6jJM1%kQIbuz2PmiFW`L0}6;_ECXeEM#9}mVp)+y%nwaYxS`-FAb>SLYkU7tOb zg6B{0D)o=`WCP2Yz-{)>AH0*Dy30z8Lf|_kWJHTRR=P0Z%=7Cy5r}Wa37x$JNm7G! zX}jBWF{~(Cctp3r!-r3++LJM}TZq5Wh@uzsC(?kULJ2!Oh-Nbh#{n2+d&G<7Tuqki+bs_V27lJ|#s>#N@AQj|l}c0t}W zDPwLY>LBpNWgK6ktY)A<;-(xWWZCC&%fK!+r9UG>&?^n|}kGBh>aC&c-bk0=06n+CG{O7L1{%`RYViNGAZm?{6E;;I|p z=YJ>-(+y7HNrNi6nBqLlhR0372sj}Ij2NN6YN8%C&Q}!``|yDqmn&-aT1q1}_0$Gp2L^y+%{(+_2< zWdG-CG}p0EE`#2Kf!pyR{=*61fLfAG{J4R{0qb3;AXsITrng`U{+z$u;q2i0NFV6}rv425ktGcJx-V87G# z;f!2PElpvYM%{CsosvRPK5LY#>$8PYa23bl+$*V;`l$(>es50t|4tT<9yxLa3j3~Y zck9*SCn$gYIvEtGY{Vs!`dK>Hohpw`a|UxC1J+;qHqnQ|9U{(pu^(dT6t>T|@7_i4 zTD|(1YJy+La<=_mbIx7eGk( z=rlj2B~suC3(L6G3wkeFpw{00*eK8t(KU|1ctl1?Gl>(T75zi@iFat7R_*NWosxI# z;C`r4<=@0EUFp+j&ukX=SEQU9lH%O9>zTQG4m z1#ay+_hq({_HP1tT35ri+P`7Zd87YSXU&wI??`{hkoYSM#2a+4f)u%Vo=U0Nlsyu%vGMQ-_W$>(t(A#$uZsg_PPjEudHBeq8;9XR7*#(5_CZlksMusR7rYOB zmhHKZh#5s9!?*=6ONjkMao&;qgAQ~f_u031h-w8Fx}brwh)WRJ7t{3g_H{XW;)DqJ zT?&_DTJ*O`<}L4l0=Z^8T!PnF=&pG_#pdJ9Klo%~N@_~V1<3LT1gq!*_#n@@lu~i& z;>8mD6Sn7&P+-6T`Li-LJ<;W8P|)Msw>AFiF-B`pdkM_cz-Kv62awD}MjsJSYBRzt z$gSsqacV6qP7e9tuiE_g^YpjGyohL5OZTvb?MAO7()m3R_5$;z^_sOA{rU_z^t#$w!ja0ayZ%f%K?2RcaLJT!0**Vg zV6KYq4&e)^Tpy?1XnSFnNueLb*m1nKE2)+zvh8<`&+QiR@O$0X(8s@7RxMAD;02lE z1;Hx+u-}N`!%4p$!0{BVybbSkFT6*lwP>a%VEjt_OwmNSH+I4Ve^!tsUE+TU7p`2s z{5-m==ZUMkGlOF@*?*>{rcu5$w0Dqnd#@Psp9623c~~j!MNKAPP*poQ0>mR%ZeWXm zbX&xq$ZYlU<;%s1wq4V1%@A%Agq0$GHu}AVy>q$kWL@AXn(JBHe&K4fhAqSWv)Vf& zEiJPGI!EsHWP7V%<*bDV@=x5WHC=qLOnxb*wS@S18kg1bc+4z(s+{Y#V$ z-1d9a@TQyS@SE@p#%=d|dIoccXX)vMJ_g0a@3zb*DtmsNR>=BioLS99<>^3X*i8noQb?3QJ`rl=oG>{em?#4kP!?^Bdw#VTFUe~#SpA%c)3EIC z1^+WUep&XVMA0IL?|3^(+d9?zO93lnj_bFi@J_tUKgNb``@C%SAN)-|LuK5!8Ek-I zMHt%10usDxHA2G<_{fb{Y#DwmhMe~qb!({dpdkO#Vr}(l z<)9~BF`!45;#gtAU8LT^ZQE|6y65={h8<3)@Zn4%Tp4%_no1UWOx7*BmD z-KKWSWb}b(me|PVWyGZknL@rZ$NKY|u4aR_@rj|p%a>=s&DnqM!BrGE#RIfL`q-S? z(Zshg1Jy?g!QeTsvA^xc7H0e4n2%3WZsE>~)@|D+1D>v93X()E+vit(y|C9x?u0Q^ zAIyat8|d(>)vN-JLXI$#s{~23Hpn)gd#B~Jn zwkGm=h}%RzO675#R5{x(Cw@gg9OY`?SH-&HD2tn3+@B_rs5;rtc7*0#hJvW5{!Ou( z8*@cX<{g}Gr9E@TMw9D%=KjcDh!pZSQQYYp{dd!)%a)xl3*4tCWXV5xpUD&$2qvWxB_u&z@eym~i4`>ys0e9YKM;vrC;9*JMBHxujCrd=I z^iC7F5vW_TQd9Q`(wk2rvCfiOftDu%T`hU#Wz1v%=8hT>7IXbg(z5>_^T%uTqLiI< zgVbHmlSBeISw8z3X1#>9MSbXfVw+_IwvT#UlydusYD=##gY+SMJ5rZ~^jhBZ&JnNp z-j7$-*t^F&FuP+&g`Q?VrIji%H@9TTMn_cmL#86@wB34hnt-Dw{eQ(D$9wyDjj3AbZ)aKlm=l(zv%VqmW47V}wW(G%%FQ zGw**&+?~~dHuE31V8fS#ZaKCA;QLLyMw_TqmMW=!tK)rTHji?#_w(e(*Os}2fZM?BJ}%`ps8+w zRO~`kr;-=3bx0ESe0A4NG+$S3F8|d);M{ulQ27$yPm{iX{(LBze19E~8b-*iPZMuBiyA+H|&^ zh1?D@fSP>fE!WuY>7*ckZfd3&z&5q6EM!vTtRvQfslV<};!!=P5=Uo8Y5u%<{*F#O$KG0(D4XTR=UiRGmSiARHNzOpv+rO7dk{! zSD5+hj$;n&-(SKn{~#2tqeN%95aHx%r^+*bu4}qxXPGajwAH>Ka}|+nOiGFy-}BFG znGv(wY(;Y`a75ndppoqnk?e%Y;Badr&6^-`?w0V*d3%|rGl4uh%E@_Byn6LfGd=N* zmZqsB#z}zI@1YWbCint)ueX__T$W$t5LyPaSC$jm83jVjg?n>N8fc%F@*b!{o6%;A z;axfo>@{NQDaecXS3s&U_Nd9aF-vj>z~NT1ylV4rHLNhKUwi#a%Rtv}i*OP(9U4?6 z+)0BC0?#d&i8WI+7h>b0vLSOW6;7!hqjA$~K|A zg!mP6U}xEgpkOiH3|?@WXd)=5gzG{IHXJIh8lKb=1WX{PEoJ0);jpx=F69*X%pAir zJdw31sXBJ-D8Z?dYAuT;RG_qE)2 zWHM@m_N`mLV$AS#SZwfzi^%6zHT+RpW)f|{!`V2*yto(L!9Wqskah3gF5XTFoX*0< zi_a~)RizgKH7dfe+PE|HMDauZsz&&7qhDXaA3IAz?E5y3%CG4wu|);c`}_K8NeC6J z@Tg26`c%F~3r~lD=3bowy)rQAvsRU_ul8}}D&3u(&oXtT`Z}XOvt~pm0&jDQ)!VGYUfoT-Fen9EXHH1^P zw)Qj9j>H0O*E1pyzLR8fZs9Z^d@w>nK=n}ze))vRY*Cc3358CfB^VᔕTvAGr@ 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 AU;qFB literal 0 HcmV?d00001 diff --git a/storage/cfstore/doc/design/pics/cfstrore_hld_seqdiag_find_full_async.png b/storage/cfstore/doc/design/pics/cfstrore_hld_seqdiag_find_full_async.png new file mode 100644 index 0000000000000000000000000000000000000000..99e6922b5e6d2d45fd211b5bb9b439130b321dae GIT binary patch literal 91234 zcmcG$c{G=8+ctb^G?X%>G#WESDion4$&@iNB&4E{%(Dt1iX;+=k|FavD-}_u%yW_< zbEeGR?Yyr0`QGRIzO~*z-nE|ly4Sk8e(^hx^BDGh+qZ4o4__7Kb6crds0o7DdR|UO zjUd()62$tul$-F$pV=EL_}3;Qg>y2*8u`zw;<#XfI6$12Ij!LkG1_IX%{aIyIyv$E zDQ%1g{il0uXMGP1|7oRvWc2YBo2t;Wh@Aly3>~%ce*%Om&&QmnWl^A(RZ=`gFU-Mc z+~QFj9Ye`|fKomvhSB8i(#rjtgQFQZkFGMZbI62Q6h6M%DDJm%$nwWT5bQOGPYrAAxz^9dRfSr9k zaoAz?Z`#VT;o!l8L_p~w2tmIB?WaS3oAKgzF;X+Qiz5l(x3^ zm9h40-mfuf2Zn19>tIEu?l(aYm&s3Z(%}* zj~-1eM44iu(GXx$&-dp?UZ2-Fy18^4qsJ_T7%>=9h+>-Z}Xu zvoh}3@jd43LvArKot@2kEn|Os+z*~RcP?bf2M-zRF4i?=(Hv>%^p)7rXfEh#Ua{D? z@Kvys|5N8%rQN)Of?Ag>et(bU9XU5ABqH)QFmO9BAD?=d#lW}c($Cq?JsQe#nE?cIMujG!H)B@9MxQ97JH2R_8OzPvv(B@Y z*VU^?x6*Ta;+*j1F3R z`}D<&hd+K?k&%%(W~%phqNgIYbd{P&%gwFmuq+KYVLkA}i}~`6@5fobCaA~NCF_db zYE7eHVq#jPJ@@)%OA0GDH)Vc)K0)l>y*sb4@MBroIzmNH&mS{^XX%B#~hMeELWEo0_9_scIe_iC)e>_wARaOcmbYbIx0)NhWHZrSTxnz`rE^sj zOWV%F!}F!Kwj$z$HPN^{BUqS647a4_n++MC-rtcfX}h}ex97eOqqpndE_++$T$8Um zu3o$Lv%AH5cD#5}a5XnEQJyD% zWhAv!MPENTW4SK+%x*!s^>u9RqZS=GN_o1XH=Frg{(NRG%bOePF#bE|jZjfU!?!;V|A5w9{b=yBkD z9zQ;J`SQM`q@*9efBR|~xH8Sn%@H2P6_0w$ylBcY9_^QU6cfX?VZ(+Sdb#C^69r$| zT_{dnxpKhY->l^8^A|6SR~BcFJI!!^tFHE3@1 zwv}8$=eg0-%F47SPo6w%T)w5Xt*uG*wQa+IHluTKa_Z^(n?8K{v>_xUgxcOr@N$vQ z&!0xbDQuIVXV1KmY4i&1wiY}8-85NxwdKPHitg_2vaEK!9@}*HHMf(FQyWexy>LPz zjT~(HHPhiIEq>+!EmQkry#kx_CeNQfWz05LpxrN-l(9E1A%Vwrrv4nYiHZ3GooutS zJ#I^fo`;9?DmLVp>lQfw6`-Try6>d6Nk>$yLMVOE@Z901rluK88L!fGZs|$@mr^)K z)}fGtJ>G{89a1ukKsul}fF~QadQve^5(s+r?@~*66+1GoUtnXa`udf9|Ni|U>A6Uy zH;xM1jcSLOq+BjeOqWnIZnD=OsD5!!aq#!=^M;0oGn2h%vipUTqXb6Ow2HMfHS3ob zrb7legXC@?muTqg>koSZZ~9m7qaM1ojfo@=A^P1b0ZN zWoF^^+I_KqrYf2q?G@Lc4b5&lBq+%29k5qCr$)QKgKE4z`(4eHOk%EA>tb?B%G*ns z*La#Hetfu};QV)d!;O|}TA}@Z5~&Glh1C{%dV8?pX+Acm8l>9knE%yXuq%~XnF%gC ziS)_mzw|5kf{zb37ne6qlg4;1vdF6^Po9XiD1=}MsHXGn#=@(P82xoLH)hh^T<|hZ z)S^=khgm-T_=yudd#0z%?LrUfzCEV2G&ja0EUX#lw8NR-ueh7ODYaUFPIYZ{#Vg~) zi4!t1ShM|9AKjM!oaC#-kFaCXg{tuH8n-=U6_|w=RvW42O)!CJ;|lfqik$W$Yov&8#ixm@MGd*WU0LH z^5kp6Cl%`E|M3Hsy0=EN(mnU^w%ulEF|n z-s#3U^^D!j%yEH?5y*`@Tk0w;5X_P3m$yEZ^FxhX9e)FGMf=US{KJ zYqHBPh-lFWx?o4nc5q~5$7eSM{WUNJR2zp$_%^TwgB za=#u@d0F|ht^{^AzkmRys#HvxVOyddM_U&YJ3G7I=0nxC&2Ii%KSF z$j8RUYG`NxI~lmI2v@(9cyTdVhf`7g(xvm}9XXmhr9d=>myt$al-u6)TTJ;1^z)^u zNwfD8&l(ja<*Tx?GO?Bmp|+Tz^TR;e2j-lv^+0FM~8t?`Tp{uV@Dvs5!RkVwD)?GRZtKPEOVwK*D?+W z01<)d(viNtzSnn(T3s*SN@{PW2(qZiAGL@jA@GU8kK3d;UJX1PuM9pIG9U#k5`7EU zDsWHf{LhE&S}A+}S@td;AIj*_st~?}tSpVZLJ8-&TWoB-Ez;uR;)#igF`Np|C>y@4 zRUI5yOi{`JsJP6!LsV3>>f5)*jDZ)SJN|ft`?qeceRhcmf&&kOdW4zhyWlYHIU(qY?39mVU4@lol_$U1_9*vxrBybr((} zE#c$qd)m~L$75|wtEQ$#`b9O$9NI^Z9)%qetv<^p1sZ3e7EJYv(kL&{rl_p?A=Ro z>IR?A{;jtBB3Y#fP-W{gffdf&x|KAUmOc96L|f_Evu80v=Jt{H)>iID%QFT&*J~np zK4q9Tyxq~!ppof*sv3BMmX_9GW{6H+K|xhR<4s1i6P6BTc0KmCp|-57_vEjb#0NIN z9sp!sFm)LV4!qSpb>WO3>)M8bhYufqpGSWE`QiTNn1M@L{Q3npsw@}P)b61y=?yh- zqhtB`wPE(|!?*DhV;#ACN;gqv3mKPFy1#h-oUD&dpFT~Pi7~D9KG;9mA8HVjm`JUv zstVA3@4gr)3)6Rw;Ee7t%fd_^X zQx-!cZf|IeQ22G8gWhJeRWC`X_ot@r05!66aLCMmH#Ri9i;cQI-Z9U1dZ2n9=fJnBN*;Ce&-ZuN zAHV$r&|I(uFvsliC8et!U(3s7`yJAkidwa^lkc}@ov5+CbH{Tt_00)}?ETkLlII@o zy()MtkaKlbwZ}M}wZ4A)}6@ay=oV~l+jkC}yCt?NgF^5Mh`;l+SO@mtJ{Xf-0Hb+Mv%HdP z%hpMH`D)yJcBR?r=^x&l51wqeAk{nB`|(R<3%)#d4BY|(U(A0AfwHQ zU$@8Fg;|5d9j7?ftzYjYnff`XMR@(o++?y%Z=`$RZ4tv~+Rv_?@Ka)QKHCc8~$k$jIpS&rei) zj^92NZ6EzCW?@v5Me&7*Qr>&_`Q8Wesb`8Ye7B`BQKZu=z=HG3)3p?hF0Zq)v(H*t z3Drc3KR9^dC3lgx%G^<5Vg}KrzU8%kp75o|mwrg;dcK?Aqb*j33k9-Aigj}>%GSsTi|kJ24)D1fuXo$lHaWAz z78FO5ij^6gozB9}#hKr)r!-^SS7w=gD5X~C*(FzI)Fa2ua%}_z1n``5j*ce;3`+cm zhs}Dm@#u>SG%{!EW{WN|FKGR2Z*TvJMf<$lvWSAvF0?zur5wTSV%TKzPXKmX{C)7G z^V}B8(v_Us7Rf8qD~O?F>9jCC*!TLeq%@L;^2?LHXCLlh1-l1q=rH-??$7`Wn1nNS zb|U+v+>(wdxBQ!z?`mT_X=!PvE?wG%TE!29OfO9(zDdY-Si`~D*|@vNai_T5t>R}* zb;H(J_UJPYs7vL(g#T(BU-}FB?gJLaOKV}BpJ4EIXV(^z3Rs=XEhRZkoF(m?Tf0Ex zz5Dxizfrc2NFg$+^in2x$16YH-)+seKKN*#gdcc^k6=7nsp6DgaLu@z85yz7jD$r+ zJ;qx6#MhHiTM}TucQEp$g!9h{_ciC>q=!k78t2bbp~ig>AJ4r!-}ji3l2T>(xSs4P z2XCSArOTHenS6cbd%0veca+>0Yd{D)+{~Uzz3R6gB1usR3H|=cT{prP=ccC0kb&YS zt?cZ)QR3kQP&Cdk{2m;9fJN>FflFq(+qcsu2aavtyt!98(PD+gN#DiA#WQN#-_f@F zN3Yiq@h9#sE-ZYguHFjJX4}27epb8g;+fA0zG1G3NbXC2CpN1DPew?(vS1TyEN;`oUO$X!rJktA-zIxu8*zms{7y6^Mov{P*9^}bK}KsJ+~QVSl3hB7lTGIA?w0Y&fIx6dpt zJu~z5NJ}bBe}5FUlA@wUSm=uvFD7MT{9C(sf~$}dESkKhwg+kUATu*FE0<%afIj_8 zhmEHIJ+1=Iqu`VlRUURS4xDiGh#xTRK&3^~ha-CyoB|h7rk>i|+^nIgc~(ZoeRUyD zEeVy5+7jb+-ylpH^%!Hu~9UvSgY#-44XV|Fphwwk}1#(DTk2?=7q`1xsz3aVO?7-cCzvb=7?@GfA;RHqf$uw%4jp{`4e8&(Md1Pv2{I4Z7-JM*UeEhbTKiBmF{Uq zY&Zrw#%rI%4u0(ePeXg`hn>t;$g=d++uU^v(_a6zZ1~;jnHiht&4gyu`CzVu2=_68 z1&wM0#S5E_9-mEb(Y5{K9PgALZyuJ`T+^Tt2ewkHM+$Fg`khWzh_+B zK_AM5gaqzGhrAv>q$ydM(_J1hSo>}!iHcfjZ=9IX98cT3T#9O`WaaQ<=Wm45@7~=J zpSosV0~+f#5_4}6GDGi=A0GSN<|%-%0&?{9Yi<^h8~qya=5q0!e)-;-c!8y{Z_kf1 zg^M(fCwy*g-HA8T&bmRDl$`trtPfe0J5bIP|LsOGyIZ4NN2^1FnI2@Qk0XTduY9*ss}({0oJJpx-p|Xtp)( zxjxkr(LQGT`Et+a!@|N$1FAr#Oneu)Lrj&&l5YlY7p}8ZREkH{0L;S8&Fv8xxfk!0 zmG}$ch3epY?CZt_r|;$DLW8S|201FfO~iJhdoO-|sQ&e4dIpA&w}<%n&Zw!;^B+1i zvO>Fr0l$fjjRw6g;WQIJP1T0@8uRKEL54p`8P3#Bol+sKUXkD@u*BGK8IJ&y*4y77TSuEN)HqnwyfdrI zGBYEiF5UQ?hL+ZAF!6a{n%W)ZW7RrK-S;EKr)6h*6&4m&8JmMzB6GZoj*iat;%$45 zZzp#s@at<4(`K)n^mRXnPidjxm%DJ`0YW_{n8nro7UfpQVskSbgIUgNQ7yZRyS3bC zD@%>EOWHmH@K=8M;zQImCaBLcA29a!ZG2L5Q!U|XRaF(YsHj%&Y}1rw^mk1i9TtcS z^&sc7cuP@kuQTg*Xnx9)N!vPoc2qJ|@X%C^g~A-*y%7>>S&yBaU3^N)j(v4PM~;+% zIq<@BM)+jPcQV9sMz*M_t9xzExr!qc7!i?_Q>$z4<>`4qLSiq{h}N*+MWzG|YA}ru z``AT9aw_*dwfH7>rIr~8yX1DpyUn{rZoOwVaEY#?6H{qucpn$#<_B(C;w%)<0#lyB zY(GEhEQ>Ckp~`41|NNhd{Y`V#e6psd32NeB3uMloHC&$m6L!+^h#QzJr;1krGc$9t9p8F0L8r{|(7}V7u@bj$-#&$aI)kvwH2;;De(~b_JEYs{%6mgP0r4K{u0CN|LxGtBW@kBgHhg1?}>-9;`7$Z4NcY z`}=XIez)4QsMOyo)}OhWsCn^X474NQ<_{=1!eI!u1vXs6lpgbm7F1;GCjRX4e@$sqC@{w0mR6Go- zQRCvp=B3#Nf1!)aqzWBi2HYHvIJ|10t?dIU``6$gjg%pdjxlJV#VwghsB!S$Kjl%^$kAm|pZou5At6$wNHW_u)9xXo0Dzl!j`{N| z!gl}V1?VsW1Vr%2N*gbDs%Zk*p=|Fo*y&zivF+vAmOcCM7+FLE=ufoH&dwa1oF6JG zHlI>bzxU;f+^32Pc0s{y$SadGGoO$SshypdoIWQg>D!LB(v_5yAVjcW)SeXUH#O#$ z_zS&dC@y*vCN$R>CTh8l;s61b@xO@pfQD}oC)C5Z{$Ct_>~E2O+3T{bjK{&j4En`R znsFH@3rPkz_71(T=Q9C)dFTbwZP24LGBVV7X*{4vp9YU47NU6_GE~_yKohk~T%4R< z;FKA?`}_NY9zT9uWdecV5tQ6$^$4S3Kc5@@RUsQZK+eeVhBW^(RGNP_!!Ur$RSS!h zrvw>UFu%VcSjjgGJsDlanJqgeA|f)gIFi}`)~2$xHH=Wfxr;9<(z9v1Ah{sJJ<`{A z2D)La+sY!<#~h0;c^MgmEyNT`!qLG&<;D$ekXiM>gSjRv4GJuy& zoEkqsQ2#?~N=Fw7R9c{pqavWu@pL|40VPI7*n<8>al(^03J#;Prsff$f-0Y6nq_1( zK$-%=auUA=24pd_PqA4)oy0L=T}Xm*A$+sB4pYLz%6ivFPUDg-w))|1AOnS7+$Rro zIJl`~ooxA?7ysp6If+KdGWAw|34G5zJvSJxA}nstro~P;L=IW$C&W|6efyL#jyQZR zA7@ctc>qI|pOPKep7U%$+X)s_^U@2@4S0EZzbA}hj9$mPokk8JJuyhWyO>O09{c8v z%B4%s%W793Dju`?DYFQPg8RgYONJ+msuJ0wMv;chgadfD?U#ImO{)Wn>yoxMWo2UP z@z0GR-|lbT=Glv4sL^rnPGdy|a#&7Q(*sI6B`*1OHU!aC;`+kp*ug@eF8NA}J9jcv z+G|>hunnuXKR?yH{@#NEu#JKM z3ZiDOS7f zvGPmiBcwxZ2v4_AywZo?C)%$0?@B{_JR&U2NnABFJZ(SGt;stLqLs$}FZeuJ85zrx zg|~+lOO(u&l^=mnudz6L)@zc%1vnxBXL={}=M%%7`A6ZFfJ_`C6H@H9Qjk`Jy~Fn@ zGAv9E(z*JL`{B=@p9ixXOCo1BUT*GJKxQf+-n|wOnI8(gtGOVx!tr#hA#NMWF&_WY zJNv}3kKxm+Vc3}Lk7*9f&!iSgi;WHHh`FHiRTOS_4J@=78Iy~ni%UTH3$>o=9Y5^ zQ{WAume>pTkBXI5dVEH>T&$W`H?0%uDRH~eSD@BGJC4Ld#4gK&;{#tbWb*N?;&Zld zBZE=yJG{TPkNWwlE9zH%$(;`H@!4K@6PB!t$JTT7^sZQ`Sa(Iwc`T0QM5KZ;Z%6)_LEs%1ez&K8cas^R#wp{sxLa`?@MWeJfo`S*tE33XZ)9>5m2b7Gjej?!ra3FCkSO*}84?MFoHA!*p^ zYNg(2en+(gM$~2JEGz`bpBo>iWngHkUH_0rHx$J0n>TM>0r~^fPEJm$h^PL4Y6A+P zbSpD;EkKx$5HGf~u=s(R^3}amzO#Y;A5<9L2@0rpWaJ_EL^XJc?-jK#Ns;Q}6F*i@12;6DB$=`tY1AgZ` zh;GvBgkSBKA(wH!Mu4>b?L4a8dF_AH`}cosEhJ5Y1%YxLi?nwoHv7o+upY)+azrQ` z+v{p@LHB9~%~0vjFvGrJlp(t$YdBd9tn*&pIlAdT5Slzwq@{7w|3=mS!yhTm?DZ(= zDsp5(~2Ynzsqr+QM1| zwd%lu1B9%sY@Wj(HbAJupy#v9n&h|DAH{nFocT6O_roQoQkAB0yCKYo4X}JsdVG(= ziZasCMXQt~Ci=mr_(o+MHHnU3YD~;MI2SI!dy-&3s-#55(Et`z@L6W~_r5bTHz?Ty5EzgyA0QiApcadO z0S1*{hr~HTxs3(a{DqqD3^}y1l zRW)kF*ma7kq~!NNzJeV|QbJFHGRr+0F$Mm_*Q&3a_0XZMq}>xo|L4!2M57CP2l!Z6 z6Y3EYiBtHPjh)?Uux4-A^XJjfrpZx_8v!1&ktvwuc90Vepp<|sg76@%q{!?5I-ajz zvm;vG554Skp7kvT84Z&hpw&lsue@ME^4~2=3+jWRseVoDC1`^ODCfjkuUkPabw;)xtb zWAvHL_}2yx&_Cy4Iq@+ZZA~Y^D+)-uf!@KvgZ}RLavTjG4tgr2)+hP-Cn#QlUFSoh;R{&`PSD-M-khs?V*b_630*`n(2$mCz(eJ!y0Esb0%qmgO+ zz}uUia3YnXj6%CHHUg3z*OsLp_qS0J3rkDtP(=T!2Z(QNb=g`fN=iW z3+)9zfBK|y>lQy99ilEB!2+jpSE+lHkB_{({7}@|@V2E zFzf#BFG$+A!0g7vsfUd2U}D0fC0+8Q+mLB=O5G$dD$0*$6R%)Oy$S~q{DG=s+8EN8 zwzlW+?fw4KSAn;;UiXR=XFsFXl|}LNG%70fupV#7lNT>`XPb9CgKhV0YG#V<**E$b zd|cyH3|!lZMO0c$Rd3(Er6*X9Uh_Zf{|{kd`(ML6h+(e&GfYYQVj*~(Pw|F8oX_Z< z&Hy8onkq=@Fc8WPK%Eq|?Dmvl`>?jsvt|fJ(kzbDyP(DR<1BuFLTVTR$OECr2TE&% zl>24FPMEZqR+ZtHMT8;Ei-1cgdugIj%|Mx92L*!jOJD4^^^#WhZx;Kp*@?R7^~9^9 zqM{GRS8)Mv%W^@h;tzI~1>nz)D0DZ<_ME? z6@%iClGRs<-AEAN#xx#HG$t?*2f&*cI^c{lt=3dkty5{(=r?-zgeK`5L|NZlEPaQi zAmtZ1f<+Xin+T9}qBmSHfH1LY&QL-}Rx;YMRzE}hR_kFhl%ifG{k~1lIxKlinm!FLy)KlXKsf$Y~iKmEd)z_M0Ich&NsEqInl*jHMpsBF)<)pief zo_waM@%mFHCY(9u9o|s(KENY1R)l@CegFP#*zgVx4(~sHTo2lnoH<};k}c|mj}LxU z)$nFWT*U2_Mca_+5|9nVY)|9W0=qG4g4C;)mzSTG8x+`3(fe*d`NlH%TK-J4rg}M0 zrN8jofhP*YA@-=c+`*LU@ifDahjGaC^6zYfn67SS$sQt~e!Ev1YyBExF>*&zyCW*i zE0Aj)5Kb7qJ32aO#FbEi63Y|2)q(On!Xq0xI(FlH$w*7zE1Q8aYaYI1;JLRsJvzJa zDqC2NQIc$glY#;cIcfa7f?z0?&1d$dz^p3oW{WVeQFCCpf&fL9KN&GsJR<~#ciUaO zxWm!enSp=`^cswE9S|DqBbtrH&i3n0;WWiT{5E9KEEd{M7qC-EdWZ$CR&T&kMNAsP zP!(S)Wj_M0JQ0uioqQ?Q$!o;DqBOt^aWD#y2vjg3#=D!q_}&y~JPQ$vF?Qf2)s z93rae*{LZtpJ*g4`MsJq+fVrVK;=+!U7S%3yMXFtxM}4X8Brm#-HE?&8`nz!gfp_sMu~z^=hG?p}N;;u@i_qp^W@|mxyGoXuyC< zZLPlLmfCmFY4q}LpB|aQtI=I<{inI6SAu)3F=j^zXds z(&>L!h{<6;w${h;!G*W=dxjVCN3Q=1z9ppoN6_h4nI4KEdA6V-@eL#{&b|_%aB@G# zn+fI}nX)Z=x)sO+n7-IMl5df>YyE%ffe5mkz@P7vbv8NjquT%TA2m~w)->S7*j}vO zahsvQN&9~RbF$Ut`uch>#VU(eO-!P*vVeB!#3~#iK_N18f7b6=$SAK5>+tfK$>?l{ z5CLXQ>IxVOcri?$n5+wLDa~hPgC+6D>dKOQA1Seqj^65>fDK_iv=8}y+Pz|)*i;Zf zS=rdup^D-SjWsP285ArJ-)OYyv8Z*!3sA{>;nXmlhySkfSW-!{Qb0lAnz>pr=5Vra0jw zOE%n=dGLJfcUc1q{gIwd5DM!~fiQVP@<~?MLa`vOHRs_H4O5Od9(`;ZWZw47>)Rw8 zr#y)|a9ElG?^6EQMwV)S{5hRrL6&t}M-i8N9zHyC<;ttW{Ad9J?EH+=`m`$baxu%= z>fch~nxn|UWCWZi8?eU5$I<%{utU^Y5OBK3dy=tV`gWa2S7sgk%yI5Rub>7&ErYJGbg!~h~ zUfy;vMTCdH{}y;;w&GMz{{344;OLdHwovPyW;=4x>o@EY-q0bM@&&?wN})rc{PBJm zIky$TM2Y_kdj6J{mYzi6QU=UBiX4Pc&ZMJVX^*&_qRC04xl9^nf%mnw+fdGEryFgALDmcFW6ERzXl;1) zswXCmR9&$0XJPE~`eS=Yw@ZX_+qMdb3o5Fr6a?91fxHbk9MWvS&^85MIpu{57s#AO z`bix$ZR1Q!wKK16b(`nDpAwS z#!9la_RlUc{HX4yU1%e557J=Xrud5UhZA8FtED-4o&il2$ic> z->7v?O}mm+K}E#_{EUwe9C!XCe#cVA;+(eUTJCS_=uk(0939;X2>$=D;W9Ed@Z{k) z5~l}mDE+y9?HXB4z{Q|~{*%2Y9Rg9j48eO{X2Wn$`3(l9lYfWvlCEw8#AtFvz;?=@ za?9=v`x!)H{#C)klAj~l-2fgvX4zdNHkiO;#})%78H8ypG{g2{XHiZrt|w6X4yVH2 z`3Q!Ngg0+wT1jiH&C;BCd#StBuHCyEz~2a$r|_&opbQ3=wlddYNgC2)9niX!I_oxv z`q*&)*Q%-*&36~+2xKFz$Ul`>l4pbp`hvLG+0Tr)$~1^LEY9%Ejt`TNb z@(FZ7-xqJf3?L13K*kSjgx8?8gF`}?K37z{>wJdyVELPk^$SW(O+CB@UR@14iS*c$ zkb~FtA7}oe!BOwsq84>9^q7KeCe;QRr5^vga?=YBeP5gDR`!ueq50){m)pl8p(d^) zX;t0|-~hC=4Z(F(SY-KK2-S{ylg zv_Z_xmW_=q9y5`JW*O45E#bDT9WSUf-N-1es&sFI$M=Q?U!NgZR--W-9{wd5HZ}D0 z_>w;2_KEA5xHqKr>*G5d6bw=4U}2QoBF_nN z@dot5!~+P;V2$PFh3s{f?Cmx`yo1fnk24jNkV9G-?P()-TQ&m;_BFKD0B&yczo6JxxUvW9<|KB7m1z9haN!x^?RU!4u{7 zxb21&j_m3!ng2;c_K5YJ%=Yd2@`W-bC513^^9wZ(ZBOqX7+6QZ?aVYR_hK$9{Aa3? z$PrB>EWxG~cL*z-vG~LaV%ldw( zVOO9nZX?1jNat5%|H9Z6z;8nk&da3ppX`7mSu_O7_#@Hu3~O+?rCqCL8STj32J9e% zVu?Jf*bt!8IbR#rx#7F0G* zE-)fSv)PJ`Z>h+FL!+u@4@{AyBcSZ?f<@Xf^fj@73G&1~Ss!nDy`$9K9VG$T*JvwH zm@*cQHO7`Qgc_v{fe(8iR#Pt<=WZub_+g=he3t>BHjdIM+qkjxBamYdZP$~>g8WX5 zkd>@M+n{9g8c!j~!?+}5J)r0%Xm_ewgmlT3rJ+CWSARc`i)s90@00H7;p2ag_nK=j zd$3@xKY!i`K0{7PiAh)=CKPBf&2p+uq}d9r-fg5a;yu|=jWUfG?#qEA_+XUFJunI6 zoSdrmngzZ)j{3_Z+|!Y?WTqQGIINGBSCo$4sLPGe)iL`>f|GM2d_6nGY`DS0c)@Q8 zk1zGMJ-*RO%ZVcXv9S=a(=p9db>*yD-0*Rs=V&QE_XvBMjl|QxatC`)! z8*ljaeEXKfL1d}?mlxpl_&1!8Uc5RAe_6CkmaMHhdp(E)eUdQOy7SnL?Kp1iGiT75 z6aa3PBL4i`NQ~)j(gh3owgP>Vbo=%_LQ3HKmN~b0(@&i@gtQ_<1h;^q`R04;> zuHraTT3cJYfE^<@oJY6;4u$1BH*+`~6-@@MQ!m=%^7>9h zfk+_;&(~ma5+ll+n=eKS>NzI1t5r?U&T8H${fpF~{zAn3OG862@`@r*Qdv=dUy4L3 zPG>OLb(#~57{G}l9_(ifJPma(EK7J!9$?SJQME9d>CrBNDEe-y= zj>coSq_Qp}Ja!ZBV4W?5)eA=I{7tqg!DXJ0bwqhYw zePc5@*hwH5kc5O;-Ga#M!q>WlMI+Xz$*EaAQTmu2t-&G;XW4?XzR))4W+2@egIuDP zVo1!q)po>YymJ@L4*nbWz8qs<$Q3g+HHAU)6FkA*cqrKxfJ*W-bm?}}0{e-Sx^dP0 zI@12b$3j~t(8VO_x_AZq8B*VSv;qFX+LLxIa5N5x1nD-v)sQqqocL#>1!}NyUSXPC zBtse^Y7D$jb!BdbU7jTO&_U*~)<7Zks$84BwZv5%P)+OlcWv0eAm|nWKPoXkzt&!! zd>)=J2=(6Bs^qu`k9+sl1&j$?{}vYgS0;n=Q@paZFZ#FkqF^Rl_pN@sr$8SiDe_`VckwQh$|8NAt>KQVj28W}?N&g1E zB%D>*X7{H5*xjnP94y%S;9r|t`ZZ66F7N+v4BAIO_*#7IOR0FdzH^o&ADWjTSVkPT zk~WX|+G5=`8TpSjF8$gm^_Z_V74~*f>z9=RNmgZH9zduh^DFsFGYOxq-YI>m$ zkCB;~Zwp$Kq-A6_fcK5RQ<6QBn}7mu3mSG|s6`nfQ#{zB-4P|!oN*fixoOqy`j>Q) zuOmnsJD{Txsy&ip#)jPr|00o=mGucyxOZ!7>n2@9qy{VapfCea|(0+Iai22j!&#X|b&=%1O{+aB-Kv4U!I6DG&yL#S>T&G#H z<)xlAi?n{Y0Y_G9#>ws{Owdn~V({}T0}2R&LEcy99ze#sNCDU~kqsW8F(}8fhnAha zU%|s=W%wa{Hj`elB`i)$N6U5gVQUa1@eO5HC>gCiAPsgBSI{Je+Lv@c6IZTX^9G&A zcJSai?g=R25CO=`GfXc-xS^z?`fzT)>jptV!96GLY=E5#*CVjNPk<|6QtM7$`SbHL zmf$l=2GXVcCN9nx7okv3M;yIQi>n$^k4=z%WnlKtI7mP6-Ef2%lEI+C0vG^n-Um4D zd~&;;Xpn>Dg$4%(j9^`9EwJU&)7SUv1u!8GD9Iv`1;5fk1)GD4VIJ_!Y@+vlQ?t0y z14S#`luRfQNRKrXSx-b!!=i%4CrWXquC-B8+t7=Edo=b!l}n%GWc!yA(WxDTpKWq_ z`aUwp#U$;!C=GjoKZs+N?&Yo4_rgBByLmL~xK&Ke5r5&$WSC6R7cX#G$f){*wIg-1 z*gs^_ApH>`7Zepa;6Wm-XJBm9LE^v$7}T7iuYfW#3-@beg57}L#Kfc? z-e^{!+WyERx3eNiJR zMjTf~#|95_2{WpJ6Yi@;j7&_sMpJRs$Lo<7xRnFF6B)Qa16F5LEZZp#fIE5e^y!<3 zV8tf1gC{ozKYz}H=D>BQ(5qm2XNf`hSkc9nEzZeQhwX0TK=~FIOKdw}wjEh*qsNV7 zERl{{DSC9^qAnHKB-9k)rj#$QPT#kAdytEZnm7-vN*9C@)fZ++WH8>ST}Q9U-MA5- z;U63vOkM}W#>N%gRb{KiaT`Zm$Ap~?WG2UvBWikjdcRPws;Q_Pz*co?u?B?!lxvjs zc+-}huVzl4%@~304fbG0fQ+_W%cu_~v$K|GI}xL*vT(x<_Ki@x!P{ng$kE?(Ee%XA zpFi(Q8V)QoZYI41a;}8K;He`L>vt%-$yZzI<_?*2=&?QvR8_`YE+R<@SX$|1^J{Yz>c)ZJ(CQ4H?BXp9R#W@H9j-98y1Skr*^XKov z6?E}=_#=a4J^PK2yZWz#OvM!*6a<2m75E*{0h@8NQaJ>SG(;j;|9|sGg@$epki8%G z(n&t98k;y-gt+qI-bS+6C@L=g(|$8G8ooA^ANOlAycb(=wbO{92>3Cy8qmUHbhypH zyIB-%0g+<1Y6IB&9~&Cf4|1u`qKediw=YCKR{e4M*aew@{S~7ks){xVtZMI?xMB83 zT0Alakh1gWwJivKaiaAb$@ClFWL7+_!5cF5>RD#yQIa_X0PVN_{hbqp&c%rgWO(`S zno#{!EW1MDeyiguAlQ0Yaq7{POHM$I!xe&Tnn1x#hii|HPC#uYtF4+ls1-L8-=d`U zld?X-yB;bZ<(QVe20HKS!1{%Yk zg@nX1lt%yaI>B9BKE49N8u&Xj34R1~OhI7Bd_+%V8d^2T9xSrxg%p@YU*mTN*@l>`k+8k&!&xMx?5 zRI=UqNb?8wBhe07c;hw~GFjs` z109oZU8^#U$A#L=jlzc1&RjD#z7GdF_k>bcj`{9mEL$(Tuh_yXA-h2K7v0Q9M)+N< zprZ+9n(WOo!b+0NF8qc5sOHJmZTaUYVhkJORZ0IRR*U2Y43S$%%QXoWQG++%=z{ry z3P&Ac=_`03$?l6ZboLaR;1;S!f+h3o_%0@$Lb|ChaCQ-b&54M0ayze7pv)k58pcXyH2H4P*x~p82#e z;VoKN3_+gY4kL8_C13jLLkSiw`rvjLi5ZtR5L4Z+yb9f>=_2?U1Tp z=naMzN`#v4XP{S0&=8OT{W#F;)Z)8ySVPz+a#oe(b}``q=N@YiqAYa4N@7c4b4iS+M?!Xqxo2;>5c%_yw-*JGBPL=)r zO~=_kO~y(xXt}QxFFff1X=+&Tj3p;)-*NwFUy>F;Z?$cA)Olpc#xU$Z>99$9{HFTH ztGT|0WeWIMiHbapRDxJ5VJ1bp7u;M$~NHHS3GqdPWb2ECitAIuINJtczLOkgCOw}_$247 zAMbtxic(TjA30u%zEK=>65>AEbK)L|jy}}S?-7vE_3?KD`-)V^5)Yy(+|u#E$G@EX z=Z%MhfQfzrO_K}|2)}zIs(P^B?LGD~X=j6C&I&sRPwCZ4`l8up-R$pnHa0fJ&W}fM zsRfMG_sCy|#@-6%pX}fPMGd;Q`MhGtQUc5mz?sSa?OCwo|3K*2L_m_KEnS|X>FnyF zI9U{|i|$*5#MmOBV<mu!O&!y=G!!IQ6TN1e0*IkuEcEP^X{or>9?sc}LJ?1KcNY z|ARM=`rG#)F)1i0swVG(i6-GCh8oMB>X?Bf^Dec}zF^+BOz zKH)r<)NB(V%Z|Z312O=6uVC|xhKec(ERecoBow${%$J;++7oR^4`8HVm5|rg4nr8J zLK-+L!vPs2T+~tkHjbz8PxA2cJ^`6nnPKvkgO5*P4sDUh=7IQnc_X73ZCzajsGXy@ zp73X1UqEx@%a;N$;L^i9fp(EQuq2x{Cp}+=)%{6eAYAhzPR5V@{OHjy!NbSbAl`$9 z>r0~8+0TKnJBu9E(XS+c8#3;o1&}VtELi~;V*E2T819|OVq|Be{RQwg93Ve1Do*(0 z@WofM){KpeJ^@gmkm5(Jas(Dm@@4{?=FpbuaKlt#ij&8Ed|12zTPO~&1jycW!fkuY zef!q}k(x+Q_zM|SXFB&*8yjw#`L27t|0=TwN*KOrKpPxs>4ouMzc|QCsC;}z+p`tW zb^Qj{!7Lz?oRL0rhEqsLm5?(tOGI!l0AJjXgR4FO-R3-qX3ir=zTe0wgj)nfq)@8? zIvN5YNb`#%79BE~KR;yz1VzH>=Mv62^^$)6{-}Ka z7i(_<&gHuHfBza*)2dY(rCFt-iAX7$G?U7hqJaiPsVJghHBqDqNfI)XrAR1^h(={7 zqEX3EBtp{rxzu{r-tV)Y|8TtTaqMI5wUpm*-`9Oz=lPw^UK2OI+||8%_c_z1?S7y! z@N=bO5v@pzM?*B|jo6c9Iqai^Kl(FuU!Ui_++K}s!(QYlI!3zOy;rYZ&D{c5AaKVC zwy#@@I70|CtNVtLIct7AOI|gnwE)`j-D+(}O?91lqP3M!CbetY-5Jch)>H$gr6dSAir&KbX*e&ReUUP68-^J8DHQK;8 zXaBrlrO4C&p;8P_zd3!9`&hlLU=F{Y%?eYiIX?I(_@ z-AIci+n(}(OkVg-+{KIyc6q@eRamlTmA#rK5mjXFrL4T!e5#WwRy`5B*&-VgHq)}4 z6Od*%fXlgCBb!MS)LE=pcmkXF(v{+v(9Rw$syW2a9C$%-`DK!XU8D?&1^r=_)_;vn5MDR+;3 z1F!mq4d@nuqry%@TZv$=FP+(J+*SfJDP8~^Hv;onyO*!}<$_HNk5P{Nm~`@B!lo(u z<4GbBK4FKtQOI|J*EHD!vTBghDzJfxN|WYOcI?={imvtu(x7;`&3{)Cwsp#B;6)|j zPtdH{>+aqOOIN@Z)dXs&r?CHLwtt*RrxAeKOcYWgup$0A+rDM-f|p!UVYi7|n(znx z!%e_+SIW^KezOEy%>K>;4#R~TCKp|6s)-TVnn)}v?~QvXjpOvVwe7m7M0gM!piIuraH>?Esm-`kn!ZJ6iw?<>-jEhC@ z7EK%4m=lnt8?M*b>8MNCZnB@o3TlYX+`z|xiv}M;F=|l1wp$O7rLm+x;jO)un_GLd z;2K36teoeRvP1vWh6~>~DwJA0yAb@~r1@ruyFf5BM5kFY_84|Mg44LPLoi2}W{hfX zY1E-`amK8st)xZSd-3At_}m(fV^IzQYa?9_ALpM}eE?n8%h#{}#CLJA)L$qL->MwV9 zlQfm_BK3<@dB8@u&8co$anO6m!q!gI&JcOWEBdi;7LlLJ+naqFKwE>}Gw zioffV#8TksRc1e+IR+s{T<)hHP>ZB3 zl2FapiQp`>BNx4!pGaO_IY%=AbBS>NQ#Rap92?#8*RKSQ7@EXRaGe~xDilyJMfM5( z9qyF#jZ4>Uu4)l4x2toQs0N+zFwvHBQpc1nJkt(0Ox(JxmM}VLoIsU$_HO3oB{bAb z-v5-E(WOL@kEiIc)?4**oUOQsQj1zCZYf!aQs`DuQOfxl7Gs->NGX+pTH7KIG*_I9 zTHV^4=k&Aalo=>@<=wB3KUMLSiu

k+wH)Ldx2N_Aj^pyga%;?_HnqZh4LJ+tyM% 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�?CGU?INuL~xuH~DT+rG5k-d2KG6%UdtXj}4*P4D{Y)2EAf z?sR18X)0kuJLq}9AD-(05UpfhFONte2q4|ZYQ4PpG)czy=Yv0tEt#;mtt3Km3Z%Rp)v`le z8T~AR4^CkHC+y#}c)ZDHE>XC7hZqveS2$IeU4^+rQo+COxNkhwgQxgdg0rr!u4qqC zd$nj`d|~eG>(^)53u9j)h{d=jpKnES@yEAEKUDwx6Z?v)Dj$T{IrZaJRVO;#52-Gc zr^!C@C@#~pM$&3TXvqC_cr7&b{GfZV%JXO84l(Bpqo{~yh-fEaG?Ypn6IoQ%ZFew^uo>Rw8Ots2qa_m0+!p_%1@ork{Bz! z;?!;X#$M%&CVm)O0ITxWQc28CTKiJ*?Bg&o>IOzkKi|wVYHEe3OY#w%+RYQp2OX%K zL245Bdfn4(CCNp~`)n&KUpBWoutht8+}4b5A1sqsEsHVfT3y_;&jr0`m6IWFKE2Hu z+GMQ97Lje|4c^nH_4=)Ms&80}W=GG2$||t@@*jXW*?MS<_NwT)X{Y0(IeMrola*+u zIVKz*W$3XevQr#jhCj}gI{Y; z27$mH)ML_vqXSV@C+`@esksB9Pk2iR+6fuKyt5N)06Mf;9TbQ@&)6K0j4CWy`@mmn zYG|mcMR52XWN;EHBV^Hru;%KRzp6DnQgB3&sDCb`dT#LwdbtL8O8F0@hpWN)OU~9- zI~!B;IMj|oFzf+kgv1bqd4QgtRb|?&&H*C~4K1weF7llYGn)>vzGQfJ;l}fRek{s1 z;$0_mk92wlI^GRLay!)}Q+7P0dSCVu0^c_?o{OV~>arlieSZ8yFw@wvHnAGcQh|Xv zJIB9wn=g}*VyrrNumaxaxF)2QHb`g8=oI!QlxdqTE>-26u$EhJc4ZS(6GzvF zJ3P=>W?8fjEyrbkH&& z;u94w7MLT4A~M_~h&C>xsCa`ey#mi%c|d>?_K(|WK6PdGxyr10aU_csuJOK`8$0U% i&F0qssgp1M(QL?!w4ZeTlP$5 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 VyR1CqMoRoK{$=j8i&HGN{~z%{i!lHI literal 0 HcmV?d00001 diff --git a/storage/cfstore/doc/design/pics/cfstrore_hld_seqdiag_find_part_async.png b/storage/cfstore/doc/design/pics/cfstrore_hld_seqdiag_find_part_async.png new file mode 100644 index 0000000000000000000000000000000000000000..adaa5e03ec20d4bbf90099b19a3101e36e779f43 GIT binary patch literal 87433 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

~IqI3u;62Y^ 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 literal 0 HcmV?d00001 diff --git a/storage/cfstore/doc/design/pics/cfstrore_hld_seqdiag_getversion_getcapabilities_sync.png b/storage/cfstore/doc/design/pics/cfstrore_hld_seqdiag_getversion_getcapabilities_sync.png new file mode 100644 index 0000000000000000000000000000000000000000..3fe37146c543842997c931405ea926fdc0021399 GIT binary patch literal 27141 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 XRV#*kIBUamoh0K~X1`oCShoG&O}Y7c literal 0 HcmV?d00001 diff --git a/storage/cfstore/doc/design/pics/cfstrore_hld_seqdiag_init_uninit_async.png b/storage/cfstore/doc/design/pics/cfstrore_hld_seqdiag_init_uninit_async.png new file mode 100644 index 0000000000000000000000000000000000000000..510fee95fe86ecc255e155d894797e524139bb3b GIT binary patch literal 48620 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 literal 0 HcmV?d00001 diff --git a/storage/cfstore/doc/design/pics/cfstrore_hld_seqdiag_open_read_async.png b/storage/cfstore/doc/design/pics/cfstrore_hld_seqdiag_open_read_async.png new file mode 100644 index 0000000000000000000000000000000000000000..4628817f9fe4c9067bedea240857cca1dfd246a0 GIT binary patch literal 87797 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 D*-(0p literal 0 HcmV?d00001 diff --git a/storage/cfstore/doc/design/pics/cfstrore_hld_seqdiag_open_read_sync.png b/storage/cfstore/doc/design/pics/cfstrore_hld_seqdiag_open_read_sync.png new file mode 100644 index 0000000000000000000000000000000000000000..2f87b364252bbd14f5a3e7e80dfae0f5cfa5dc68 GIT binary patch literal 56555 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%0ARdcqhtN9IG}IU*~CJss3KKqH=B^xc^A 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 literal 0 HcmV?d00001 diff --git a/storage/cfstore/doc/design/pics/cfstrore_hld_seqdiag_open_write_sync.png b/storage/cfstore/doc/design/pics/cfstrore_hld_seqdiag_open_write_sync.png new file mode 100644 index 0000000000000000000000000000000000000000..a7049f930636278f7f4cb6436da54233a11525a5 GIT binary patch literal 53033 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 literal 0 HcmV?d00001 diff --git a/storage/cfstore/doc/design/pics/cfstrore_hld_seqdiag_power_control_sync.png b/storage/cfstore/doc/design/pics/cfstrore_hld_seqdiag_power_control_sync.png new file mode 100644 index 0000000000000000000000000000000000000000..488e7c47e420c40cdfe94e13894e66f006a06808 GIT binary patch literal 22644 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

5#KPpV;s6Ls`v(Uxh}xt@UaYHo2Lv;1 z#*Ai_iXbFSP0ATAP|@#cd{X1M$g4(AH>w-kn92?;mjH55D^(J)#*5f z##cQS%k@loW8==L=QS^7RN`K6u>A_>6Fom&zHEm>lO%P;0-|j4Vq zlTm;v^ppc5Hp9e>U3TBg#&g z7Vm4dv0WZeXcAxXwcX4~$B#<4BC>DG^!z z54;Evcrrfab>d`z!KA3Dc<=j%327??0>O>MUM9$u%-{drFtnza&LUUFuWg+H)|w9a zizeyW^XGrV`Ha6-Etfw*c^`q~2QLo2LkvWm!*4wF)pa*FC<~6{}8^E z*}TuI6}MmYtqru> z&}`cQ7Qkbg+Fp!Pw=pPa0IQ$|0hx~;d8pN8*T%50lO3K-D(Ctgi&7<;kt9q(bq%Q*oga0s5gvV#ZS#JB9qvpLGU_d$%*`TrW#|LS4K-K`Z|$F2FT RKO;t%ULm01q}dD4?n>D9Pk1_goj6f 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 jCgbu<9$N|QQ(Q`bgZn?Kd1i%qAd(! literal 0 HcmV?d00001 diff --git a/storage/cfstore/doc/design/umlet/configuartion_store_hld.uxf b/storage/cfstore/doc/design/umlet/configuartion_store_hld.uxf new file mode 100644 index 0000000000..1ab3401720 --- /dev/null +++ b/storage/cfstore/doc/design/umlet/configuartion_store_hld.uxf @@ -0,0 +1,363 @@ + + + 8 + + UMLInterface + + 0 + 872 + 784 + 312 + + ARM_DRIVER_CFSTORE +Config-Store (CS) Interface +-- +ARM_DRIVER_VERSION (*GetVersion)(void); +int32_t (*Close)(ARM_CFSTORE_HANDLE hkey); +int32_t (*Create)(const char* key_name, ARM_CFSTORE_SIZE value_len, const ARM_CFSTORE_KEYDESC* kdesc, ARM_CFSTORE_HANDLE hkey); +int32_t (*Delete)(ARM_CFSTORE_HANDLE hkey); +int32_t (*Find)(const char* key_name_query, const ARM_CFSTORE_HANDLE previous, ARM_CFSTORE_HANDLE next); +int32_t (*Flush)(void); +int32_t (*GetKeyName)(ARM_CFSTORE_HANDLE hkey, char* key_name, uint8_t *key_len); +ARM_CFSTORE_CAPABILITIES (*GetCapabilities)(void); +ARM_CFSTORE_STATUS (*GetStatus)(void); +int32_t (*GetValueLen)(ARM_CFSTORE_HANDLE hkey, ARM_CFSTORE_SIZE *value_len); +int32_t (*Initialize)(ARM_CFSTORE_CALLBACK callback, void* client_context); +int32_t (*PowerControl)(ARM_POWER_STATE state); +int32_t (*Read)(ARM_CFSTORE_HANDLE hkey, void* data, ARM_CFSTORE_SIZE* len); +int32_t (*Open)(const char* key_name, ARM_CFSTORE_FMODE flags, ARM_CFSTORE_HANDLE hkey); +int32_t (*Rseek)(ARM_CFSTORE_HANDLE hkey, ARM_CFSTORE_OFFSET offset); +int32_t (*Uninitialise)(void); +int32_t (*Write)(ARM_CFSTORE_HANDLE hkey, const char* data, ARM_CFSTORE_SIZE* len); + + + + + + UMLClass + + 488 + 1168 + 192 + 112 + + ARM_CFSTORE_ACCESS_CONTROL_LIST +-- +uint32_t perm_owner_read : 1; +uint32_t perm_owner_write : 1; +uint32_t perm_owner_execute : 1; +uint32_t perm_other_read : 1; +uint32_t perm_other_write : 1; +uint32_t perm_other_execute : 1; + + + + + UMLClass + + 688 + 1168 + 264 + 144 + + ARM_STOR_DATA_RETENTION_LEVEL +-- +/* supported volatility values of different sotrage mediums */ +DATA_RETENTION_WHILE_DEVICE_ACTIVE, +DATA_RETENTION_ACROSS_SLEEP, +DATA_RETENTION_ACROSS_DEEP_SLEEP, +DATA_RETENTION_BATTERY_BACKED, +DATA_RETENTION_NVM, + + + + + UMLClass + + 1320 + 1168 + 184 + 136 + + ARM_CFSTORE_FMODE +-- +uint32_t continuous : 1; +uint32_t lazy_flush : 1; +uint32_t flush_on_close : 1; +uint32_t read : 1; +uint32_t write : 1; +uint32_t execute : 1; +uint32_t storage_detect : 1; + + + + + + Relation + + 536 + 1072 + 544 + 112 + + lt=<- + 10.0;120.0;660.0;10.0 + + + Relation + + 1056 + 1072 + 368 + 112 + + lt=<- + 440.0;120.0;10.0;10.0 + + + UMLClass + + 968 + 1168 + 344 + 256 + + ARM_STOR_SECURITY_FEATURES +-- +uint8_t acls : 1; ///< protection against internal software attacks using ACLs. +uint8_t rollback_protection : 1; ///< roll-back protection. +uint8_t tamper_proof : 1; ///< tamper-proof memory (will be deleted on tamper-attempts using board level or chip level sensors). +uint8_t internal_flash : 1; ///< Internal flash. +uint8_t reserved : 4; + +/** +* Encode support for hardening against various classes of attacks. +*/ +struct ARM_STOR_HARDENING +{ + uint8_t device_software : 1; ///< device software (malware running on the device). + uint8_t board_level_attacks : 1; ///< board level attacks (debug probes, copy protection fuses.) + uint8_t chip_level_attacks : 1; ///< chip level attacks (tamper-protection). + uint8_t side_channel_attacks : 1; ///< side channel attacks. + uint8_t reserved : 4; +} hardening_against; ///< hardening. + + + + + Relation + + 816 + 1072 + 264 + 112 + + lt=<- + 10.0;120.0;310.0;10.0 + + + Relation + + 1056 + 1072 + 24 + 112 + + lt=<- + 10.0;120.0;10.0;10.0 + + + UMLActor + + 1304 + 0 + 104 + 96 + + Box 1 +Security Context + + + + UMLActor + + 1408 + 0 + 104 + 96 + + Box i +Security Context + + + + UMLActor + + 1504 + 0 + 104 + 96 + + Box n +Security Context + + + + UMLUseCase + + 1376 + 160 + 184 + 96 + + Config Store +{key,value} storage operations + + + + + Relation + + 1360 + 48 + 128 + 128 + + <<uses>> + 10.0;10.0;140.0;140.0 + + + Relation + + 1464 + 48 + 56 + 128 + + <<uses>> + 10.0;10.0;10.0;140.0 + + + Relation + + 1464 + 48 + 120 + 128 + + <<uses>> + 130.0;10.0;10.0;140.0 + + + UMLNote + + 224 + 656 + 304 + 64 + + Note.. +mbed_config_store_hld +v0.04 +20160225 + + + + + + UMLClass + + 824 + 968 + 264 + 112 + + ARM_CFSTORE_KEYDESC +-- +/*key descriptor attributes */ +ARM_CFSTORE_ACCESS_CONTROL_LIST acl; +ARM_STOR_DATA_RETENTION_LEVEL drl; +ARM_STOR_SECURITY_FEATURES security; +ARM_CFSTORE_FMODE flags; + + + + + + + UMLClass + + 904 + 720 + 240 + 232 + + ARM_CFSTORE_OPCODE; +-- +CFSTORE_OPCODE_CLOSE +CFSTORE_OPCODE_CREATE +CFSTORE_OPCODE_DELETE +CFSTORE_OPCODE_FIND +CFSTORE_OPCODE_FLUSH +CFSTORE_OPCODE_GET_KEY_NAME +CFSTORE_OPCODE_GET_STATUS +CFSTORE_OPCODE_GET_VALUE_LEN +CFSTORE_OPCODE_INITIALIZE +CFSTORE_OPCODE_OPEN +CFSTORE_OPCODE_POWER_CONTROL +CFSTORE_OPCODE_READ +CFSTORE_OPCODE_RSEEK +CFSTORE_OPCODE_UNINITIALIZE +CFSTORE_OPCODE_WRITE +CFSTORE_OPCODE_MAX + + + + + UMLClass + + 576 + 608 + 808 + 64 + + ARM_CFSTORE_CALLBACK +-- +typedef void (*ARM_CFSTORE_CALLBACK)(int32_t status, ARM_CFSTORE_OPCODE cmd_code, void *client_context, ARM_CFSTORE_HANDLE handle); + + + + + Relation + + 392 + 880 + 576 + 104 + + lt=<- + 700.0;110.0;10.0;10.0 + + + Relation + + 392 + 664 + 536 + 240 + + lt=<- + 650.0;10.0;10.0;280.0 + + + Relation + + 392 + 816 + 528 + 88 + + lt=<- + 640.0;10.0;10.0;90.0 + + diff --git a/storage/cfstore/doc/project/configuration_store_releases.md b/storage/cfstore/doc/project/configuration_store_releases.md new file mode 100644 index 0000000000..903b183646 --- /dev/null +++ b/storage/cfstore/doc/project/configuration_store_releases.md @@ -0,0 +1,68 @@ +# Configuration Store Releases +Author: Simon Hughes + +# Overview + +This page documents the supported requirements in each release. The Configuration Store Requirements are documented here: + +[CFSTORE_REQUIREMENTS](https://github.com/ARMmbed/meVo/blob/master/config_store/doc/design/configuration_store_requirements.md) + + +# Releases + +## Release 0.3.2 + +The requirements status (supported versus not supported) in this release are as follows: + +- REQ-1.01-SKVS-R: Not supported. Currently only SRAM back CFSTORE is supported. +- REQ-1.02-SKVS-R: Not supported. uvisor integration is still outstanding. +- REQ-1.03-SKVS-R: Supported. +- REQ-1.04-SKVS-R: Supported. +- REQ-1.05-SKVS-R: Supported. +- REQ-1.06-SKVS-R: Supported. +- REQ-1.07-SKVS-R: CS Stores Binary Blobs: Supported. +- REQ-1.08-SKVS-R: CS Key Structure as Name Strings: Supported. +- REQ-1.09-SKVS-R: Key Creation and Ownership Part 1: Not supported. uvisor integration is still outstanding. +- REQ-1.10-SKVS-R: Security Context: Not supported. uvisor integration is still outstanding. +- REQ-1.2.01-SKVS-HLD: Not supported. Currently only SRAM back CFSTORE is supported. +- REQ-1.2.02-SKVS-HLD: "only during device activity" supported but other options not supported. +- REQ-1.2.03-SKVS-HLD: Not supported. +- REQ-1.2.04-SKVS-HLD: Not supported. +- REQ-1.2.05-SKVS-HLD: Supported. +- REQ-3.1.01-SKVS-HLAPID-KVS: CS Global Key Namespace: Supported. +- REQ-3.1.02-SKVS-HLAPID-KVS: CS Key Name String Format Max Length: Supported. +- REQ-3.1.03-SKVS-HLAPID-KVS: CS Key Name String Allowed Characters: Supported. +- REQ-3.1.04-SKVS-HLAPID-KVS: Key Name Path Directory Entry List []: Supported. +- REQ-3.1.05-SKVS-HLAPID-KVS: CS Global Key Yotta Namespace: Supported. +- REQ-3.2.01-SKVS-HLAPID-KACS: Not supported as requires uvisor integration. +- REQ-3.2.02-SKVS-HLAPID-KACS: CS Key Creation Part 2: Supported. +- REQ-3.2.03-SKVS-HLAPID-KACS: Partially supported as requires uvisor integration. +- REQ-3.2.04-SKVS-HLAPID-KACS: Supported. +- REQ-5.1.01-SKVS-APIL-FK: Key Searching/Finding Scoped by ACL: Supported. +- REQ-5.1.02-SKVS-APIL-FK: CS Global Key Namespace Reserves Character '*': Supported. +- REQ-5.1.03-SKVS-APIL-FK: Key Searching/Finding Resume: Supported. +- REQ-5.1.04-SKVS-APIL-FK: Key Searching/Finding Internals (key versions): Not supported. +- REQ-5.2.01-SKVS-APIL-GSI: storage_detect: Not supported. +- REQ-5.2.02-SKVS-APIL-GSI: Minimal Storage Support: Supported. +- REQ-5.3.01-SKVS-APIL-COKFW: storage_key_create with O_CREATE: Partially suppported. +- REQ-5.3.02-SKVS-APIL-COKFW: storage_key_create without O_CREATE: Not supported. +- REQ-5.3.03-SKVS-APIL-COKFW: O_CONTINUOUS for executable objects: Not supported. +- REQ-5.3.04-SKVS-APIL-COKFW: O_CONTINUOUS for non-executable objects: Not supported. +- REQ-6.1.01-SKVS-USP: Supported. +- REQ-6.2.01-SKVS-USP-DK: Supported. +- REQ-6.2.02-SKVS-USP-DK: Supported. +- REQ-6.3.01-SKVS-USP-OKFR storage_key_open_read: Supported. +- REQ-6.4.01-SKVS-USP-SIKV storage_value_rseek: Supported. +- REQ-6.4.02-SKVS-USP-SIKV storage_value_write has no write location: Supported. +- REQ-6.4.03-SKVS-USP-SIKV storage_value_write sequential-access: Supported. +- REQ-6.5.01-SKVS-USP-WK: Partially supported. +- REQ-6.5.01-SKVS-USP-WK: Not supported. +- REQ-6.6.01-SKVS-USP-EKFU: Not supported. +- REQ-6.6.02-SKVS-USP-EKFU: Not supported. +- REQ-7.1.01-SKVS-M: Supported. +- REQ-7.1.02-SKVS-M: Supported. +- REQ-7.1.03-SKVS-M KV Value Data May Not Fit into Available (SRAM) Memory. Not supported. + + + + diff --git a/storage/cfstore/source/cfstore_config.h b/storage/cfstore/source/cfstore_config.h new file mode 100644 index 0000000000..e30e54600f --- /dev/null +++ b/storage/cfstore/source/cfstore_config.h @@ -0,0 +1,60 @@ +/** @file cfstore_debug.h + * + * component debug header file. + */ + + +#ifndef __CFSTORE_CONFIG_H +#define __CFSTORE_CONFIG_H + +/* + * CFSTORE_CONFIG_BACKEND_FLASH_ENABLED + * = 1 >1 build with the flash + * CFSTORE_CONFIG_BACKEND_SRAM_ENABLED + * CFSTORE_CONFIG_BACKEND_UVISOR_ENABLED + * CFSTORE_CONFIG_MBED_OS_VERSION + * 3 => mbedosV3 + * 4 => morpheus + */ + +/* default values */ +#define CFSTORE_CONFIG_BACKEND_FLASH_ENABLED 1 +#define CFSTORE_CONFIG_BACKEND_SRAM_ENABLED 0 +#define CFSTORE_CONFIG_BACKEND_UVISOR_ENABLED 0 +#define CFSTORE_CONFIG_MBED_OS_VERSION 3 + +/* default build config overridden by package manager configuarion + * + * __MBED__ + * Morpheus build system (mbed-classic) defines the __MBED__ symbol + * + * YOTTA_CFG_CFSTORE_BACKEND_SRAM + * build only for sram backend (no flash integration) + * YOTTA_CFG_CFSTORE_UVISOR_ENABLE + * build with uvisor enable + * + * */ + +#ifdef __MBED__ +#undef CFSTORE_CONFIG_MBED_OS_VERSION +#define CFSTORE_CONFIG_MBED_OS_VERSION 4 +/* currently build only sram version (port flash-journal later) */ + +#define YOTTA_CFG_CFSTORE_BACKEND_SRAM + +/* define the symbol that yotta would define for the k64f target */ +#define TARGET_LIKE_FRDM_K64F_GCC + +/* at present time building for sram so set yotta symbol for sync mode i.e. async_ops = 0*/ +#define YOTTA_CFG_CONFIG_HARDWARE_MTD_ASYNC_OPS 0 +#endif /* __MBED__ */ + +#if defined YOTTA_CFG_CFSTORE_BACKEND_SRAM +#undef CFSTORE_CONFIG_BACKEND_FLASH_ENABLED +#define CFSTORE_CONFIG_BACKEND_FLASH_ENABLED 0 +#undef CFSTORE_CONFIG_BACKEND_SRAM_ENABLED +#define CFSTORE_CONFIG_BACKEND_SRAM_ENABLED 1 +#endif /* YOTTA_CFG_CFSTORE_BACKEND_SRAM */ + + +#endif /*__CFSTORE_CONFIG_H*/ diff --git a/storage/cfstore/source/cfstore_debug.h b/storage/cfstore/source/cfstore_debug.h new file mode 100644 index 0000000000..dcedc3dd2d --- /dev/null +++ b/storage/cfstore/source/cfstore_debug.h @@ -0,0 +1,118 @@ +/** @file cfstore_debug.h + * + * component debug header file. + */ + + +#ifndef __CFSTORE_DEBUG +#define __CFSTORE_DEBUG + +#include +#include + + +/* Debug Support */ + +#define CFSTORE_LOG_NONE 0 +#define CFSTORE_LOG_ERR 1 +#define CFSTORE_LOG_WARN 2 +#define CFSTORE_LOG_NOTICE 3 +#define CFSTORE_LOG_INFO 4 +#define CFSTORE_LOG_DEBUG 5 +#define CFSTORE_LOG_FENTRY 6 + +#define CFSTORE_LOG(_fmt, ...) \ + do \ + { \ + printf(_fmt, __VA_ARGS__); \ + }while(0); + +#define noCFSTORE_DEBUG +#ifdef CFSTORE_DEBUG + +extern uint32_t cfstore_optDebug_g; +extern uint32_t cfstore_optLogLevel_g; +extern uint32_t cfstore_optLogTracepoint_g; + + +/* uncomment for asserts to work */ +/* #undef NDEBUG */ +// todo: port to mbedOSV3++ #include + +#define CFSTORE_INLINE +// todo: port to mbedOSV3++ #define CFSTORE_ASSERT CORE_UTIL_ASSERT +#define CFSTORE_ASSERT(...) + +#define CFSTORE_DBGLOG(_fmt, ...) \ + do \ + { \ + if(cfstore_optDebug_g && (cfstore_optLogLevel_g >= CFSTORE_LOG_DEBUG)) \ + { \ + printf(_fmt, __VA_ARGS__); \ + } \ + }while(0); + + +#define CFSTORE_ERRLOG(_fmt, ...) \ + do \ + { \ + if(cfstore_optDebug_g && (cfstore_optLogLevel_g >= CFSTORE_LOG_ERR)) \ + { \ + printf(_fmt, __VA_ARGS__); \ + } \ + }while(0); + + +#define CFSTORE_FENTRYLOG(_fmt, ...) \ + do \ + { \ + if(cfstore_optDebug_g && (cfstore_optLogLevel_g >= CFSTORE_LOG_FENTRY)) \ + { \ + printf(_fmt, __VA_ARGS__); \ + } \ + }while(0); + + +/* tracepoints */ +#define CFSTORE_TP_NONE 0x0 +#define CFSTORE_TP_CLOSE (1<<0) +#define CFSTORE_TP_CREATE (1<<1) +#define CFSTORE_TP_DELETE (1<<2) +#define CFSTORE_TP_FILE (1<<3) +#define CFSTORE_TP_FIND (1<<4) +#define CFSTORE_TP_FLUSH (1<<5) +#define CFSTORE_TP_FSM (1<<6) +#define CFSTORE_TP_INIT (1<<7) +#define CFSTORE_TP_MEM (1<<8) +#define CFSTORE_TP_OPEN (1<<9) +#define CFSTORE_TP_READ (1<<10) +#define CFSTORE_TP_WRITE (1<<11) +#define CFSTORE_TP_VERBOSE1 (1<<12) +#define CFSTORE_TP_VERBOSE2 (1<<13) +#define CFSTORE_TP_VERBOSE3 (1<<14) +#define CFSTORE_TP_FENTRY (1<<31) + +#define CFSTORE_TP(_tp, _fmt, ...) \ +do \ +{ \ + if(cfstore_optDebug_g && (cfstore_optLogLevel_g >= CFSTORE_LOG_DEBUG)) \ + { \ + if((cfstore_optLogTracepoint_g & (_tp)) == (uint32_t)(_tp)) \ + { \ + printf(_fmt, __VA_ARGS__); \ + } \ + } \ +}while(0); + + +#else +#define CFSTORE_ASSERT(_x) do { } while(0) +#define CFSTORE_INLINE inline +#define CFSTORE_DBGLOG(_fmt, ...) do { } while(0) +#define CFSTORE_ERRLOG(_fmt, ...) do { printf(_fmt, __VA_ARGS__); } while(0) +#define CFSTORE_FENTRYLOG(_fmt, ...) do { } while(0) +#define CFSTORE_TP(_tp, _fmt, ...) do { } while(0) +#endif /* CFSTORE_DEBUG */ + + +#endif /*__CFSTORE_DEBUG*/ diff --git a/storage/cfstore/source/cfstore_fnmatch.c b/storage/cfstore/source/cfstore_fnmatch.c new file mode 100644 index 0000000000..bc3bf9689c --- /dev/null +++ b/storage/cfstore/source/cfstore_fnmatch.c @@ -0,0 +1,325 @@ +/* + * Copyright (c) 1989, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Guido van Rossum. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _NO_FNMATCH + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)fnmatch.c 8.2 (Berkeley) 4/16/94"; +#endif /* LIBC_SCCS and not lint */ + +/* In order to support ARM toolchain, this have been removed from the original + * fnmatch.c from newlib. + * #include + */ + +/* + * Function fnmatch() as specified in POSIX 1003.2-1992, section B.6. + * Compares a filename or pathname to a pattern. + */ + +#include +#include +#include +#include +#include + +#define EOS '\0' + +#define RANGE_MATCH 1 +#define RANGE_NOMATCH 0 +#define RANGE_ERROR (-1) + + +/* In order to support ARM toolchain and simplify the number of newlib posix files used, + * this have been copied from collate.c, and the license for this code has been included at the + * here: + * + * Copyright (c) 1995 Alex Tatmanjants + * at Electronni Visti IA, Kiev, Ukraine. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ +int __collate_load_error = 1; + +/* In order to support ARM toolchain and simplify the number of newlib posix files used, + * the following has been copied from collcmp.c, and the license for this code is + * included here: + * + * Copyright (C) 1996 by Andrey A. Chernov, Moscow, Russia. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Compare two characters converting collate information + * into ASCII-compatible range, it allows to handle + * "[a-z]"-type ranges with national characters. + */ + +int __collate_range_cmp (c1, c2) + int c1, c2; +{ + static char s1[2], s2[2]; + int ret; +#ifndef ASCII_COMPATIBLE_COLLATE + int as1, as2, al1, al2; +#endif + + c1 &= UCHAR_MAX; + c2 &= UCHAR_MAX; + if (c1 == c2) + return (0); + + s1[0] = c1; + s2[0] = c2; + if ((ret = strcoll(s1, s2)) != 0) + return (ret); + return (c1 - c2); +} + + +static int rangematch(const char *, char, int, char **); + +int +fnmatch(pattern, string, flags) + const char *pattern, *string; + int flags; +{ + const char *stringstart; + char *newp; + char c, test; + + for (stringstart = string;;) + switch (c = *pattern++) { + case EOS: + if ((flags & FNM_LEADING_DIR) && *string == '/') + return (0); + return (*string == EOS ? 0 : FNM_NOMATCH); + case '?': + if (*string == EOS) + return (FNM_NOMATCH); + if (*string == '/' && (flags & FNM_PATHNAME)) + return (FNM_NOMATCH); + if (*string == '.' && (flags & FNM_PERIOD) && + (string == stringstart || + ((flags & FNM_PATHNAME) && *(string - 1) == '/'))) + return (FNM_NOMATCH); + ++string; + break; + case '*': + c = *pattern; + /* Collapse multiple stars. */ + while (c == '*') + c = *++pattern; + + if (*string == '.' && (flags & FNM_PERIOD) && + (string == stringstart || + ((flags & FNM_PATHNAME) && *(string - 1) == '/'))) + return (FNM_NOMATCH); + + /* Optimize for pattern with * at end or before /. */ + if (c == EOS) + if (flags & FNM_PATHNAME) + return ((flags & FNM_LEADING_DIR) || + strchr(string, '/') == NULL ? + 0 : FNM_NOMATCH); + else + return (0); + else if (c == '/' && flags & FNM_PATHNAME) { + if ((string = strchr(string, '/')) == NULL) + return (FNM_NOMATCH); + break; + } + + /* General case, use recursion. */ + while ((test = *string) != EOS) { + if (!fnmatch(pattern, string, flags & ~FNM_PERIOD)) + return (0); + if (test == '/' && flags & FNM_PATHNAME) + break; + ++string; + } + return (FNM_NOMATCH); + case '[': + if (*string == EOS) + return (FNM_NOMATCH); + if (*string == '/' && (flags & FNM_PATHNAME)) + return (FNM_NOMATCH); + if (*string == '.' && (flags & FNM_PERIOD) && + (string == stringstart || + ((flags & FNM_PATHNAME) && *(string - 1) == '/'))) + return (FNM_NOMATCH); + + switch (rangematch(pattern, *string, flags, &newp)) { + case RANGE_ERROR: + goto norm; + case RANGE_MATCH: + pattern = newp; + break; + case RANGE_NOMATCH: + return (FNM_NOMATCH); + } + ++string; + break; + case '\\': + if (!(flags & FNM_NOESCAPE)) { + if ((c = *pattern++) == EOS) { + c = '\\'; + --pattern; + } + } + /* FALLTHROUGH */ + default: + norm: + if (c == *string) + ; + else if ((flags & FNM_CASEFOLD) && + (tolower((unsigned char)c) == + tolower((unsigned char)*string))) + ; + else + return (FNM_NOMATCH); + string++; + break; + } + /* NOTREACHED */ +} + +static int +rangematch(pattern, test, flags, newp) + const char *pattern; + char test; + int flags; + char **newp; +{ + int negate, ok; + char c, c2; + + /* + * A bracket expression starting with an unquoted circumflex + * character produces unspecified results (IEEE 1003.2-1992, + * 3.13.2). This implementation treats it like '!', for + * consistency with the regular expression syntax. + * J.T. Conklin (conklin@ngai.kaleida.com) + */ + if ( (negate = (*pattern == '!' || *pattern == '^')) ) + ++pattern; + + if (flags & FNM_CASEFOLD) + test = tolower((unsigned char)test); + + /* + * A right bracket shall lose its special meaning and represent + * itself in a bracket expression if it occurs first in the list. + * -- POSIX.2 2.8.3.2 + */ + ok = 0; + c = *pattern++; + do { + if (c == '\\' && !(flags & FNM_NOESCAPE)) + c = *pattern++; + if (c == EOS) + return (RANGE_ERROR); + + if (c == '/' && (flags & FNM_PATHNAME)) + return (RANGE_NOMATCH); + + if (flags & FNM_CASEFOLD) + c = tolower((unsigned char)c); + + if (*pattern == '-' + && (c2 = *(pattern+1)) != EOS && c2 != ']') { + pattern += 2; + if (c2 == '\\' && !(flags & FNM_NOESCAPE)) + c2 = *pattern++; + if (c2 == EOS) + return (RANGE_ERROR); + + if (flags & FNM_CASEFOLD) + c2 = tolower((unsigned char)c2); + + if (__collate_load_error ? + c <= test && test <= c2 : + __collate_range_cmp(c, test) <= 0 + && __collate_range_cmp(test, c2) <= 0 + ) + ok = 1; + } else if (c == test) + ok = 1; + } while ((c = *pattern++) != ']'); + + *newp = (char *)pattern; + return (ok == negate ? RANGE_NOMATCH : RANGE_MATCH); +} + +#endif /* !_NO_FNMATCH */ diff --git a/storage/cfstore/source/cfstore_fnmatch.h b/storage/cfstore/source/cfstore_fnmatch.h new file mode 100644 index 0000000000..afe65f346c --- /dev/null +++ b/storage/cfstore/source/cfstore_fnmatch.h @@ -0,0 +1,56 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: src/include/fnmatch.h,v 1.10 2002/03/23 17:24:53 imp Exp $ + * @(#)fnmatch.h 8.1 (Berkeley) 6/2/93 + */ + +#ifndef _FNMATCH_H_ +#define _FNMATCH_H_ + +#define FNM_NOMATCH 1 /* Match failed. */ + +#define FNM_NOESCAPE 0x01 /* Disable backslash escaping. */ +#define FNM_PATHNAME 0x02 /* Slash must be matched by slash. */ +#define FNM_PERIOD 0x04 /* Period must be matched by period. */ + +#if defined(_GNU_SOURCE) || !defined(_ANSI_SOURCE) && !defined(_POSIX_SOURCE) +#define FNM_LEADING_DIR 0x08 /* Ignore / after Imatch. */ +#define FNM_CASEFOLD 0x10 /* Case insensitive search. */ +#define FNM_IGNORECASE FNM_CASEFOLD +#define FNM_FILE_NAME FNM_PATHNAME +#endif + +//todo: #include +//#include + +//__BEGIN_DECLS +int fnmatch(const char *, const char *, int); +//__END_DECLS + +#endif /* !_FNMATCH_H_ */ diff --git a/storage/cfstore/source/cfstore_list.h b/storage/cfstore/source/cfstore_list.h new file mode 100644 index 0000000000..7b9bd4cf33 --- /dev/null +++ b/storage/cfstore/source/cfstore_list.h @@ -0,0 +1,63 @@ +/** @file cfstore_list.h + * + * mbed Microcontroller Library + * Copyright (c) 2006-2016 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef _CFSTORE_LIST_H_ +#define _CFSTORE_LIST_H_ + +/* + * Doubly linked list implementation based on the following design + * and psuedo-code: + * Introduction to Algorithms, TH Cormen, CE Leiserson, Rl Rivest, + * ISBN 0-262-03141-8 (1989), Pages 206-207. + */ +typedef struct cfstore_list_node_t +{ + struct cfstore_list_node_t *next; + struct cfstore_list_node_t *prev; +} cfstore_list_node_t; + + +#define CFSTORE_ZERO_NODE(_node_cFStOrE) \ + do{ \ + (_node_cFStOrE)->next=NULL; \ + (_node_cFStOrE)->prev=NULL; \ + }while(0) + +#define CFSTORE_INIT_LIST_HEAD(_node_cFStOrE) \ + do { \ + (_node_cFStOrE)->next = (_node_cFStOrE); \ + (_node_cFStOrE)->prev = (_node_cFStOrE); \ + } while (0) + +/* brief insert the new_node between 2 other nodes, the one before being node_before, the one after being node_after */ +static inline void cfstore_listAdd(cfstore_list_node_t* node_before, cfstore_list_node_t * new_node, cfstore_list_node_t* node_after) +{ + /* init new node before insertion */ + new_node->next = node_after; + new_node->prev = node_before; + node_before->next = new_node; + node_after->prev = new_node; +} + +/* brief remove the node D from the list by making the nodes before and after D point to each other */ +static inline void cfstore_listDel(cfstore_list_node_t *node) +{ + node->prev->next = node->next; + node->next->prev = node->prev; + CFSTORE_ZERO_NODE(node); +} +#endif /* _CFSTORE_LIST_H_ */ diff --git a/storage/cfstore/source/cfstore_test.c b/storage/cfstore/source/cfstore_test.c new file mode 100644 index 0000000000..b78b25b037 --- /dev/null +++ b/storage/cfstore/source/cfstore_test.c @@ -0,0 +1,564 @@ +/* @file cfstore_test.c + * + * mbed Microcontroller Library + * Copyright (c) 2006-2016 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * test support code implementation file. + */ +#include +#include +#include +#include +#include +#include "cfstore_config.h" +#include "cfstore_debug.h" +#include "cfstore_test.h" +#include + + +/* ruler for measuring text strings */ +/* 1 1 1 1 1 1 1 1 1 1 2 2 2 */ +/* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 */ +/* 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 */ + +const uint8_t cfstore_test_byte_data_table[CFSTORE_TEST_BYTE_DATA_TABLE_SIZE] = { + 0x2d, 0xf3, 0x31, 0x4c, 0x11, 0x4f, 0xde, 0x0d, 0xbd, 0xbc, 0xa6, 0x78, 0x36, 0x5c, 0x1d, 0x28, + 0x5f, 0xa9, 0x10, 0x65, 0x54, 0x45, 0x21, 0x1a, 0x88, 0xfe, 0x76, 0x45, 0xb9, 0xac, 0x65, 0x9a, + 0x34, 0x9d, 0x73, 0x10, 0xb4, 0xa9, 0x2e, 0x90, 0x95, 0x68, 0xac, 0xfe, 0xc5, 0x2d, 0x15, 0x03, + 0x34, 0x70, 0xf1, 0x1d, 0x48, 0xa1, 0xa0, 0xed, 0x5c, 0x2f, 0xf5, 0x2b, 0xb9, 0x84, 0xbb, 0x45, + 0x32, 0xdd, 0xb1, 0x33, 0x95, 0x2a, 0xbc, 0x26, 0xf0, 0x89, 0xba, 0xf4, 0xbd, 0xf9, 0x5d, 0x2e, + 0x6e, 0x11, 0xc6, 0xa7, 0x78, 0xfc, 0xc9, 0x0e, 0x6b, 0x38, 0xba, 0x14, 0x1b, 0xab, 0x4c, 0x20, + 0x91, 0xe4, 0xb0, 0xf1, 0x2b, 0x14, 0x07, 0x6b, 0xb5, 0xcd, 0xe3, 0x49, 0x75, 0xac, 0xe8, 0x98, + 0xf1, 0x58, 0x8f, 0xd9, 0xc4, 0x8f, 0x00, 0x17, 0xb5, 0x06, 0x6a, 0x33, 0xbd, 0xa7, 0x40, 0x5a, + 0xbf, 0x49, 0xf7, 0x27, 0x1b, 0x4c, 0x3e, 0x6f, 0xe3, 0x08, 0x1f, 0xfd, 0xa6, 0xd4, 0xc7, 0x5f, + 0xa4, 0xa6, 0x82, 0xad, 0x19, 0xd5, 0x5c, 0xd8, 0x3a, 0x49, 0x85, 0xc9, 0x21, 0x83, 0xf6, 0xc6, + 0x84, 0xf9, 0x76, 0x89, 0xf3, 0x2d, 0x17, 0x50, 0x97, 0x38, 0x48, 0x9a, 0xe1, 0x82, 0xcd, 0xac, + 0xa8, 0x1d, 0xd7, 0x96, 0x5e, 0xb3, 0x08, 0xa8, 0x3a, 0xc7, 0x2b, 0x05, 0xaf, 0xdc, 0x16, 0xdf, + 0x48, 0x0f, 0x2a, 0x7e, 0x3a, 0x82, 0xd7, 0x80, 0xd6, 0x49, 0x27, 0x5d, 0xe3, 0x07, 0x62, 0xb3, + 0xc3, 0x6c, 0xba, 0xb2, 0xaa, 0x9f, 0xd9, 0x03, 0x0d, 0x27, 0xa8, 0xe0, 0xd6, 0xee, 0x79, 0x4b, + 0xd6, 0x97, 0x99, 0xb7, 0x11, 0xd6, 0x0d, 0x34, 0xae, 0x99, 0x4a, 0x93, 0x95, 0xd0, 0x5a, 0x34, + 0x19, 0xa2, 0x69, 0x57, 0xcf, 0x7c, 0x3d, 0x98, 0x88, 0x5d, 0x04, 0xf2, 0xd7, 0xac, 0xa5, 0x63 +}; + + +/* @brief set of test data for sequential write tests */ +cfstore_test_rw_data_entry_t cfstore_test_rw_data_table[] = +{ + { 25, 'z' }, + { 00, 'a' }, + { 24, 'y' }, + { 01, 'b' }, + { 23, 'x' }, + { 02, 'c' }, + { 22, 'w' }, + { 03, 'd' }, + { 21, 'v' }, + { 04, 'e' }, + { 20, 'u' }, + { 05, 'f' }, + { 19, 't' }, + { 06, 'g' }, + { 18, 's' }, + { 07, 'h' }, + { 17, 'r' }, + { 8, 'i' }, + { 16, 'q' }, + { 9, 'j' }, + { 15, 'p' }, + { 10, 'k' }, + { 14, 'o' }, + { 11, 'l' }, + { 13, 'n' }, + { 12, 'm' }, + { CFSTORE_TEST_RW_TABLE_SENTINEL, '@' }, +}; + +const char* cfstore_test_opcode_str[] = +{ + "UNDEFINED", + "CFSTORE_OPCODE_CLOSE", + "CFSTORE_OPCODE_CREATE", + "CFSTORE_OPCODE_DELETE", + "CFSTORE_OPCODE_FIND", + "CFSTORE_OPCODE_FLUSH", + "CFSTORE_OPCODE_GET_KEY_NAME", + "CFSTORE_OPCODE_GET_STATUS", + "CFSTORE_OPCODE_GET_VALUE_LEN", + "CFSTORE_OPCODE_INITIALIZE", + "CFSTORE_OPCODE_OPEN", + "CFSTORE_OPCODE_POWER_CONTROL", + "CFSTORE_OPCODE_READ", + "CFSTORE_OPCODE_RSEEK", + "CFSTORE_OPCODE_UNINITIALIZE", + "CFSTORE_OPCODE_WRITE", + "CFSTORE_OPCODE_MAX" +}; +/* @brief test utility function to check a node appears correctly in the cfstore + * @note this function expects cfstore to have been initialised with + * a call to ARM_CFSTORE_DRIVER::Initialize() + */ +int32_t cfstore_test_check_node_correct(const cfstore_kv_data_t* node) +{ + char* read_buf; + int32_t ret = ARM_DRIVER_ERROR; + ARM_CFSTORE_SIZE len = 0; + ARM_CFSTORE_DRIVER* drv = &cfstore_driver; + ARM_CFSTORE_HANDLE_INIT(hkey); + ARM_CFSTORE_FMODE flags; + + CFSTORE_FENTRYLOG("%s:entered\r\n", __func__); + memset(&flags, 0, sizeof(flags)); + + ret = drv->Open(node->key_name, flags, hkey); + if(ret < ARM_DRIVER_OK){ + CFSTORE_ERRLOG("%s:Error: failed to open node (key_name=\"%s\", value=\"%s\")(ret=%d)\r\n", __func__, node->key_name, node->value, (int) ret); + goto out0; + } + len = strlen(node->value) + 1; + read_buf = (char*) malloc(len); + if(read_buf == NULL) { + CFSTORE_ERRLOG("%s:Error: failed to allocated read buffer \r\n", __func__); + goto out1; + } + memset(read_buf, 0, len); + ret = drv->Read(hkey, read_buf, &len); + if(ret < ARM_DRIVER_OK){ + CFSTORE_ERRLOG("%s:Error: failed to write key (key_name=\"%s\", value=\"%s\")\r\n", __func__, node->key_name, node->value); + goto out2; + } + /* check read data is as expected */ + if(strncmp(read_buf, node->value, strlen(node->value)) != 0){ + CFSTORE_ERRLOG("%s:Error: read value data (%s) != KV value data (key_name=\"%s\", value=\"%s\")\r\n", __func__, read_buf, node->key_name, node->value); + ret = ARM_DRIVER_ERROR; + } +out2: + if(read_buf) free(read_buf); +out1: + drv->Close(hkey); + hkey = NULL; +out0: + return ret; +} + + +/* @brief test utility function to delete the cfstore key identified by key_name + * @note this function expects cfstore to have been initialised with + * a call to ARM_CFSTORE_DRIVER::Initialize() + */ +int32_t cfstore_test_delete(const char* key_name) +{ + int32_t ret = ARM_DRIVER_ERROR; + ARM_CFSTORE_DRIVER* drv = &cfstore_driver; + ARM_CFSTORE_HANDLE_INIT(hkey); + ARM_CFSTORE_FMODE flags; + + CFSTORE_FENTRYLOG("%s:entered.\r\n", __func__); + memset(&flags, 0, sizeof(flags)); + ret = drv->Open(key_name, flags, hkey); + if(ret < ARM_DRIVER_OK){ + return ret; + } + if(hkey != NULL){ + ret = drv->Delete(hkey); + drv->Close(hkey); + } + return ret; +} + +/* @brief test utility function to delete all of the KVs in the cfstore + * @note this function expects cfstore to have been initialised with + * a call to ARM_CFSTORE_DRIVER::Initialize() + */ +int32_t cfstore_test_delete_all(void) +{ + const char* key_name_query = "*"; + char key_name[CFSTORE_KEY_NAME_MAX_LENGTH+1]; + uint8_t len = CFSTORE_KEY_NAME_MAX_LENGTH+1; + int32_t ret = ARM_DRIVER_ERROR; + ARM_CFSTORE_DRIVER* drv = &cfstore_driver; + ARM_CFSTORE_HANDLE_INIT(next); + ARM_CFSTORE_HANDLE_INIT(prev); + + CFSTORE_FENTRYLOG("%s:entered.\r\n", __func__); + while((ret = drv->Find(key_name_query, prev, next)) == ARM_DRIVER_OK) + { + len = CFSTORE_KEY_NAME_MAX_LENGTH+1; + drv->GetKeyName(next, key_name, &len); + CFSTORE_TP(CFSTORE_TP_DELETE, "%s:deleting key_name=%s, len=%d\r\n", __func__, key_name, (int) len); + ret = drv->Delete(next); + if(ret < ARM_DRIVER_OK){ + CFSTORE_ERRLOG("%s:Error: failed to delete key_name=%s, len=%d\r\n", __func__, key_name, (int) len); + return ret; + } + CFSTORE_HANDLE_SWAP(prev, next); + } + if(ret == ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND) { + /* as expected, no more keys have been found by the Find()*/ + ret = ARM_DRIVER_OK; + } + // todo: find portable format specification CFSTORE_FENTRYLOG("%s:exiting (ret=%ld).\r\n", __func__, ret); + CFSTORE_FENTRYLOG("%s:exiting (ret=%" PRId32 ").\r\n", __func__, ret); + return ret; +} + + +/* @brief test utility function to create a KV in the cfstore + * @note this function expects cfstore to have been initialised with + * a call to ARM_CFSTORE_DRIVER::Initialize() + */ +int32_t cfstore_test_create(const char* key_name, const char* data, ARM_CFSTORE_SIZE* len, ARM_CFSTORE_KEYDESC* kdesc) +{ + int32_t ret = ARM_DRIVER_ERROR; + ARM_CFSTORE_SIZE value_len = 0; + ARM_CFSTORE_DRIVER* drv = &cfstore_driver; + ARM_CFSTORE_HANDLE_INIT(hkey); + + CFSTORE_FENTRYLOG("%s:entered.\r\n", __func__); + value_len = *len; + kdesc->drl = ARM_RETENTION_WHILE_DEVICE_ACTIVE; + ret = drv->Create(key_name, value_len, kdesc, hkey); + if(ret < ARM_DRIVER_OK){ + return ret; + } + value_len = *len; + ret = drv->Write(hkey, data, &value_len); + if(ret < ARM_DRIVER_OK){ + drv->Close(hkey); + return ret; + } + if(value_len != *len){ + drv->Close(hkey); + return ARM_DRIVER_ERROR; + } + drv->Close(hkey); + return ret; +} + +/* @brief test utility function to create KVs from the supplied table + * @note this function expects cfstore to have been initialised with + * a call to ARM_CFSTORE_DRIVER::Initialize() + */ +int32_t cfstore_test_create_table(const cfstore_kv_data_t* table) +{ + int32_t ret = ARM_DRIVER_ERROR; + ARM_CFSTORE_SIZE len = 0; + cfstore_kv_data_t* node = NULL; + ARM_CFSTORE_KEYDESC kdesc; + + CFSTORE_FENTRYLOG("%s:entered.\r\n", __func__); + memset(&kdesc, 0, sizeof(kdesc)); + kdesc.drl = ARM_RETENTION_WHILE_DEVICE_ACTIVE; + while(table->key_name != NULL) + { + len = strlen(table->value); + ret = cfstore_test_create(table->key_name, table->value, &len, &kdesc); + if(ret < ARM_DRIVER_OK){ + CFSTORE_ERRLOG("%s:Error: failed to create node (key_name=\"%s\", value=\"%s\")\r\n", __func__, node->key_name, node->value); + return ret; + } + table++; + } + return ret; +} + +cfstore_kv_data_t cfstore_test_init_1_data[] = { + CFSTORE_INIT_1_TABLE_HEAD, + { "b", "1"}, + { "c", "12"}, + { "d", "123"}, + { "e", "1234"}, + { "g", "12345"}, + { "h", "123456"}, + { "i", "1234567"}, + { "j", "12345678"}, + { "k", "123456789"}, + { "l", "1234567890"}, + { "m", "12345678901"}, + { "n", "123456789012"}, + { "o", "1234567890123"}, + { "p", "12345678901234"}, + { "q", "123456789012345"}, + { "r", "1234567890123456"}, + { "0", "a"}, + { "01", "ab"}, + { "012", "abc"}, + { "0123", "abcd"}, + { "01234", "abcde"}, + { "012345", "abcdef"}, + { "0123456", "abcdefg"}, + { "01234567", "abcdefgh"}, + { "012345678", "abcdefghi"}, + { "0123456789", "abcdefghj"}, + { "0123456789a", "abcdefghjk"}, + { "0123456789ab", "abcdefghjkl"}, + { "0123456789abc", "abcdefghjklm"}, + { "0123456789abcd", "abcdefghjklmn"}, + { "0123456789abcde", "abcdefghjklmno"}, + { "0123456789abcdef", "abcdefghjklmnop"}, + { "0123456789abcdef0", "abcdefghjklmnopq"}, + { "0123456789abcdef01", "abcdefghjklmnopqr"}, + { "0123456789abcdef012", "abcdefghjklmnopqrs"}, + { "0123456789abcdef0123", "abcdefghjklmnopqrst"}, + { "0123456789abcdef01234", "abcdefghjklmnopqrstu"}, + { "0123456789abcdef012345", "abcdefghjklmnopqrstuv"}, + CFSTORE_INIT_1_TABLE_MID_NODE, + { "0123456789abcdef01234567", "abcdefghjklmnopqrstuvwx"}, + { "0123456789abcdef012345678", "abcdefghjklmnopqrstuvwxy"}, + { "0123456789abcdef0123456789", "abcdefghjklmnopqrstuvwxyz"}, + { "0123456789abcdef0123456789a", "b"}, + { "0123456789abcdef0123456789ab", "c"}, + { "0123456789abcdef0123456789abc", "d"}, + { "0123456789abcdef0123456789abcd", "e"}, + { "0123456789abcdef0123456789abcde", "f"}, + { "0123456789abcdef0123456789abcdef", "g"}, + { "com.arm.mbed.wifi.accesspoint.essid", ""}, + { "com.arm.mbed.wifi.accesspoint.essid2", ""}, + { "yotta.your-yotta-registry-module-name.module1", ""}, + { "yotta.hello-world.animal{wobbly-dog}{foot}frontLeft", "missing"}, + { "yotta.hello-world.animal{wobbly-dog}{foot}frontRight", "present"}, + { "yotta.hello-world.animal{wobbly-dog}{foot}backLeft", "half present"}, + { "piety.demands.us.to.honour.truth.above.our.friends", "Aristotle"}, + { "basement.medicine.pavement.government.trenchcoat.off.cough.off.kid.did.when.again.alleyway.friend.cap.pen.dollarbills.ten.foot.soot.put.but.anyway.say.May.DA.kid.did.toes.bows.those.hose.nose.clothes.man.blows.well.well", "TheRollingStone" }, + CFSTORE_INIT_1_TABLE_TAIL, + { NULL, NULL}, +}; + + +/* @brief utility test function to initialise cfstore sram area with some + * KV's to manipulate + * @note this function expects cfstore to have been initialised with + * a call to ARM_CFSTORE_DRIVER::Initialize() + */ +int32_t cfstore_test_init_1(void) +{ + char* read_buf = NULL; + const uint8_t key_name_max_len = CFSTORE_KEY_NAME_MAX_LENGTH+1; + uint8_t key_name_len = 0; + char key_name_buf[key_name_max_len]; + int32_t ret = ARM_DRIVER_ERROR; + ARM_CFSTORE_SIZE len = 0; + ARM_CFSTORE_SIZE max_len = 0; + ARM_CFSTORE_DRIVER* drv = &cfstore_driver; + cfstore_kv_data_t* node = NULL; + ARM_CFSTORE_KEYDESC kdesc; + ARM_CFSTORE_HANDLE_INIT(hkey); + + CFSTORE_FENTRYLOG("%s:entered\r\n", __func__); + memset(&kdesc, 0, sizeof(kdesc)); + memset(key_name_buf, 0, CFSTORE_KEY_NAME_MAX_LENGTH+1); + + /*scan for max length of value blob*/ + node = cfstore_test_init_1_data; + while(node->key_name != NULL) + { + len = strlen(node->value); + if(len > max_len){ + max_len = len; + max_len++; + } + node++; + } + read_buf = (char*) malloc(max_len); + if(read_buf == NULL) { + CFSTORE_ERRLOG("%s:Error: failed to allocated read buffer \r\n", __func__); + return ret; + } + kdesc.drl = ARM_RETENTION_WHILE_DEVICE_ACTIVE; + node = cfstore_test_init_1_data; + while(node->key_name != NULL) + { + CFSTORE_DBGLOG("%s:About to create new node (key_name=\"%s\", value=\"%s\")\r\n", __func__, node->key_name, node->value); + ret = drv->Create(node->key_name, strlen(node->value), &kdesc, hkey); + if(ret < ARM_DRIVER_OK){ + CFSTORE_ERRLOG("%s:Error: failed to create node (key_name=\"%s\", value=\"%s\")\r\n", __func__, node->key_name, node->value); + return ret; + } + + CFSTORE_DBGLOG("%s:length of KV=%d (key_name=\"%s\", value=\"%s\")\r\n", __func__, (int) len, node->key_name, node->value); + len = strlen(node->value); + ret = drv->Write(hkey, (char*) node->value, &len); + if(ret < ARM_DRIVER_OK){ + CFSTORE_ERRLOG("%s:Error: failed to write key (key_name=\"%s\", value=\"%s\")\r\n", __func__, node->key_name, node->value); + drv->Close(hkey); + return ret; + } + if(len != strlen(node->value)){ + CFSTORE_ERRLOG("%s:Error: failed to write full value data (key_name=\"%s\", value=\"%s\"), len=%d\r\n", __func__, node->key_name, node->value, (int) len); + drv->Close(hkey); + return ARM_DRIVER_ERROR; + } + /* read the data back*/ + len = strlen(node->value); + memset(read_buf, 0, max_len); + ret = drv->Read(hkey, read_buf, &len); + if(ret < ARM_DRIVER_OK){ + CFSTORE_ERRLOG("%s:Error: failed to read key (key_name=\"%s\", value=\"%s\")\r\n", __func__, node->key_name, node->value); + drv->Close(hkey); + return ret; + } + if(len != strlen(node->value)){ + CFSTORE_ERRLOG("%s:Error: failed to read full value data (key_name=\"%s\", value=\"%s\"), len=%d, ret=%d\r\n", __func__, node->key_name, node->value, (int) len, (int) ret); + drv->Close(hkey); + return ARM_DRIVER_ERROR; + } + key_name_len = key_name_max_len; + memset(key_name_buf, 0, key_name_len); + drv->GetKeyName(hkey, key_name_buf, &key_name_len); + if(len != strlen(node->value)){ + CFSTORE_ERRLOG("%s:Error: failed to GetKeyName() (key_name=\"%s\", value=\"%s\"), len=%d\r\n", __func__, node->key_name, node->value, (int) len); + drv->Close(hkey); + return ARM_DRIVER_ERROR; + } + CFSTORE_LOG("Created KV successfully (key_name=\"%s\", value=\"%s\")\r\n", key_name_buf, read_buf); + drv->Close(hkey); + node++; + } + free(read_buf); + return ret; +} + +/* @brief test utility function to check a particular KV exists in the + * cfstore using Find() interface + * @note this function expects cfstore to have been initialised with + * a call to ARM_CFSTORE_DRIVER::Initialize() + */ +int32_t cfstore_test_kv_is_found(const char* key_name, bool* bfound) +{ + CFSTORE_FENTRYLOG("%s:entered.\r\n", __func__); + int32_t ret = ARM_DRIVER_ERROR; + ARM_CFSTORE_HANDLE_INIT(prev); + ARM_CFSTORE_HANDLE_INIT(next); + ARM_CFSTORE_DRIVER* drv = &cfstore_driver; + + CFSTORE_ASSERT(bfound != NULL); + CFSTORE_ASSERT(key_name != NULL); + *bfound = 0; + + ret = drv->Find(key_name, prev, next); + if(ret == ARM_DRIVER_OK){ + *bfound = 1; + CFSTORE_DBGLOG("%s:Found key_name=\"%s\", about to call close.\r\n", __func__, key_name); + drv->Close(next); + } + return ret; +} + + +/* @brief support function for generating a kv_name + * @param name buffer to hold kv name + * @param len length of kv name to generate + * @note braces are not included in the generated names as the names are + * of varible length and theyre may be unmatched + * + */ +#define CFSTORE_TEST_KV_NAME_BUF_MAX_DATA (10+26+26+4) +int32_t cfstore_test_kv_name_gen(char* name, const size_t len) +{ + size_t i; + const char buf[CFSTORE_TEST_KV_NAME_BUF_MAX_DATA+1] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.-_@"; + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + for(i = 0; i < len; i++) + { + name[i] = buf[i % CFSTORE_TEST_KV_NAME_BUF_MAX_DATA]; + } + return ARM_DRIVER_OK; +} + +/* @brief test utility function to read the value blob of a specified KV + * @note this function expects cfstore to have been initialised with + * a call to ARM_CFSTORE_DRIVER::Initialize() + */ +int32_t cfstore_test_read(const char* key_name, char* data, ARM_CFSTORE_SIZE* len) +{ + int32_t ret = ARM_DRIVER_ERROR; + ARM_CFSTORE_DRIVER* drv = &cfstore_driver; + ARM_CFSTORE_HANDLE_INIT(hkey); + ARM_CFSTORE_FMODE flags; + + CFSTORE_FENTRYLOG("%s:entered\r\n", __func__); + memset(&flags, 0, sizeof(flags)); + if(key_name == NULL) { + CFSTORE_ERRLOG("%s:invalid key_name argument \r\n", __func__); + goto out0; + } + if(data == NULL) { + CFSTORE_ERRLOG("%s:invalid data argument \r\n", __func__); + goto out0; + } + if(len == NULL) { + CFSTORE_ERRLOG("%s:invalid len argument \r\n", __func__); + goto out0; + } + ret = drv->Open(key_name, flags, hkey); + if(ret < ARM_DRIVER_OK){ + CFSTORE_ERRLOG("%s:Error: failed to open node (key_name=\"%s\")(ret=%d)\r\n", __func__, key_name, (int) ret); + goto out1; + } + ret = drv->Read(hkey, data, len); + if(ret < ARM_DRIVER_OK){ + CFSTORE_ERRLOG("%s:Error: failed to read key (key_name=\"%s\"\r\n", __func__, key_name); + goto out2; + } +out2: + drv->Close(hkey); +out1: +out0: + return ret; +} + +/* @brief write the value blob of a specified KV + * @note this function expects cfstore to have been initialised with + * a call to ARM_CFSTORE_DRIVER::Initialize() + */ +int32_t cfstore_test_write(const char* key_name, const char* data, ARM_CFSTORE_SIZE* len) +{ + int32_t ret = ARM_DRIVER_ERROR; + ARM_CFSTORE_DRIVER* drv = &cfstore_driver; + ARM_CFSTORE_HANDLE_INIT(hkey); + ARM_CFSTORE_FMODE flags; + + CFSTORE_FENTRYLOG("%s:entered\r\n", __func__); + memset(&flags, 0, sizeof(flags)); + if(key_name == NULL) { + CFSTORE_ERRLOG("%s:Error: invalid key_name argument \r\n", __func__); + goto out0; + } + if(data == NULL) { + CFSTORE_ERRLOG("%s:Error: invalid data argument \r\n", __func__); + goto out0; + } + if(len == NULL) { + CFSTORE_ERRLOG("%s:Error: invalid len argument \r\n", __func__); + goto out0; + } + flags.write = 1; + ret = drv->Open(key_name, flags, hkey); + if(ret < ARM_DRIVER_OK){ + CFSTORE_ERRLOG("%s:Error: failed to open node (key_name=\"%s\")(ret=%d)\r\n", __func__, key_name, (int) ret); + goto out1; + } + ret = drv->Write(hkey, data, len); + if(ret < ARM_DRIVER_OK){ + CFSTORE_ERRLOG("%s:Error: failed to write key (key_name=\"%s\")\r\n", __func__, key_name); + goto out2; + } +out2: + drv->Close(hkey); +out1: +out0: + return ret; +} + + diff --git a/storage/cfstore/source/cfstore_test.h b/storage/cfstore/source/cfstore_test.h new file mode 100644 index 0000000000..056c4ae828 --- /dev/null +++ b/storage/cfstore/source/cfstore_test.h @@ -0,0 +1,84 @@ +/** @file cfstore_test.h + * + * mbed Microcontroller Library + * Copyright (c) 2006-2016 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Header file for test support data structures and function API. + */ +#ifndef __CFSTORE_TEST_H +#define __CFSTORE_TEST_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "configuration-store/configuration_store.h" + +/* Defines */ +#define CFSTORE_INIT_1_TABLE_HEAD { "a", ""} +#define CFSTORE_INIT_1_TABLE_MID_NODE { "0123456789abcdef0123456", "abcdefghijklmnopqrstuvwxyz"} +#define CFSTORE_INIT_1_TABLE_TAIL { "yotta.hello-world.animal{wobbly-dog}{foot}backRight", "present"} +#define CFSTORE_TEST_RW_TABLE_SENTINEL 0xffffffff +#define CFSTORE_TEST_BYTE_DATA_TABLE_SIZE 256 +#define CFSTORE_UTEST_MSG_BUF_SIZE 256 +#define CFSTORE_UTEST_DEFAULT_TIMEOUT_MS 10000 +#define CFSTORE_MBED_HOSTTEST_TIMEOUT 60 + +/* support macro for make string for utest _MESSAGE macros, which dont support formatted output */ +#define CFSTORE_TEST_UTEST_MESSAGE(_buf, _max_len, _fmt, ...) \ + do \ + { \ + snprintf((_buf), (_max_len), (_fmt), __VA_ARGS__); \ + }while(0); + + +/* + * Structures + */ + +/* kv data for test */ +typedef struct cfstore_kv_data_t { + const char* key_name; + const char* value; +} cfstore_kv_data_t; + +typedef struct cfstore_test_rw_data_entry_t +{ + uint32_t offset; + char rw_char; +} cfstore_test_rw_data_entry_t; + + +extern cfstore_kv_data_t cfstore_test_init_1_data[]; +extern cfstore_test_rw_data_entry_t cfstore_test_rw_data_table[]; +extern const char* cfstore_test_opcode_str[]; +extern const uint8_t cfstore_test_byte_data_table[CFSTORE_TEST_BYTE_DATA_TABLE_SIZE]; + +int32_t cfstore_test_check_node_correct(const cfstore_kv_data_t* node); +int32_t cfstore_test_create(const char* key_name, const char* data, size_t* len, ARM_CFSTORE_KEYDESC* kdesc); +int32_t cfstore_test_create_table(const cfstore_kv_data_t* table); +int32_t cfstore_test_delete(const char* key_name); +int32_t cfstore_test_delete_all(void); +int32_t cfstore_test_init_1(void); +int32_t cfstore_test_kv_is_found(const char* key_name, bool* bfound); +int32_t cfstore_test_kv_name_gen(char* name, const size_t len); +int32_t cfstore_test_read(const char* key_name, char* data, size_t* len); +int32_t cfstore_test_write(const char* key_name, const char* data, size_t* len); + +#ifdef __cplusplus +} +#endif + +#endif /* __CFSTORE_TEST_H */ diff --git a/storage/cfstore/source/cfstore_utest.h b/storage/cfstore/source/cfstore_utest.h new file mode 100644 index 0000000000..45ac78c89d --- /dev/null +++ b/storage/cfstore/source/cfstore_utest.h @@ -0,0 +1,76 @@ +/** @file cfstore_test.h + * + * mbed Microcontroller Library + * Copyright (c) 2006-2016 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Header file for test support data structures and function API. + */ +#ifndef __CFSTORE_UTEST_H +#define __CFSTORE_UTEST_H + +#include +#include "cfstore_debug.h" +#include "cfstore_test.h" + +using namespace utest::v1; + +void cfstore_utest_default_callback(int32_t status, ARM_CFSTORE_OPCODE cmd_code, void *client_context, ARM_CFSTORE_HANDLE handle) +{ + (void) status; + (void) client_context; + (void) handle; + + CFSTORE_FENTRYLOG("%s:entered: status=%d, cmd_code=%d (%s) handle=%p\n", __func__, (int) status, (int) cmd_code, cfstore_test_opcode_str[cmd_code], handle); + switch(cmd_code) + { + case CFSTORE_OPCODE_INITIALIZE: + case CFSTORE_OPCODE_FLUSH: + case CFSTORE_OPCODE_UNINITIALIZE: + case CFSTORE_OPCODE_CLOSE: + case CFSTORE_OPCODE_CREATE: + case CFSTORE_OPCODE_DELETE: + case CFSTORE_OPCODE_FIND: + case CFSTORE_OPCODE_GET_KEY_NAME: + case CFSTORE_OPCODE_GET_STATUS: + case CFSTORE_OPCODE_GET_VALUE_LEN: + case CFSTORE_OPCODE_OPEN: + case CFSTORE_OPCODE_POWER_CONTROL: + case CFSTORE_OPCODE_READ: + case CFSTORE_OPCODE_RSEEK: + case CFSTORE_OPCODE_WRITE: + default: + CFSTORE_DBGLOG("%s:debug: received asynchronous notification for opcode=%d (%s)", __func__, cmd_code, cmd_code < CFSTORE_OPCODE_MAX ? cfstore_test_opcode_str[cmd_code] : "unknown"); + } + CFSTORE_DBGLOG("%s:about to validate callback\n", __func__); + Harness::validate_callback(); + return; +} + + +static control_t cfstore_utest_default_start(const size_t call_count) +{ + int32_t ret = ARM_DRIVER_ERROR; + ARM_CFSTORE_DRIVER* drv = &cfstore_driver; + char cfstore_utest_msg[CFSTORE_UTEST_MSG_BUF_SIZE]; + + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + (void) call_count; + ret = drv->Initialize(cfstore_utest_default_callback, NULL); + CFSTORE_TEST_UTEST_MESSAGE(cfstore_utest_msg, CFSTORE_UTEST_MSG_BUF_SIZE, "%s:Error: failed to initialize CFSTORE (ret=%" PRId32 ")\n", __func__, ret); + TEST_ASSERT_MESSAGE(ret >= ARM_DRIVER_OK, cfstore_utest_msg); + return CaseTimeout(CFSTORE_UTEST_DEFAULT_TIMEOUT_MS); +} + +#endif /* __CFSTORE_UTEST_H */ diff --git a/storage/cfstore/source/cfstore_uvisor.h b/storage/cfstore/source/cfstore_uvisor.h new file mode 100644 index 0000000000..fb5936d2fd --- /dev/null +++ b/storage/cfstore/source/cfstore_uvisor.h @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2013-2016, ARM Limited, All Rights Reserved + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __CFSTORE_UVISOR_H__ +#define __CFSTORE_UVISOR_H__ + +/* target specifc ACLs */ +#if defined(TARGET_LIKE_FRDM_K64F) + +#define CFSTORE_UVISOR_LED_ON false +#define CFSTORE_UVISOR_LED_OFF true +#define CFSTORE_UVISOR_MAIN_LED LED_BLUE +#define CFSTORE_UVISOR_MAIN_BTN SW2 +#define CFSTORE_UVISOR_MAIN_BTN_PUPD PullUp +#define CFSTORE_UVISOR_MAIN_ACL(acl_list_name) \ + static const UvisorBoxAclItem acl_list_name[] = { \ + {MCG, sizeof(*MCG), UVISOR_TACLDEF_PERIPH}, \ + {SIM, sizeof(*SIM), UVISOR_TACLDEF_PERIPH}, \ + {PORTB, sizeof(*PORTB), UVISOR_TACLDEF_PERIPH}, \ + {PORTC, sizeof(*PORTC), UVISOR_TACLDEF_PERIPH}, \ + {RTC, sizeof(*RTC), UVISOR_TACLDEF_PERIPH}, \ + {LPTMR0, sizeof(*LPTMR0), UVISOR_TACLDEF_PERIPH}, \ + {PIT, sizeof(*PIT), UVISOR_TACLDEF_PERIPH}, \ + {SMC, sizeof(*SMC), UVISOR_TACLDEF_PERIPH}, \ + {UART0, sizeof(*UART0), UVISOR_TACLDEF_PERIPH}, \ + } + +#elif defined(TARGET_LIKE_STM32F429I_DISCO) + +#define CFSTORE_UVISOR_LED_ON false +#define CFSTORE_UVISOR_LED_OFF true +#define CFSTORE_UVISOR_MAIN_LED LED1 +#define CFSTORE_UVISOR_MAIN_BTN USER_BUTTON +#define CFSTORE_UVISOR_MAIN_BTN_PUPD PullDown +#define CFSTORE_UVISOR_MAIN_ACL(acl_list_name) \ + static const UvisorBoxAclItem acl_list_name[] = { \ + {TIM2, sizeof(*TIM2), UVISOR_TACLDEF_PERIPH}, \ + {TIM5, sizeof(*TIM5), UVISOR_TACLDEF_PERIPH}, \ + {GPIOA, sizeof(*GPIOA), UVISOR_TACLDEF_PERIPH}, \ + {GPIOG, sizeof(*GPIOG), UVISOR_TACLDEF_PERIPH}, \ + /* FIXME: secure RCC/EXTI/SYSCFG/FLASH */ \ + {RCC, sizeof(*RCC), UVISOR_TACLDEF_PERIPH}, \ + {EXTI, sizeof(*EXTI), UVISOR_TACLDEF_PERIPH}, \ + {SYSCFG, sizeof(*SYSCFG), UVISOR_TACLDEF_PERIPH}, \ + {FLASH, sizeof(*FLASH), UVISOR_TACLDEF_PERIPH}, \ + {PWR, sizeof(*PWR), UVISOR_TACLDEF_PERIPH}, \ + {USART1, sizeof(*USART1), UVISOR_TACLDEF_PERIPH}, \ + {(void *) 0x42470000, 0x1000, UVISOR_TACLDEF_PERIPH}, \ + } + +#elif defined(TARGET_LIKE_EFM32GG_STK) \ + || defined(TARGET_LIKE_EFM32LG_STK) \ + || defined(TARGET_LIKE_EFM32WG_STK) + +#define CFSTORE_UVISOR_LED_ON false +#define CFSTORE_UVISOR_LED_OFF true +#define CFSTORE_UVISOR_MAIN_LED LED1 +#define CFSTORE_UVISOR_MAIN_BTN BTN0 +#define CFSTORE_UVISOR_MAIN_BTN_PUPD PullUp +#define CFSTORE_UVISOR_MAIN_ACL(acl_list_name) \ + static const UvisorBoxAclItem acl_list_name[] = { \ + {GPIO, sizeof(*GPIO), UVISOR_TACLDEF_PERIPH}, \ + {UART0, sizeof(*UART0), UVISOR_TACLDEF_PERIPH}, \ + {TIMER0, sizeof(*TIMER0), UVISOR_TACLDEF_PERIPH}, \ + /* FIXME: Secure CMU */ \ + {CMU, sizeof(*CMU), UVISOR_TACLDEF_PERIPH}, \ + {RTC, sizeof(*RTC), UVISOR_TACLDEF_PERIPH}, \ + /* FIXME: Secure MSC */ \ + {MSC, sizeof(*MSC), UVISOR_TACLDEF_PERIPH}, \ + /* mbed-hal-silabs requires the DI page to be readable */ \ + {(void*) 0x0FE08000, 0x1000, UVISOR_TACLDEF_SECURE_CONST}, \ + } + +#elif defined(TARGET_LIKE_EFM32PG_STK) + +#define CFSTORE_UVISOR_LED_ON false +#define CFSTORE_UVISOR_LED_OFF true +#define CFSTORE_UVISOR_MAIN_LED LED1 +#define CFSTORE_UVISOR_MAIN_BTN BTN0 +#define CFSTORE_UVISOR_MAIN_BTN_PUPD PullUp +#define CFSTORE_UVISOR_MAIN_ACL(acl_list_name) \ + static const UvisorBoxAclItem acl_list_name[] = { \ + {GPIO, sizeof(*GPIO), UVISOR_TACLDEF_PERIPH}, \ + {USART0, sizeof(*USART0), UVISOR_TACLDEF_PERIPH}, \ + {TIMER0, sizeof(*TIMER0), UVISOR_TACLDEF_PERIPH}, \ + /* FIXME: Secure CMU */ \ + {CMU, sizeof(*CMU), UVISOR_TACLDEF_PERIPH}, \ + {EMU, sizeof(*EMU), UVISOR_TACLDEF_PERIPH}, \ + {RTCC, sizeof(*RTCC), UVISOR_TACLDEF_PERIPH}, \ + /* FIXME: Secure MSC */ \ + {MSC, sizeof(*MSC), UVISOR_TACLDEF_PERIPH}, \ + /* mbed-hal-silabs requires the DI page to be readable */ \ + {(void*) 0x0FE08000, 0x1000, UVISOR_TACLDEF_SECURE_CONST}, \ + } + +#else + +#define CFSTORE_UVISOR_LED_ON true +#define CFSTORE_UVISOR_LED_OFF false +#define CFSTORE_UVISOR_MAIN_LED NC +#define CFSTORE_UVISOR_MAIN_BTN NC +#define CFSTORE_UVISOR_MAIN_BTN_PUPD PullNone +#define CFSTORE_UVISOR_MAIN_ACL(acl_list_name) \ + static const UvisorBoxAclItem acl_list_name[] = {} + +#endif + +#endif diff --git a/storage/cfstore/source/configuration_store.c b/storage/cfstore/source/configuration_store.c new file mode 100644 index 0000000000..c943172e5e --- /dev/null +++ b/storage/cfstore/source/configuration_store.c @@ -0,0 +1,4098 @@ +/** @file configuration_store.c + * + * mbed Microcontroller Library + * Copyright (c) 2006-2016 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include + +#if defined CFSTORE_CONFIG_MBED_OS_VERSION && CFSTORE_CONFIG_MBED_OS_VERSION == 3 +#include +#endif /* CFSTORE_CONFIG_MBED_OS_VERSION == 3 */ +#include "cfstore_config.h" +#ifdef YOTTA_CFG_CFSTORE_UVISOR +#include "uvisor-lib/uvisor-lib.h" +#endif /* YOTTA_CFG_CFSTORE_UVISOR */ +#if defined CFSTORE_CONFIG_BACKEND_FLASH_ENABLED && CFSTORE_CONFIG_BACKEND_FLASH_ENABLED == 1 +#include +#include +#include +#endif /* CFSTORE_CONFIG_BACKEND_FLASH_ENABLED */ +#include +#include "cfstore_debug.h" +#include "cfstore_list.h" + + +#ifdef CFSTORE_DEBUG +uint32_t cfstore_optDebug_g = 1; +uint32_t cfstore_optLogLevel_g = CFSTORE_LOG_NONE; /*CFSTORE_LOG_NONE|CFSTORE_LOG_ERR|CFSTORE_LOG_DEBUG|CFSTORE_LOG_FENTRY */ +uint32_t cfstore_optLogTracepoint_g = CFSTORE_TP_NONE; /*CFSTORE_TP_NONE|CFSTORE_TP_CLOSE|CFSTORE_TP_CREATE|CFSTORE_TP_DELETE|CFSTORE_TP_FILE|CFSTORE_TP_FIND|CFSTORE_TP_FLUSH|CFSTORE_TP_INIT|CFSTORE_TP_OPEN|CFSTORE_TP_READ|CFSTORE_TP_WRITE|CFSTORE_TP_VERBOSE1|CFSTORE_TP_VERBOSE2|CFSTORE_TP_VERBOSE3|CFSTORE_TP_FENTRY */ +#endif + + +/* + * Externs + */ +#if defined CFSTORE_CONFIG_BACKEND_FLASH_ENABLED && CFSTORE_CONFIG_BACKEND_FLASH_ENABLED == 1 +extern ARM_DRIVER_STORAGE ARM_Driver_Storage_(0); +ARM_DRIVER_STORAGE *cfstore_storage_drv = &ARM_Driver_Storage_(0); +#endif /* CFSTORE_CONFIG_BACKEND_FLASH_ENABLED */ + +/* + * Defines + * + * CFSTORE_FLASH_STACK_BUF_SIZE + * when performing flush, if the program_unit <= CFSTORE_FLASH_STACK_BUF_SIZE octets then a + * stack buffer is used to perform the tail write. Otherwise a buffer is malloced + * + * CFSTORE_FLASH_AREA_SIZE_MIN + * valid sizes of areas should always be greater than the size of the header, and therefore + * greater than this value, which is defined as smaller than the header size + * + * ARM_DRIVER_OK_DONE + * value that indicates an operation has been done i.e. a value > 0 + */ +#define CFSTORE_KEY_NAME_CHARS_ACCEPTABLE "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ{}.-_@" +#define CFSTORE_KEY_NAME_QUERY_CHARS_ACCEPTABLE CFSTORE_KEY_NAME_CHARS_ACCEPTABLE"*" +#define CFSTORE_HKVT_REFCOUNT_MAX 0xff +#define CFSTORE_LOCK_REFCOUNT_MAX 0xffff +#define CFSTORE_FILE_CREATE_MODE_DEFAULT (ARM_CFSTORE_FMODE)0 +#define CFSTORE_FLASH_STACK_BUF_SIZE 64 +#define CFSTORE_FLASH_AREA_SIZE_MIN (sizeof(cfstore_area_header_t) - 1) +#define cfstore_fsm_null NULL +#define CFSTORE_SENTINEL 0x7fffffff +#define CFSTORE_CALLBACK_RET_CODE_DEFAULT 0x1 +#define ARM_DRIVER_OK_DONE 1 + +/* + * Simple Types + */ +#define CFSTORE_LOCK uint32_t + + +/* + * Structures + */ + +/** @brief + * + * @param key_permissions + * bottom 6 bits contain the ACLs-bits (owner read/write/execute, + * other read/write/execute). The remaining bits in this field are + * used for the Device Data Security Protection Features bit field, + * bits are low-active + * @param perm_owner_read + * if set => this KV is owner readable + * @param perm_owner_write + * if set => this KV is owner writable + * @param perm_owner_execute + * if set => this KV is owner executable + * @param perm_other_read + * if set => this KV is world readable + * @param perm_other_write + * if set => this KV is world writable + * @param perm_other_execute + * if set => this KV is world executable + * @param klength + * key name size including zero-padding + * @param vlength + * this value fragment length + * @param refcount + * Number of handles open on this hkvt + * + * @param delete + * indicates this KV is being deleted + */ +typedef struct cfstore_area_header_t +{ + uint32_t vlength; + uint8_t klength; + uint8_t perm_owner_read : 1; + uint8_t perm_owner_write : 1; + uint8_t perm_owner_execute : 1; + uint8_t perm_other_read : 1; + uint8_t perm_other_write : 1; + uint8_t perm_other_execute : 1; + uint8_t reserved : 2; + uint8_t refcount; + struct flags_t { + uint8_t delete : 1; + uint8_t reserved : 7; + } flags ; +} cfstore_area_header_t; + + +/* helper struct */ +typedef struct cfstore_area_hkvt_t +{ + uint8_t *head; + uint8_t *key; + uint8_t *value; + uint8_t *tail; +} cfstore_area_hkvt_t; + + +/* helper struct */ +typedef struct cfstore_client_notify_data_t +{ + uint32_t opcode; + int32_t status; + ARM_CFSTORE_HANDLE handle; +} cfstore_client_notify_data_t; + +/* @brief test fsm states and events */ +typedef enum cfstore_fsm_state_t { + cfstore_fsm_state_stopped = 0, + cfstore_fsm_state_initing, + cfstore_fsm_state_reading, + cfstore_fsm_state_logging, + cfstore_fsm_state_committing, + cfstore_fsm_state_resetting, + cfstore_fsm_state_ready, /* ready for next flash journal command to arise */ + cfstore_fsm_state_max +} cfstore_fsm_state_t; + +/* @brief test fsm events */ +typedef enum cfstore_fsm_event_t { + cfstore_fsm_event_init_done = 0, + cfstore_fsm_event_read_done, + cfstore_fsm_event_log_done, + cfstore_fsm_event_commit_req, + cfstore_fsm_event_commit_done, + cfstore_fsm_event_reset_done, + cfstore_fsm_event_max, +} cfstore_fsm_event_t; + +typedef int32_t (*cfstore_fsm_handler)(void* ctx); + +/* @brief flash finite state machine helper function */ +typedef struct cfstore_fsm_t +{ + cfstore_fsm_state_t state; + cfstore_fsm_event_t event; +} cfstore_fsm_t; + + +#ifdef CFSTORE_DEBUG +#if defined CFSTORE_CONFIG_BACKEND_FLASH_ENABLED && CFSTORE_CONFIG_BACKEND_FLASH_ENABLED == 1 +/* strings used for debug trace */ +static const char* cfstore_flash_opcode_str[] = +{ + "FLASH_JOURNAL_OPCODE_INITIALIZE", + "FLASH_JOURNAL_OPCODE_GET_INFO", + "FLASH_JOURNAL_OPCODE_READ_BLOB", + "FLASH_JOURNAL_OPCODE_LOG_BLOB", + "FLASH_JOURNAL_OPCODE_COMMIT", + "FLASH_JOURNAL_OPCODE_RESET", +}; + +static const char* cfstore_flash_state_str[] = +{ + "stopped", + "initializing", + "reading", + "logging", + "committing", + "resetting", + "ready", + "unknown" +}; + +static const char* cfstore_flash_event_str[] = +{ + "init_done", + "read_done", + "log_done", + "commit_req", + "commit_done", + "reset_done", + "unknown" +}; +#endif /* CFSTORE_CONFIG_BACKEND_FLASH_ENABLED */ +#endif /* CFSTORE_DEBUG */ + + +/* + * Forward decl + */ +#if defined CFSTORE_CONFIG_BACKEND_FLASH_ENABLED && CFSTORE_CONFIG_BACKEND_FLASH_ENABLED == 1 +static int32_t cfstore_fsm_state_handle_event(cfstore_fsm_t* fsm, cfstore_fsm_event_t event, void* context); +static int32_t cfstore_fsm_state_set(cfstore_fsm_t* fsm, cfstore_fsm_state_t new_state, void* ctx); +#endif /* CFSTORE_CONFIG_BACKEND_FLASH_ENABLED */ +static int32_t cfstore_get_key_name_ex(cfstore_area_hkvt_t *hkvt, char* key_name, uint8_t *key_name_len); + + +/* Walking Area HKVT's While Inserted a New HKVT: + * Implementation Note 1 [NOTE1] + * + * The implementation must address the following problem: + * - client1 may be creating a new KV into area_0, which means inserting the + * header-key-value-tail data into area_0. + * - concurrently, client2 (through a call to Find()) is walking KVs in area_0, + * and the walk has to be safe against the insertion of the new KV. + * + * This problem is addressed in the by using the cfstore_ctx_g.rw_lock to police + * access to the area when making changes. + * - Walking the KVs in area_0 is performed using the header structures, + * which contain key and value lengths required to find the start of the + * next hkvt. These must not change under the client. + * - The Find() walk is terminated when the hkvt header pointer is found to + * point to cfstore_ctx_g.area_0_tail i.e. when this arises then the + * iterator knows its come to the end of the hkvt's in the area. + * - When inserting a new KV, the last operation to be performed is to + * update cfstore_ctx_g.area_0_tail to point to the new tail. This + * operation also reveals the new KV to other operations including + * the Find(). All the header, key, value and tail data for the + * HKVT must be setup correctly before the tail pointer is updated. + * + * Memory Management (todo: future support) + * Implementation Note 2 [NOTE2] + * CFSTORE supports using a client provisioned SRAM slab rather than using realloc() to allocated heap + * memory. This has the following advantages: + * - the client is in control of the memory allocation. + * - realloc() cannot fail (e.g. due to memory leaks losing memory) as the sram has been preprovisioned. + * This makes the system more resilient. + * The client specifes the sram slab in the following way: + * - having target.json defined yotta_config.h symbol for CFSTORE_SRAM_START_ADDR, CFSTORE_SRAM_SIZE + * and #ifdef on these values to use that memory area for area_0 rather than using malloc. + * - for the case where a client tries to create a KV which causes area_0 to exceed CFSTORE_SRAM_SIZE + * then the operation is failed. + * - modify the API so that the client is responsible for allocating the memory the the CFSTORE internal + * data structures, with the size of the internal data structure exposed through a #define. + * The contents of the buffer are opaque to the client. The reasons for this are as follows: + * - to allow the cfstore implementation not to use malloc(). + * - the memory allocation policy for allocating the memory of CFSTORE internal data structures + * can be decided and implemented by the client + * - for clients written in C++, its possible to have a static class with the memory for the + * internal context, and the static class memory area is given to CFSTORE for use, so it + * provides good C++ support. + * - The SRAM area can be allocated with the previous point, and the handle associated data + * structures i.e. cfstore_file_t, can be covered by the supplied buffers to those functions + * creating handles. + * - currently neither target.json nor config.json allow a symbol in yotta_config.h to be defined + * for the current case of CFSTORE being a yotta module/library. + * + * UVISOR Integration (todo) + * Implementation Note 3 [NOTE3] + * Outstanding Questions: + * - uvisor_ctx. Should all functions use this to access the global data context? + * - see cfstore_ctx_get() for an implementation + * - compile in cfstore_ctx_g only when not using uvisor + * - how do you allocate heap memory objects with uvisor protections? + * - doesnt seem to be an api for this yet. + * - will be required for sram storage of KVs i.e. "the area". + * - will be required for file objects + * - Q: is it safe to store the caller_box_id in the cfstore_file_t? + * A: no, because the cfstore_file_t is held in client controlled memory (opaque hkey) + * so the client can modify from under cfstore, breaching security if it was used + * by other cfstore methods. + * - method for securing access: + * - create()/open() checks namespace etc, and then creates/opens cfstore_file_t + * and returns hkey (opaque cfstore_file_t) for subsequent use by api calls. + * - read/write/rseek etc check the kv pathname accessible via cfstore_file_t::head + * is within the callers namespace. + * - we are trusting the caller to be secure and not be malicious? + * - put "uvisor-lib" : "^2.0.0" in module.json. not necessary as mbed-drivers has this dep. + * - flash-journal change from using NVIC_Set/GetVector() to VIRQ_Set/GetVector() + * + */ + +/* + * @brief CS global context that maintains state + * + * @param area_0_start + * pointer to start of malloc-ed memory block for containing area_0 + * + * @param area_0_head + * pointer to area_0 header struct within the memblock. + * - ((cfstore_area_header_t*) area_0)->refcount is the number of + * open handles in the whole of area_0. + * - accessed in app & intr context; hence needs CS protection. + * + * @param area_0_tail + * pointer to address in the sram after the last byte of the last + * KV. Note there can be padding after the area_0_tail to align the + * sram area with flash program_unit (or 1 if SRAM only version) + * to facilitate reading/writing to flash. + * - accessed in app & intr context; hence needs CS protection. + * + * @param area_0_end + * pointer to end area_0 of area_0 memblock (last memory address). + * + * @param rw_area0_lock + * lock used to make CS re-entrant e.g. only 1 flush operation can be + * performed at a time while no readers/writers have handles open + * to KVs. The lock is to protect access to the following: + * - cfstore_ctx_g.area_0_head/cfstore_ctx_g.area_0_tail. Realloc() + * in Delete() and Create() can cause these pointers to change. + * + * @param client_notify_data + * fsm handler functions set a flag for a client notification call + * to be made after fsm handler functions have been completed. This + * block holds the client notification status data for the callback. + * + * @param area_dirty_flag + * flag indicating that the area has been written and therefore is + * dirty with respect to the data persisted to flash. + * + * @expected_blob_size expected_blob_size = area_0_tail - area_0_head + pad + * In the case of reading from flash into sram, this will be be size + * of the flash blob (rounded to a multiple program_unit if not + * already so). + * In the case of writing to flash, this the size of all the KV's + * plus padding so the sram blob size is a multiple of flash + * program_unit. + * - accessed in app & intr context; hence needs CS protection. + */ +typedef struct cfstore_ctx_t +{ + cfstore_list_node_t file_list; + int32_t init_ref_count; + CFSTORE_LOCK rw_area0_lock; + ARM_POWER_STATE power_state; + uint8_t *area_0_head; + uint8_t *area_0_tail; + cfstore_fsm_t fsm; + int32_t status; + + /* client notification data */ + void* client_context; + ARM_CFSTORE_CALLBACK client_callback; + cfstore_client_notify_data_t client_notify_data; + + /* flags */ + uint32_t client_callback_notify_flag : 1; + uint32_t area_dirty_flag : 1; + uint32_t f_reserved0 : 30; + +#if defined CFSTORE_CONFIG_BACKEND_FLASH_ENABLED && CFSTORE_CONFIG_BACKEND_FLASH_ENABLED == 1 + /* flash journal related data */ + FlashJournal_t jrnl; + FlashJournal_Info_t info; + FlashJournal_OpCode_t cmd_code; + uint64_t expected_blob_size; +#endif /* CFSTORE_CONFIG_BACKEND_FLASH_ENABLED */ +} cfstore_ctx_t; + + +/* + * @brief file structure for KV, one per open file handle. + * + * @param head + * pointer to head of KV + * + * @param rlocation + * read location of rseek to move + * + * @param read + * indicates file is readable, + * @param writable + * indicates file is readable, + * @param executable + * indicates file is readable, + * @param uvisor_client_box_id + * box id of caller using this file. set on create/open and thereafter used by other methods to check accesses. + * Q: is it safe to store this here? Is it of any value? i.e. a client can change the value + * after cfstore has set it so cfstore cant rely on it being secure. + */ +typedef struct cfstore_file_t +{ + cfstore_list_node_t node; + uint32_t rlocation; + uint32_t wlocation; + uint8_t *head; + ARM_CFSTORE_FMODE flags; +#ifdef YOTTA_CFG_CFSTORE_UVISOR + // todo: add this into mix. + //int uvisor_client_box_id; +#endif + +} cfstore_file_t; + +/* @brief structure used to compose table for mapping flash journal error codes to cfstore error codes */ +typedef struct cfstore_flash_journal_error_code_node +{ + int32_t flash_journal_error_code; + int32_t cfstore_error_code; +} cfstore_flash_journal_error_code_node; + + +/* + * Globals + */ +#ifndef YOTTA_CFG_CONFIG_HARDWARE_MTD_ASYNC_OPS +static ARM_CFSTORE_CAPABILITIES cfstore_caps_g = { .asynchronous_ops = 1, .uvisor_support_enabled = 0 }; +#else +static ARM_CFSTORE_CAPABILITIES cfstore_caps_g = { .asynchronous_ops = YOTTA_CFG_CONFIG_HARDWARE_MTD_ASYNC_OPS, .uvisor_support_enabled = 0 }; +#endif /* YOTTA_CFG_CONFIG_HARDWARE_MTD_ASYNC_OPS */ + +static const ARM_DRIVER_VERSION cfstore_driver_version_g = { .api = ARM_CFSTORE_API_VERSION, .drv = ARM_CFSTORE_DRV_VERSION }; + +#ifndef YOTTA_CFG_CFSTORE_UVISOR +/* uvisor is not being used so instantiate a context */ +static cfstore_ctx_t cfstore_ctx_g = { + .file_list.next = NULL, + .file_list.prev = NULL, + .init_ref_count = 0, + .rw_area0_lock = 0, + .power_state = ARM_POWER_FULL, + .area_0_head = NULL, + .area_0_tail = NULL, + .client_callback = NULL, + .client_context = NULL, + .f_reserved0 = 0, +}; +#endif /* YOTTA_CFG_CFSTORE_UVISOR */ + +#ifdef YOTTA_CFG_CFSTORE_UVISOR + +/* + * Configure the secure box compartment + */ +static const char const cfstore_uvisor_namespace_root_g[] = "com.arm.mbed."; +// UVISOR_BOX_NAMESPACE("com.arm.mbed.configuration-store"); +// macro: static const char *const __uvisor_box_namespace = box_namespace +static const char *const __uvisor_box_namespace = "com.arm.mbed.configuration-store"; + +/* although the descriptor is empty, the main box descriptor is inherited and added to whats here. */ +static const UvisorBoxAclItem cfstore_acl_list_g[] = { + /* todo: this needs completing with correct data for the secure flash partition above the binary + * + 0xabaadfood = start of secure flash in address map (flash journal partition + 0xbeefbeef = size in bytes of secure flash partition + {(void *) 0xabaadfood, 0xbeefbeef, UVISOR_TACLDEF_PERIPH}, + */ + /* put reference to k64 subfamily reference manual and cmsis k64f target header as to where this comes from */ + {FTFE, sizeof(*FTFE), UVISOR_TACLDEF_PERIPH}, +}; + +/* UVISOR_BOX_CONFIG_CTX(configuration_store, UVISOR_BOX_STACK_SIZE, cfstore_ctx_t); + * + * It would be better to use the following macro: + * UVISOR_BOX_CONFIG(configuration_store, cfstore_acl_list_g, UVISOR_BOX_STACK_SIZE, cfstore_ctx_t); + * rather than the unpacked macro code that follows. + * + * #define __UVISOR_BOX_CONFIG(box_name, acl_list, acl_list_count, stack_size, context_size) \ + * \ + * uint8_t __attribute__((section(".keep.uvisor.bss.boxes"), aligned(32))) \ + * box_name ## _reserved[UVISOR_STACK_SIZE_ROUND(((UVISOR_MIN_STACK(stack_size) + (context_size))*8)/6)]; \ + * \ + * static const __attribute__((section(".keep.uvisor.cfgtbl"), aligned(4))) UvisorBoxConfig box_name ## _cfg = { \ + * UVISOR_BOX_MAGIC, \ + * UVISOR_BOX_VERSION, \ + * UVISOR_MIN_STACK(stack_size), \ + * context_size, \ + * __uvisor_box_namespace, \ + * acl_list, \ + * acl_list_count \ + * }; \ + * \ + * extern const __attribute__((section(".keep.uvisor.cfgtbl_ptr"), aligned(4))) void * const box_name ## _cfg_ptr = &box_name ## _cfg; + * + * However, the macro currently generates warnings that need to be fixed i.e. + * ===================================================================================================================================================================================== + * d:/datastore/public/jobs/yr2016/2247/sdh_dev_10/configuration-store/source/configuration_store.c:490:1: error: initializer element is not constant + * UVISOR_BOX_CONFIG(configuration_store, cfstore_acl_list_g, UVISOR_BOX_STACK_SIZE, cfstore_ctx_t); + * ^ + * d:/datastore/public/jobs/yr2016/2247/sdh_dev_10/configuration-store/source/configuration_store.c:490:1: error: (near initialization for 'configuration_store_cfg.box_namespace') + * In file included from d:/datastore/public/jobs/yr2016/2247/sdh_dev_10/configuration-store/yotta_modules/uvisor-lib/uvisor-lib/uvisor-lib.h:38:0, + * from d:/datastore/public/jobs/yr2016/2247/sdh_dev_10/configuration-store/source/configuration_store.c:27: + * d:/datastore/public/jobs/yr2016/2247/sdh_dev_10/configuration-store/source/configuration_store.c:490:19: warning: 'configuration_store_cfg_ptr' initialized and declared 'extern' + * UVISOR_BOX_CONFIG(configuration_store, cfstore_acl_list_g, UVISOR_BOX_STACK_SIZE, cfstore_ctx_t); + * ^ + * d:/datastore/public/jobs/yr2016/2247/sdh_dev_10/configuration-store/yotta_modules/uvisor-lib/uvisor-lib/box_config.h:74:95: note: in definition of macro '__UVISOR_BOX_CONFIG' + * extern const __attribute__((section(".keep.uvisor.cfgtbl_ptr"), aligned(4))) void * const box_name ## _cfg_ptr = &box_name ## _cfg; + * ^ + * d:/datastore/public/jobs/yr2016/2247/sdh_dev_10/configuration-store/yotta_modules/uvisor-lib/uvisor-lib/box_config.h:57:55: note: in expansion of macro '__UVISOR_BOX_CONFIG_CONTEXT' + * #define __UVISOR_BOX_MACRO(_1, _2, _3, _4, NAME, ...) NAME + * ^ + * d:/datastore/public/jobs/yr2016/2247/sdh_dev_10/configuration-store/yotta_modules/uvisor-lib/uvisor-lib/box_config.h:101:5: note: in expansion of macro 'UVISOR_BOX_CONFIG_ACL' + * UVISOR_BOX_CONFIG_ACL(__VA_ARGS__) + * ^ + * d:/datastore/public/jobs/yr2016/2247/sdh_dev_10/configuration-store/source/configuration_store.c:490:1: note: in expansion of macro 'UVISOR_BOX_CONFIG' + * UVISOR_BOX_CONFIG(configuration_store, cfstore_acl_list_g, UVISOR_BOX_STACK_SIZE, cfstore_ctx_t); + * ^ + * ninja: build stopped: subcommand failed. + * error: command ['ninja'] failed + * ===================================================================================================================================================================================== + * The UVISOR_BOX_CONFIG() macro expands to include the following: + * extern const __attribute__((section(".keep.uvisor.cfgtbl_ptr"), aligned(4))) void * const configuration_store_cfg_ptr = &configuration_store_cfg; + * The extern at the beginning of the line creates a warning when in a c file, and so needs to be removed/fixed. + * There are also many other warnings from the macro expansion which need to be investigated further. + * + * todo: possible investigation: move configuration_store.c -> configuration_store.cpp + */ +uint8_t __attribute__((section(".keep.uvisor.bss.boxes"), aligned(32))) configuration_store_reserved[UVISOR_STACK_SIZE_ROUND(((UVISOR_MIN_STACK(UVISOR_BOX_STACK_SIZE) + (sizeof(cfstore_ctx_t)))*8)/6)]; +static const __attribute__((section(".keep.uvisor.cfgtbl"), aligned(4))) UvisorBoxConfig configuration_store_cfg = { + UVISOR_BOX_MAGIC, + UVISOR_BOX_VERSION, + UVISOR_MIN_STACK(UVISOR_BOX_STACK_SIZE), + sizeof(cfstore_ctx_t), + "com.arm.mbed.configuration-store", //problem using__uvisor_box_namespace defined above so inserting string directly here + cfstore_acl_list_g, + UVISOR_ARRAY_COUNT(cfstore_acl_list_g) +}; + +const __attribute__((section(".keep.uvisor.cfgtbl_ptr"), aligned(4))) void * const configuration_store_cfg_ptr = &configuration_store_cfg; +UVISOR_EXTERN cfstore_ctx_t * const uvisor_ctx; + +#endif /* YOTTA_CFG_CFSTORE_UVISOR */ + +/* + * client notifier helper function + */ +static void cfstore_client_notify_data_init(cfstore_client_notify_data_t* data, uint32_t opcode, int32_t status, ARM_CFSTORE_HANDLE handle) +{ + memset(data, 0, sizeof(cfstore_client_notify_data_t)); + data->opcode = opcode; + data->status = status; + data->handle = handle; +} + +/* + * cfstore_ctx_t methods + */ + +/* @brief helper function to reset cfstore_ctx_g state when out of memory is received from malloc */ +static void cfstore_ctx_reset(cfstore_ctx_t* ctx) +{ + CFSTORE_ASSERT(ctx!= NULL); + CFSTORE_INIT_LIST_HEAD(&ctx->file_list); + ctx->area_0_head = NULL; + ctx->area_0_tail = NULL; + return; +} + +/* @brief helper function to report whether the initialisation flag has been set in the cfstore_ctx_g */ +static bool cfstore_ctx_is_initialised(cfstore_ctx_t* ctx) +{ + CFSTORE_ASSERT(ctx!= NULL); + return ctx->init_ref_count > 0 ? true : false; +} + +/* @brief helper function to return a pointer to the global cfstore context. */ +static inline cfstore_ctx_t* cfstore_ctx_get(void) +{ +#ifdef YOTTA_CFG_CFSTORE_UVISOR + /* use the secure cfstore_ctx_t struct allocated by uvisor for use */ + return (cfstore_ctx_t*) uvisor_ctx; +#else + /* use the insecure statically allocated data struct */ + return &cfstore_ctx_g; +#endif +} + +/* @brief helper function to compute the size of the sram area in bytes */ +static ARM_CFSTORE_SIZE cfstore_ctx_get_area_len(void) +{ + ARM_CFSTORE_SIZE size = 0; + cfstore_ctx_t* ctx = cfstore_ctx_get(); + + size = (ARM_CFSTORE_SIZE) (ctx->area_0_tail - ctx->area_0_head); + return size; +} + +/* @brief helper function to get the program_unit */ +static inline uint32_t cfstore_ctx_get_program_unit(cfstore_ctx_t* ctx) +{ + CFSTORE_ASSERT(ctx!= NULL); +#if defined CFSTORE_CONFIG_BACKEND_FLASH_ENABLED && CFSTORE_CONFIG_BACKEND_FLASH_ENABLED == 1 + return ctx->info.program_unit; +#else + /* the program unit is 1 so byte aligned when no flash backend present */ + (void) ctx; + return 1; +#endif /* CFSTORE_CONFIG_BACKEND_FLASH_ENABLED */ + +} + +static inline void cfstore_ctx_client_notify(cfstore_ctx_t* ctx, cfstore_client_notify_data_t* data) +{ + CFSTORE_FENTRYLOG("%s:entered: ctx=%p, ctx->client_callback=%p, ctx->client_context=%p\n", __func__, ctx, ctx->client_callback, ctx->client_context); + if(ctx->client_callback){ + ctx->client_callback(data->status, (ARM_CFSTORE_OPCODE) data->opcode, ctx->client_context, data->handle); + } + return; +} + +/* + * CFSTORE_YOTTA_CFG_CFSTORE_SRAM_ADDR + * client can supply a SRAM slab address and size for + * CFSTORE internal use. This is a default addr + * for development use. Should be defined by client + * CFSTORE_YOTTA_CFG_CFSTORE_SRAM_SIZE + * size of sram area. Should be define by client + */ +#ifndef CFSTORE_YOTTA_CFG_CFSTORE_SRAM_ADDR +/* if the client doesnt provide a memory slab then CFSTORE uses realloc internally*/ + +#ifndef CFSTORE_DEBUG +#define CFSTORE_FREE free +#define CFSTORE_MALLOC malloc +#define CFSTORE_REALLOC realloc +#else + +static uint32_t cfstore_malloc_size_g = 0; +#define CFSTORE_MALLOC malloc + +static void* CFSTORE_REALLOC(void *ptr, size_t size) +{ + void* mem; + + mem = realloc(ptr, size); + CFSTORE_TP(CFSTORE_TP_MEM, "%s:ptr=%p, mem=%p, old_size=%u, new_size=%u.\n", __func__, ptr, mem, (int) cfstore_malloc_size_g, (int) size); + cfstore_malloc_size_g = size; + return mem; +} + +static void CFSTORE_FREE(void *ptr) +{ + free(ptr); + CFSTORE_TP(CFSTORE_TP_MEM, "%s:ptr=%p, old_size=%u, new_size=%u.\n", __func__, ptr, (int) cfstore_malloc_size_g, 0); + cfstore_malloc_size_g = 0; + return; +} +#endif /* CFSTORE_DEBUG */ + +/* memory tracking */ + +#else +#define CFSTORE_FREE CFSTORE_ASSERT(0) +#define CFSTORE_MALLOC CFSTORE_ASSERT(0) +#define CFSTORE_REALLOC cfstore_realloc + + + +/* function to realloc from a client provided memory slab + * size = new size of area used by sram + * ptr is always head of slab + * + * The cfstore_realloc() function changes the size of the memory + * block pointed to by ptr to size bytes, backed by the client + * provided memory slab. The contents will be unchanged in the + * range from the start of the region up to the minimum of the + * old and new sizes. If the new size is larger than the old size, + * the added memory will not be initialized. + * + * ptr + * ptr should be set to null on the first call to this function and + * for size > 0 && size <= CFSTORE_YOTTA_CFG_CFSTORE_SRAM_SIZE + * CFSTORE_YOTTA_CFG_CFSTORE_SRAM_ADDR will be returned. + * On subsequent calls, ptr must have been returned by an earlier + * call to this function. + * + * size + * if size is equal to zero, and ptr is not NULL, then the call is + * equivalent to reseting the memory area and NULL will be returned. + */ +void *cfstore_realloc(void *ptr, ARM_CFSTORE_SIZE size) +{ + static uint8_t *cfstore_sram_head = NULL; + static uint8_t *cfstore_sram_tail = NULL; + + if(size > 0) { + if(size <= CFSTORE_YOTTA_CFG_CFSTORE_SRAM_SIZE) { + if(ptr == NULL) { + memset(CFSTORE_YOTTA_CFG_CFSTORE_SRAM_ADDR, 0, CFSTORE_YOTTA_CFG_CFSTORE_SRAM_SIZE); + cfstore_sram_head = CFSTORE_YOTTA_CFG_CFSTORE_SRAM_ADDR; + } + cfstore_sram_tail = cfstore_sram_head + size; + return (void*) cfstore_sram_head; + } + /* requested size is too big so fail the operation by setting + * head/tail to NULL */ + } + /* size == 0 => reset */ + cfstore_sram_head = NULL; + cfstore_sram_tail = NULL; + return (void*) cfstore_sram_head; +} + +#endif /* CFSTORE_YOTTA_CFG_CFSTORE_SRAM_ADDR */ + +/* + * Platform Specific Function Implementations + */ +#ifdef TARGET_LIKE_FRDM_K64F_GCC +static inline void cfstore_critical_section_init(CFSTORE_LOCK* lock){ *lock = 0; } +static inline void cfstore_critical_section_unlock(CFSTORE_LOCK* lock, const char* tag) +{ + (void) lock; + (void) tag; + CFSTORE_DBGLOG("%s:before critical_section_exit()(lock=%lu)\n", tag, *lock); + (*lock)--; + /* todo: put mbedosv3++ critical section exit here */ + CFSTORE_DBGLOG("%s:after critical_section_exit()(lock=%lu)\n", tag, *lock); +} + +static inline void cfstore_critical_section_lock(CFSTORE_LOCK* lock, const char* tag) +{ + (void) lock; + (void) tag; + CFSTORE_DBGLOG("%s:before critical_section_enter()(lock=%lu)\n", tag, *lock); + /* todo: put mbedosv3++ critical section enter here */ + (*lock)++; + CFSTORE_DBGLOG("%s:after critical_section_enter()(lock=%lu)\n", tag, *lock); +} + +static CFSTORE_INLINE int32_t cfstore_hkvt_refcount_dec(cfstore_area_hkvt_t* hkvt, uint8_t *refcount) +{ + cfstore_area_header_t *hdr = (cfstore_area_header_t*) hkvt->head; + + /* todo: put mbedosv3++ critical section enter here */ + hdr->refcount--; + if(refcount) *refcount = hdr->refcount; + /* todo: put mbedosv3++ critical section exit here */ + return ARM_DRIVER_OK; +} + +static CFSTORE_INLINE int32_t cfstore_hkvt_refcount_inc(cfstore_area_hkvt_t* hkvt, uint8_t *refcount) +{ + int32_t ret = ARM_CFSTORE_DRIVER_ERROR_HANDLE_COUNT_MAX; + cfstore_area_header_t *hdr = (cfstore_area_header_t*) hkvt->head; + + /* todo: put mbedosv3++ critical section enter here */ + if(hdr->refcount < CFSTORE_HKVT_REFCOUNT_MAX) + { + hdr->refcount++; + if(refcount) *refcount = hdr->refcount; + ret = ARM_DRIVER_OK; + } + /* todo: put mbedosv3++ critical section exit here */ + return ret; +} +#endif /* TARGET_LIKE_FRDM_K64F_GCC */ + + +#ifdef TARGET_LIKE_X86_LINUX_NATIVE +static inline void cfstore_critical_section_init(CFSTORE_LOCK* lock){ *lock = 0; } +static inline void cfstore_critical_section_lock(CFSTORE_LOCK* lock, const char* tag){ (void) tag; __sync_fetch_and_add(lock, 1); } +static inline void cfstore_critical_section_unlock(CFSTORE_LOCK* lock, const char* tag){(void) tag; __sync_fetch_and_sub(lock, 1); } + +static CFSTORE_INLINE int32_t cfstore_hkvt_refcount_dec(cfstore_area_hkvt_t* hkvt, uint8_t *refcount) +{ + cfstore_area_header_t *hdr = (cfstore_area_header_t*) hkvt->head; + uint32_t __refcount; + + __refcount =__sync_fetch_and_sub(&hdr->refcount, 1); + if(refcount) *refcount = __refcount; + return ARM_DRIVER_OK; +} + +static CFSTORE_INLINE int32_t cfstore_hkvt_refcount_inc(cfstore_area_hkvt_t* hkvt, uint8_t *refcount) +{ + int32_t ret = ARM_CFSTORE_DRIVER_ERROR_HANDLE_COUNT_MAX; + uint32_t __refcount; + cfstore_area_header_t *hdr = (cfstore_area_header_t*) hkvt->head; + + if( (__refcount = __sync_fetch_and_add(&hdr->refcount, 1)) < CFSTORE_LOCK_REFCOUNT_MAX) { + if(refcount) *refcount = __refcount; + ret = ARM_DRIVER_OK; + } else { + /* maximum count reach, back down and return error*/ + __sync_fetch_and_sub(&hdr->refcount, 1); + } + return ret; +} + +#endif /* TARGET_LIKE_X86_LINUX_NATIVE */ + + +/* + * security/permissions helper functions + */ +#ifdef noCFG_CFSTORE_UVISOR + +/** + * @brief check that a client (cfstore-uvisor client box) is the "owner" of the + * KV. Owner means the client that can create or created the KV. This is + * determined by the clients namespace and whether the KV path name falls + * within that name space + * @param key_name + * the name of the KV being created. + * the validation that the key_name is composed of permissible chars is + * carried out before this function is called. + * @note + * Conceptually, cfstore supports the following KV path namespaces: + * - com.arm.mbed. + * - guids of the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx where x is a hex digit. + * + * In the cfstore implementation, explicit checking of the structure of the + * namespace string is not required. Cfstore only need enforce that: + * the root of the KV pathname == cfstore client uvisor namespace. + */ +static int32_t cfstore_uvisor_is_client_kv_owner(char* key_name, int32_t* cfstore_uvisor_box_id) +{ + int32_t calling_box_id; + int32_t ret; + /* We store the calling_box_namespace on our stack, lest somebody else modify it. */ + char calling_box_namespace[UVISOR_MAX_BOX_NAMESPACE_LENGTH]; + + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + memset(calling_box_namespace, 0, sizeof(calling_box_namespace)); + /* Get the ID of the box that called this box through the most recent secure gateway. */ + calling_box_id = uvisor_box_id_caller(); + if(calling_box_id < 0){ + CFSTORE_ERRLOG("%s: Error: uvisor uvisor_box_id_caller() returned invalid id (calling_box_id=%" PRId32 "\n", __func__, calling_box_id); + return ARM_CFSTORE_DRIVER_ERROR_UVISOR_BOX_ID; + } + if(cfstore_uvisor_box_id){ + *cfstore_uvisor_box_id = calling_box_id; + } + if(calling_box_id == 0){ + /* the cfstore uvisor client is the main box. + * main box is not allowed to create a key as a client is only permitted to create KVs in their namespace. */ + CFSTORE_ERRLOG("%s: Error: uvisor box id identifies cfstore client cannot create KVs (calling_box_id=%" PRId32 "\n", __func__, calling_box_id); + return ARM_CFSTORE_DRIVER_ERROR_UVISOR_BOX_ID; + } + /* Copy the name of the calling box to our stack. */ + ret = uvisor_box_namespace(calling_box_id, calling_box_namespace, sizeof(calling_box_namespace)); + if(ret < 0){ + /* error */ + CFSTORE_ERRLOG("%s: Error: unable to recover uvisor box namespace\n", __func__); + return ARM_CFSTORE_DRIVER_ERROR_UVISOR_NAMESPACE; + } + /* check the cfstore client uvisor box namespace is non-trivial */ + if(strlen(calling_box_namespace) == 0){ + CFSTORE_ERRLOG("%s: Error: uvisor box namespace is zero length\n", __func__); + return ARM_CFSTORE_DRIVER_ERROR_UVISOR_NAMESPACE; + } + /* check that the key name is within the root domain namespace */ + if(strncmp(calling_box_namespace, key_name, sizeof(calling_box_namespace)) != 0) { + /* The key_name does not fall within the cfstore-uvisor client namespace and therefore the create is not allowed */ + CFSTORE_ERRLOG("%s: Error: key name (%s) is not permitted to be created within client uvisor box namespace (%s) of cfstore client\n", __func__, key_name, calling_box_namespace); + return ARM_CFSTORE_DRIVER_ERROR_NO_PERMISSIONS; + } + /* We've passed all our checks, so we allow the calling box. */ + return ARM_DRIVER_OK; +} +#endif /* YOTTA_CFG_CFSTORE_UVISOR */ + +/** + * @brief check that the cfstore client (caller, which is a uvisor box) + * is only trying to access its own namespace. + * + * @note This function is the cfstore equivalent of "is_calling_box_allowed" + */ +static int32_t cfstore_uvisor_security_context_prefix_check(const char* key_name) +{ + /*todo: implement : A client uvisor security context should exist with + * a security_prefix_name that matches the first part of the + * key_name. Make sure this is the case. */ + + // if the caller is the main box then deny access, as only secure uvisor boxes + // are permitted to access cfstore. + + // get box_id of caller + // get namespace of caller + // if the keyname is in the namespace then permit, otherwise deny + + (void) key_name; + return ARM_DRIVER_OK; +} + +/* @brief check that a client (cfstore-uvisor client box) is the "owner" of the + * KV (wrapper). see cfstore_uvisor_is_client_kv_owner() for more details. + */ +static int32_t cfstore_is_client_kv_owner(const char* key_name, int32_t* cfstore_uvisor_box_id) +{ + CFSTORE_FENTRYLOG("%s:entered\n", __func__); +/* + #ifdef YOTTA_CFG_CFSTORE_UVISOR + return cfstore_uvisor_is_client_kv_owner(key_name, cfstore_uvisor_box_id); +#else + return ARM_DRIVER_OK; +#endif +*/ + (void) key_name; + (void) cfstore_uvisor_box_id; + return ARM_DRIVER_OK; +} + +/* @brief helper function to determine whether this client can close a given KV */ +static bool cfstore_is_kv_client_closable(cfstore_file_t* file) +{ + /* todo: integrate with uvisor to get boxId (security prefix name) + * - check the kv key_name prefix matches the security context to determine whether client is + * allowed to close the given key_name. + */ + /* until can implement this functionality, assume client can close KV */ + (void) file; + return true; +} + +/* @brief helper function to determine whether this client can delete a given KV */ +static bool cfstore_is_kv_client_deletable(cfstore_file_t* file) +{ + /* todo: integrate with uvisor to get boxId (security prefix name) + * - check the kv key_name prefix matches the security context to determine whether client is + * allowed to delete the given key_name. + */ + /* until can implement this functionality, assume client can delete KV */ + (void) file; + return true; +} + +#ifdef YOTTA_CFG_CFSTORE_UVISOR_to_debug +/* @brief helper function to determine whether this cfstore-uvisor client box can read a given KV */ +static bool cfstore_is_kv_client_readable(cfstore_area_hkvt_t* hkvt) +{ + bool bret = false; + int32_t ret = ARM_DRIVER_ERROR; + char key_name[CFSTORE_KEY_NAME_MAX_LENGTH+1]; + uint8_t key_name_len = CFSTORE_KEY_NAME_MAX_LENGTH+1; + cfstore_area_header_t *hdr = (cfstore_area_header_t*) hkvt->head; + + + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + memset(key_name, 0, key_name_len); + ret = cfstore_get_key_name_ex(hkvt, key_name, &key_name_len); + if(ret < ARM_DRIVER_OK){ + CFSTORE_ERRLOG("%s:Error: cfstore_get_key_name_ex() returned error.\n", __func__); + return bret; + } + ret = cfstore_is_client_kv_owner(key_name, NULL); + if(ret == ARM_DRIVER_OK){ + /* cfstore-usvisor client box is the "owner" of the key */ + bret = hdr->perm_owner_read; + } else { + /* cfstore-usvisor client box is not the "owner" of the key i.e. is the "other" */ + bret = hdr->perm_other_read; + } + return bret; +} + +/* @brief helper function to determine whether this client can write a given KV */ +static bool cfstore_is_kv_client_writable(cfstore_area_hkvt_t* hkvt) +{ + bool bret = false; + int32_t ret = ARM_DRIVER_ERROR; + char key_name[CFSTORE_KEY_NAME_MAX_LENGTH+1]; + uint8_t key_name_len = CFSTORE_KEY_NAME_MAX_LENGTH+1; + cfstore_area_header_t *hdr = (cfstore_area_header_t*) hkvt->head; + + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + memset(key_name, 0, key_name_len); + ret = cfstore_get_key_name_ex(hkvt, key_name, &key_name_len); + if(ret < ARM_DRIVER_OK){ + CFSTORE_ERRLOG("%s:Error: cfstore_get_key_name_ex() returned error.\n", __func__); + return bret; + } + ret = cfstore_is_client_kv_owner(key_name, NULL); + if(ret == ARM_DRIVER_OK){ + /* cfstore-usvisor client box is the "owner" of the key */ + bret = hdr->perm_owner_write; + } else { + /* cfstore-usvisor client box is not the "owner" of the key i.e. is the "other" */ + bret = hdr->perm_other_write; + } + return bret; +} + +/* @brief helper function to determine whether this client can execute a given KV */ +static bool cfstore_is_kv_client_executable(cfstore_area_hkvt_t* hkvt) +{ + bool bret = false; + int32_t ret = ARM_DRIVER_ERROR; + char key_name[CFSTORE_KEY_NAME_MAX_LENGTH+1]; + uint8_t key_name_len = CFSTORE_KEY_NAME_MAX_LENGTH+1; + cfstore_area_header_t *hdr = (cfstore_area_header_t*) hkvt->head; + + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + memset(key_name, 0, key_name_len); + ret = cfstore_get_key_name_ex(hkvt, key_name, &key_name_len); + if(ret < ARM_DRIVER_OK){ + CFSTORE_ERRLOG("%s:Error: cfstore_get_key_name_ex() returned error.\n", __func__); + return bret; + } + ret = cfstore_is_client_kv_owner(key_name, NULL); + if(ret == ARM_DRIVER_OK){ + /* cfstore-usvisor client box is the "owner" of the key */ + bret = hdr->perm_owner_execute; + } else { + /* cfstore-usvisor client box is not the "owner" of the key i.e. is the "other" */ + bret = hdr->perm_other_execute; + } + return bret; +} +#endif // YOTTA_CFG_CFSTORE_UVISOR_to_debug + +/* @brief helper function to determine whether this client can read a given KV */ +static bool cfstore_is_kv_client_readable(cfstore_area_hkvt_t* hkvt) +{ + /* todo: integrate with uvisor to get boxId (security prefix name) + * - check the kv key_name prefix matches the security context to determine whether client is + * owner or other. + * - if(owner) + * { + * // client is owner of kv + * if( ((cfstore_area_header_t*)(hkvt->head))->perm_owner_read == true) { + * return true; + * } + * } else { + * // client is other + * if( ((cfstore_area_header_t*)(hkvt->head))->perm_other_read == true) { + * return true; + * } + * return false; + */ + /* until can implement this functionality, assume client has read access to KV */ + (void) hkvt; + return true; +} + +/* @brief helper function to determine whether this client can write a given KV */ +static bool cfstore_is_kv_client_writable(cfstore_area_hkvt_t* hkvt) +{ + cfstore_area_header_t *hdr = (cfstore_area_header_t*) hkvt->head; + + /* todo: integrate with uvisor to get boxId (security prefix name) + * - check the kv key_name prefix matches the security context to determine whether client is + * owner or other. + * - if(owner) + * { + * // client is owner of kv + * if( ((cfstore_area_header_t*)(hkvt->head))->perm_owner_write == true) { + * return true; + * } + * } else { + * // client is other + * if( ((cfstore_area_header_t*)(hkvt->head))->perm_other_write == true) { + * return true; + * } + * return false; + */ + /* until can implement this functionality, assume client has write access to KV */ + + /* check that the owner has write permission */ + return hdr->perm_owner_write; +} + +/* @brief helper function to determine whether this client can execute a given KV */ +static bool cfstore_is_kv_client_executable(cfstore_area_hkvt_t* hkvt) +{ + /* todo: integrate with uvisor to get boxId (security prefix name) + * - check the kv key_name prefix matches the security context to determine whether client is + * owner or other. + * - if(owner) + * { + * // client is owner of kv + * if( ((cfstore_area_header_t*)(hkvt->head))->perm_owner_execute == true) { + * return true; + * } + * } else { + * // client is other + * if( ((cfstore_area_header_t*)(hkvt->head))->perm_other_execute == true) { + * return true; + * } + * return false; + */ + /* until can implement this functionality, assume client has execute access to KV */ + (void) hkvt; + return true; +} + + +/* + * flags helper function + */ +static bool cfstore_acl_is_default(ARM_CFSTORE_ACCESS_CONTROL_LIST acl) +{ + if( acl.perm_owner_read == false && + acl.perm_owner_write == false && + acl.perm_owner_execute == false && + acl.perm_other_read == false && + acl.perm_other_write == false && + acl.perm_other_execute == false ) + { + /* flags are set to indicate "adopt some meaningful default behaviour" */ + return true; + } + return false; +} + +/* + * flags helper function + */ +static bool cfstore_flags_is_default(ARM_CFSTORE_FMODE flags) +{ + if( flags.read == 0 && + flags.write == 0 && + flags.continuous == 0 && + flags.flush_on_close == 0 && + flags.lazy_flush == 0 && + flags.storage_detect == 0 ) + { + /* flags are set to indicate "adopt some meaningful default behaviour" */ + return true; + } + return false; +} + +static CFSTORE_INLINE bool cfstore_hkvt_get_flags_delete(cfstore_area_hkvt_t *hkvt) +{ + return ((cfstore_area_header_t*) hkvt->head)->flags.delete; +} + +static CFSTORE_INLINE void cfstore_hkvt_set_flags_delete(cfstore_area_hkvt_t *hkvt, bool flag) +{ + CFSTORE_ASSERT(hkvt != NULL); + ((cfstore_area_header_t*) hkvt->head)->flags.delete = flag; +} + + +/* + * struct cfstore_area_hkvt_t helper operations + */ +static CFSTORE_INLINE uint8_t cfstore_hkvt_get_key_len(cfstore_area_hkvt_t* hkvt) +{ + cfstore_area_header_t *header; + CFSTORE_ASSERT(hkvt != NULL); + header = (cfstore_area_header_t*) hkvt->head; + return header->klength; +} + +static CFSTORE_INLINE uint32_t cfstore_hkvt_get_value_len(cfstore_area_hkvt_t* hkvt) +{ + cfstore_area_header_t *header; + CFSTORE_ASSERT(hkvt != NULL); + header = (cfstore_area_header_t*) hkvt->head; + return header->vlength; +} + +static CFSTORE_INLINE ARM_CFSTORE_SIZE cfstore_hkvt_get_size(cfstore_area_hkvt_t* hkvt) +{ + ARM_CFSTORE_SIZE kv_size = 0; + + kv_size += sizeof(cfstore_area_header_t); + kv_size += cfstore_hkvt_get_key_len(hkvt); + kv_size += cfstore_hkvt_get_value_len(hkvt); + return kv_size; +} + +static CFSTORE_INLINE void cfstore_hkvt_init(cfstore_area_hkvt_t* hkvt) +{ + memset(hkvt, 0, sizeof(cfstore_area_hkvt_t)); +} + + +static CFSTORE_INLINE bool cfstore_hkvt_is_valid(cfstore_area_hkvt_t *hkvt, uint8_t *area_0_tail) +{ + if(hkvt->head && hkvt->head != area_0_tail && hkvt->key && hkvt->value && hkvt->tail) { + return true; + } + return false; +} + +static CFSTORE_INLINE uint32_t cfstore_hkvt_set_value_len(cfstore_area_hkvt_t* hkvt, uint32_t value_len) +{ + uint32_t vlength; + cfstore_area_header_t *hdr; + CFSTORE_ASSERT(hkvt != NULL); + hdr = (cfstore_area_header_t*) hkvt->head; + vlength = hdr->vlength; + hdr->vlength = value_len; + return vlength; +} + +/* @brief helper function to detect if there are any KV's stored in the sram area */ +static bool cfstore_area_has_hkvt(void) +{ + cfstore_ctx_t* ctx = cfstore_ctx_get(); + + /* head and tail pointer equal means there are no KVs stored */ + if(ctx->area_0_head == ctx->area_0_tail){ + /* there are no KV's stored*/ + return false; + } + return true; +} + + +/* @brief helper function to get the first KV in the sram area */ +static cfstore_area_hkvt_t cfstore_get_hkvt_from_head_ptr(uint8_t* head) +{ + cfstore_area_hkvt_t hkvt; + + CFSTORE_ASSERT(head != NULL); + memset((void*) &hkvt, 0, sizeof(hkvt)); + hkvt.head = head; + hkvt.key = hkvt.head + sizeof(cfstore_area_header_t); + hkvt.value = hkvt.key + ((cfstore_area_header_t*) hkvt.head)->klength; + hkvt.tail = hkvt.value + ((cfstore_area_header_t*) hkvt.head)->vlength; + return hkvt; +} + + +/* @brief helper function to convert a opaque handle to a struct cfstore_area_hkvt_t */ +static cfstore_area_hkvt_t cfstore_get_hkvt(ARM_CFSTORE_HANDLE hkey) +{ + cfstore_file_t* file = (cfstore_file_t*) hkey; + return cfstore_get_hkvt_from_head_ptr((uint8_t*) file->head); +} + + +/* @brief helper function to convert a opaque handle to a struct cfstore_area_hkvt_t */ +static int32_t cfstore_get_head_hkvt(cfstore_area_hkvt_t* hkvt) +{ + cfstore_ctx_t* ctx = cfstore_ctx_get(); + + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + CFSTORE_ASSERT(hkvt != NULL); + if(!cfstore_area_has_hkvt()){ + CFSTORE_TP(CFSTORE_TP_VERBOSE1, "%s:CFSTORE has no KVs\n", __func__); + memset((void*) hkvt, 0, sizeof(cfstore_area_hkvt_t)); + return ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND; + } + + CFSTORE_TP(CFSTORE_TP_VERBOSE1, "%s:CFSTORE has KVs\n", __func__); + *hkvt = cfstore_get_hkvt_from_head_ptr(ctx->area_0_head); + return ARM_DRIVER_OK; +} + + +/* @brief helper function to walk the sram area from the previous hkvt to + * the next hkvt. + * @param prev + * pointer to previous hkvt. If null then the search is started + * from the beginning of the sram area. + * @param next + * pointer to next hkvt for which the pointers need calculating. + */ +static int32_t cfstore_get_next_hkvt(cfstore_area_hkvt_t* prev, cfstore_area_hkvt_t* next) +{ + cfstore_ctx_t* ctx = cfstore_ctx_get(); + + CFSTORE_ASSERT(prev != NULL); + CFSTORE_ASSERT(next != NULL); + + if(prev->tail == ctx->area_0_tail){ + CFSTORE_TP(CFSTORE_TP_VERBOSE1, "%s:reached the end of the list. return NULL entry\n", __func__); + memset((void*) next, 0, sizeof(cfstore_area_hkvt_t)); + return ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND; + } + /* use the prev tail pointer to find the next head pointer */ + *next = cfstore_get_hkvt_from_head_ptr((uint8_t*) prev->tail); + return ARM_DRIVER_OK; +} + + +/* + * Flash support functions + */ + +static CFSTORE_INLINE void cfstore_hkvt_dump(cfstore_area_hkvt_t* hkvt, const char* tag); + +/* set the tail pointer */ +static int32_t cfstore_flash_set_tail(void) +{ + int32_t ret = ARM_DRIVER_ERROR; + uint8_t* ptr = NULL; + cfstore_ctx_t* ctx = cfstore_ctx_get(); + uint8_t* tail = NULL; + cfstore_area_hkvt_t hkvt; + + /* walk the area to find the last KV */ + CFSTORE_FENTRYLOG("%s:entered: \n", __func__); + CFSTORE_ASSERT(ctx != NULL); + cfstore_hkvt_init(&hkvt); + ptr = ctx->area_0_head; + /* ctx->area_0_tail has been set to the end of the sram area allocated, but this is now refined so + * as to point to the end of the last KV */ + tail = ctx->area_0_tail; + while(ptr < tail) { + hkvt = cfstore_get_hkvt_from_head_ptr(ptr); + cfstore_hkvt_dump(&hkvt, __func__); + /* when the length between the hkvt.tail and tail (set to the end of the area including padding) + * is less than the minimum KV length then we have found the last KV, and can set the + * area_0_tail correctly to the end of the last KV */ + if((uint32_t)(tail - hkvt.tail) < sizeof(cfstore_area_header_t)){ + /* ptr is last KV in area as there isn't space for another header */ + ctx->area_0_tail = hkvt.tail; + ret = ARM_DRIVER_OK; + break; + } + ptr = hkvt.tail; + } + return ret; +} + +#if defined CFSTORE_CONFIG_BACKEND_FLASH_ENABLED && CFSTORE_CONFIG_BACKEND_FLASH_ENABLED == 1 + +/* + * flash helper functions + */ + +/* @brief table for mapping flash journal error codes to equivalent cfstore error codes */ +static cfstore_flash_journal_error_code_node cfstore_flash_journal_error_code_map[]= +{ + { JOURNAL_STATUS_OK, ARM_DRIVER_OK}, + { JOURNAL_STATUS_ERROR, ARM_CFSTORE_DRIVER_ERROR_JOURNAL_STATUS_ERROR}, + { JOURNAL_STATUS_BUSY, ARM_CFSTORE_DRIVER_ERROR_JOURNAL_STATUS_BUSY}, + { JOURNAL_STATUS_TIMEOUT, ARM_CFSTORE_DRIVER_ERROR_JOURNAL_STATUS_TIMEOUT}, + { JOURNAL_STATUS_UNSUPPORTED, ARM_CFSTORE_DRIVER_ERROR_JOURNAL_STATUS_UNSUPPORTED}, + { JOURNAL_STATUS_PARAMETER, ARM_CFSTORE_DRIVER_ERROR_JOURNAL_STATUS_PARAMETER}, + { JOURNAL_STATUS_BOUNDED_CAPACITY, ARM_CFSTORE_DRIVER_ERROR_JOURNAL_STATUS_BOUNDED_CAPACITY}, + { JOURNAL_STATUS_STORAGE_API_ERROR, ARM_CFSTORE_DRIVER_ERROR_JOURNAL_STATUS_STORAGE_API_ERROR}, + { JOURNAL_STATUS_STORAGE_IO_ERROR, ARM_CFSTORE_DRIVER_ERROR_JOURNAL_STATUS_STORAGE_IO_ERROR}, + { JOURNAL_STATUS_NOT_INITIALIZED, ARM_CFSTORE_DRIVER_ERROR_JOURNAL_STATUS_NOT_INITIALIZED}, + { JOURNAL_STATUS_EMPTY, ARM_CFSTORE_DRIVER_ERROR_JOURNAL_STATUS_EMPTY}, + { JOURNAL_STATUS_SMALL_LOG_REQUEST, ARM_CFSTORE_DRIVER_ERROR_JOURNAL_STATUS_SMALL_LOG_REQUEST}, + { CFSTORE_SENTINEL, CFSTORE_SENTINEL} +}; + +static int32_t cfstore_flash_map_error(int32_t flash_journal_status_code) +{ + cfstore_flash_journal_error_code_node* node = cfstore_flash_journal_error_code_map; + + while(node->flash_journal_error_code != (int32_t) CFSTORE_SENTINEL) + { + if(flash_journal_status_code == node->flash_journal_error_code) + { + return node->cfstore_error_code; + } + } + return ARM_CFSTORE_DRIVER_ERROR_INTERNAL; +} + + +/* @brief Callback registered with flash journal for async operation + * completion notifications. + * + * @note The callback is called at interrupt context. + * The critical section to used police access to context variables + * modified by both the interrupt and application context processing. + * The interrupt context prevents application context from running and + * hence its only necessary to use the critical_section_xxx in the + * application execution context. + * + * In flash journal async mode, when: + * - a FlashJournal_xxx() function has been invoked, and + * - before the async completion has been received and processed + * the application context code should alway co-ordinate access to + * context variables modified by interrupt and application context + * by use of the critical_section_xxx. + */ +static void cfstore_flash_journal_callback(int32_t status, FlashJournal_OpCode_t cmd_code) +{ + cfstore_ctx_t* ctx = cfstore_ctx_get(); + + CFSTORE_FENTRYLOG("%s:entered: status=%d, cmd_code=%d (%s)\n", __func__, (int) status, (int) cmd_code, cfstore_flash_opcode_str[cmd_code]); + switch(cmd_code) + { + case FLASH_JOURNAL_OPCODE_INITIALIZE: + ctx->fsm.event = cfstore_fsm_event_init_done; + break; + case FLASH_JOURNAL_OPCODE_READ_BLOB: + ctx->fsm.event = cfstore_fsm_event_read_done; + break; + case FLASH_JOURNAL_OPCODE_LOG_BLOB: + ctx->fsm.event = cfstore_fsm_event_log_done; + break; + case FLASH_JOURNAL_OPCODE_COMMIT: + ctx->fsm.event = cfstore_fsm_event_commit_done; + break; + case FLASH_JOURNAL_OPCODE_RESET: + ctx->fsm.event = cfstore_fsm_event_reset_done; + break; + case FLASH_JOURNAL_OPCODE_GET_INFO: + default: + CFSTORE_ERRLOG("%s:Error: notification of unsupported cmd_code event (status=%d, cmd_code=%d)\n", __func__, (int) status, (int) cmd_code); + return; + } + ctx->status = status; + ctx->cmd_code = cmd_code; + cfstore_fsm_state_handle_event(&ctx->fsm, ctx->fsm.event, (void*) ctx); + return; +} + + +/* @brief */ +static int32_t cfstore_fsm_stop_on_entry(void* context) +{ + cfstore_ctx_t* ctx = (cfstore_ctx_t*) context; + + /* reset fsm state */ + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + CFSTORE_ASSERT(ctx->fsm.state == cfstore_fsm_state_stopped); + + ctx->fsm.event = cfstore_fsm_event_max; + ctx->cmd_code = (FlashJournal_OpCode_t)((int) FLASH_JOURNAL_OPCODE_RESET+1); + return ARM_DRIVER_OK; +} + +/* static int32_t cfstore_fsm_stop_on_exit(void* context) {(void) context; }*/ + + +/* @brief fsm on entry function for the initing state + * @note + * flash journal sync mode: (see async mode notes) + * flash journal async mode: + * This is typically called in app context (not intr context) for both flash + * journal sync and asyc modes. There are no outstanding async requests + * so it cannot be interrupted, and therefore doesnt need CS protection. + */ +static int32_t cfstore_fsm_init_on_entry(void* context) +{ + int32_t ret = ARM_DRIVER_ERROR; + const ARM_DRIVER_STORAGE *drv = &ARM_Driver_Storage_(0); + cfstore_ctx_t* ctx = (cfstore_ctx_t*) context; + + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + + ret = FlashJournal_initialize(&ctx->jrnl, drv, &FLASH_JOURNAL_STRATEGY_SEQUENTIAL, cfstore_flash_journal_callback); + CFSTORE_FENTRYLOG("%s:here\n", __func__); + CFSTORE_TP(CFSTORE_TP_FSM, "%s:FlashJournal_initialize ret=%" PRId32 "\n", __func__, ret); + if(ret < ARM_DRIVER_OK){ + CFSTORE_ERRLOG("%s:Error: failed to initialize flash journaling layer (ret=%" PRId32 ")\n", __func__, ret); + cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_stopped, ctx); + } + else if(ret > 0){ + /* operation completed synchronously*/ + cfstore_flash_journal_callback(ret, FLASH_JOURNAL_OPCODE_INITIALIZE); + } + return ret; +} + + +/* @brief fsm initing state handler function + * @note + * flash journal sync mode: + * CS protection not required as there are no callbacks. + * flash journal async mode: + * This is typically called at intr context (not app context) when flash + * journal invokes the callback handler for FLASH_JOURNAL_OPCODE_INITIALIZE + * Hence as running at intr level, no CS protection is required. + */ +static int32_t cfstore_fsm_initing(void* context) +{ + int32_t ret = ARM_DRIVER_OK; + cfstore_ctx_t* ctx = (cfstore_ctx_t*) context; + + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + CFSTORE_ASSERT(ctx->fsm.state == cfstore_fsm_state_initing); + CFSTORE_ASSERT(ctx->cmd_code == FLASH_JOURNAL_OPCODE_INITIALIZE); + + /* only change state if status > 0*/ + if(ctx->status > 0){ + ret = cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_reading, ctx); + } else if(ctx->status < 0) { + CFSTORE_ERRLOG("%s:Error: failed to initialize flash journaling layer (ret=%" PRId32 ")\n", __func__, ctx->status); + cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_stopped, ctx); + } + return ret; +} + +/* static int32_t cfstore_fsm_init_on_exit(void* context) */ + + +/* @brief fsm on entry function for the reading state + * @note + * flash journal sync mode: + * CS protection not required as there are no callbacks. + * flash journal async mode: + * This is typically called at intr context (not app context) when flash + * journal invokes the callback handler for FLASH_JOURNAL_OPCODE_INITIALIZE + * Hence as running at intr level, no CS protection is required. + */ +static int32_t cfstore_fsm_read_on_entry(void* context) +{ + uint8_t* ptr = NULL; + int32_t ret = 0; + FlashJournal_Status_t status = JOURNAL_STATUS_ERROR; + cfstore_ctx_t* ctx = (cfstore_ctx_t*) context; + + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + CFSTORE_ASSERT(ctx != NULL); + /* FlashJournal_getInfo() is synchronous */ + status = FlashJournal_getInfo(&ctx->jrnl, &ctx->info); + if(status < JOURNAL_STATUS_OK){ + CFSTORE_TP(CFSTORE_TP_FSM, "%s:Error: failed get journal info (status=%d)\n", __func__, (int) status); + /* move to ready state. cfstore client is expected to Uninitialize() before further calls */ + cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_ready, ctx); + ret = ARM_CFSTORE_DRIVER_ERROR_INTERNAL; + goto out; + + } + if(ctx->info.sizeofJournaledBlob > 0) + { + /* setup the expected blob size for writing + * This is a multiple of program unit so the write doesnt fail due to unaligned log */ + ctx->expected_blob_size = ctx->info.sizeofJournaledBlob; + if(ctx->expected_blob_size % ctx->info.program_unit > 0){ + ctx->expected_blob_size += (ctx->info.program_unit - (ctx->info.sizeofJournaledBlob % ctx->info.program_unit)); + } + /* grow the area by the size of the stored blob */ + ptr = (uint8_t*) CFSTORE_REALLOC((void*) ctx->area_0_head, ctx->expected_blob_size); + if(ptr == NULL){ + CFSTORE_ERRLOG("%s:Error: unable to allocate memory (size=%lu)\n", __func__, (long unsigned int) ctx->info.sizeofJournaledBlob); + cfstore_ctx_reset(ctx); + ret = ARM_CFSTORE_DRIVER_ERROR_OUT_OF_MEMORY; + /* move to ready state. cfstore client is expected to Uninitialize() before further calls */ + cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_ready, ctx); + goto out; + } + memset(ptr, 0, ctx->expected_blob_size); + if(ptr != ctx->area_0_head){ + CFSTORE_TP(CFSTORE_TP_FSM, "%s:cfstore_ctx_g.area_0_head pointer changed (cfstore_ctx_g.area_0_head=%p, ptr=%p)\n", __func__, ctx->area_0_head, ptr); + ctx->area_0_head = ptr; + ctx->area_0_tail = ctx->area_0_head + ctx->info.sizeofJournaledBlob; + } + ret = FlashJournal_read(&ctx->jrnl, (void*) ctx->area_0_head, ctx->info.sizeofJournaledBlob); + if(ret < ARM_DRIVER_OK){ + CFSTORE_ERRLOG("%s:Error: failed to initialize flash journaling layer (ret=%d)\n", __func__, (int) ret); + /* move to ready state. cfstore client is expected to Uninitialize() before further calls */ + cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_ready, ctx); + goto out; + } else if(ret > 0){ + /* read has completed synchronously*/ + CFSTORE_TP(CFSTORE_TP_FSM, "%s:debug:ret > 0: (ret=%d)\n", __func__, (int) ret); + cfstore_flash_journal_callback(ret, FLASH_JOURNAL_OPCODE_READ_BLOB); + ret = ctx->status; + goto out; + } + /* keep lock and wait for async callback */ + } else { + /* there is no blob, move to next state. need a +ve status value to indicate async completion + * to the fsm reading state handler. use CFSTORE_FLASH_AREA_SIZE_MIN for this value */ + ctx->expected_blob_size = CFSTORE_FLASH_AREA_SIZE_MIN; + status = (FlashJournal_Status_t) CFSTORE_FLASH_AREA_SIZE_MIN; + cfstore_flash_journal_callback(status, FLASH_JOURNAL_OPCODE_READ_BLOB); + ret = ctx->status; + goto out; + } +out: + return ret; +} + + +/* @brief fsm handler when in reading state */ +static int32_t cfstore_fsm_reading(void* context) +{ + int32_t ret = ARM_DRIVER_ERROR; + cfstore_ctx_t* ctx = (cfstore_ctx_t*) context; + + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + CFSTORE_ASSERT(ctx->fsm.state == cfstore_fsm_state_reading); + CFSTORE_ASSERT(ctx->cmd_code == FLASH_JOURNAL_OPCODE_READ_BLOB); + if(ctx->status > 0) + { + if(ctx->status > (int32_t) CFSTORE_FLASH_AREA_SIZE_MIN) + { + CFSTORE_TP(CFSTORE_TP_FSM, "%s:debug:ctx->status > (int32_t) CFSTORE_FLASH_AREA_SIZE_MIN:\n", __func__); + /* check the correct amount of data was read, which is the status code */ + if(ctx->status == (int32_t) ctx->expected_blob_size) + { + /* now have to allow for the fact that there may have been some padding + * at the end of the last _log() to flash, so the read back area may have + * padding at the end, and the tail_pointer needs to not point to the + * end where the padding is located, but to the end of the last KV. + */ + ret = cfstore_flash_set_tail(); + if(ret < ARM_DRIVER_OK){ + CFSTORE_ERRLOG("%s:Error: cfstore_flash_set_tail() failed (ret=%" PRId32 ")\n", __func__, ret); + /* move to ready state. cfstore client is expected to Uninitialize() before further calls */ + cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_ready, ctx); + memset(&ctx->info, 0, sizeof(ctx->info)); + goto out; + } + /* clear info data */ + memset(&ctx->info, 0, sizeof(ctx->info)); + ret = cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_ready, ctx); + if(ret < ARM_DRIVER_OK){ + CFSTORE_ERRLOG("%s:Error: cfstore_fsm_state_set() failed (ret=%" PRId32 ")\n", __func__, ret); + goto out; + } + ret = ctx->status; + } + else + { + CFSTORE_ERRLOG("%s:Error: read bytes (%d) does not equal requested read size (%d)\n", __func__, (int) ctx->status, (int) ctx->expected_blob_size); + ret = cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_ready, ctx); + if(ret < ARM_DRIVER_OK){ + /* move to ready state. cfstore client is expected to Uninitialize() before further calls */ + CFSTORE_ERRLOG("%s:Error: cfstore_fsm_state_set() failed (ret=%" PRId32 ")\n", __func__, ret); + goto out; + } + ret = ctx->status; + } + } + else + { + CFSTORE_TP(CFSTORE_TP_FSM, "%s:debug:ctx->status <= (int32_t) CFSTORE_FLASH_AREA_SIZE_MIN:\n", __func__); + ret = cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_ready, ctx); + if(ret < ARM_DRIVER_OK){ + /* move to ready state. cfstore client is expected to Uninitialize() before further calls */ + CFSTORE_ERRLOG("%s:Error: cfstore_fsm_state_set() failed (ret=%" PRId32 ")\n", __func__, ret); + goto out; + } + ret = ctx->status; + } + } + else if(ctx->status < 0) + { + CFSTORE_TP(CFSTORE_TP_FSM, "%s:debug:ctx->status < 0:\n", __func__); + ret = ctx->status; + } +out: + return ret; +} + + +static int32_t cfstore_fsm_read_on_exit(void* context) +{ + cfstore_ctx_t* ctx = (cfstore_ctx_t*) context; + + CFSTORE_FENTRYLOG("%s:entered:\n", __func__); + /* notify client of initialisation status */ + cfstore_client_notify_data_init(&ctx->client_notify_data, CFSTORE_OPCODE_INITIALIZE, ctx->status, NULL); + ctx->client_callback_notify_flag = true; + return ARM_DRIVER_OK; +} + +/* int32_t cfstore_fsm_log_on_entry(void* context){ (void) context;} */ + +/* @brief on entry to writing state, update value */ +int32_t cfstore_fsm_log_on_entry(void* context) +{ + int32_t ret = 0; + cfstore_ctx_t* ctx = (cfstore_ctx_t*) context; + FlashJournal_Info_t info; + FlashJournal_Status_t status = JOURNAL_STATUS_ERROR; + + CFSTORE_FENTRYLOG("%s:entered:\n", __func__); + memset(&info, 0, sizeof(info)); + + status = FlashJournal_getInfo(&ctx->jrnl, &info); + if(status < JOURNAL_STATUS_OK){ + CFSTORE_ERRLOG("%s:Error: failed get journal info (status=%d)\n", __func__, (int) status); + /* move to ready state. cfstore client is expected to Uninitialize() before further calls */ + cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_ready, ctx); + return cfstore_flash_map_error(status); + } + /* compute the expected_blob_size = area_size plus the padding at the end of the area to align with program_unit*/ + ctx->expected_blob_size = cfstore_ctx_get_area_len(); + if(ctx->expected_blob_size % info.program_unit > 0){ + ctx->expected_blob_size += (info.program_unit - (ctx->expected_blob_size % info.program_unit)); + } + if(ctx->area_0_head && ctx->area_dirty_flag == true) + { + ret = FlashJournal_log(&ctx->jrnl, (const void*) ctx->area_0_head, ctx->expected_blob_size); + if(ret < JOURNAL_STATUS_OK){ + CFSTORE_ERRLOG("%s:Error: FlashJournal_commit() failed (ret=%d)\n", __func__, (int) ret); + ret = cfstore_flash_map_error(status); + /* move to ready state. cfstore client is expected to Uninitialize() before further calls */ + cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_ready, ctx); + goto out0; + } else if(ret > 0){ + /* read has completed synchronously*/ + cfstore_flash_journal_callback(ret, FLASH_JOURNAL_OPCODE_LOG_BLOB); + ret = ctx->status; + } + /* wait for async completion handler*/ + } + else + { + /* nothing to be logged so move back to ready state indicating success*/ + cfstore_flash_journal_callback(ctx->expected_blob_size, FLASH_JOURNAL_OPCODE_LOG_BLOB); + } +out0: + return ret; +} + +/* @brief fsm handler when in reading state */ +static int32_t cfstore_fsm_logging(void* context) +{ + cfstore_ctx_t* ctx = (cfstore_ctx_t*) context; + + CFSTORE_FENTRYLOG("%s:entered:ctx->status=%ld\n", __func__, ctx->status); + /* check the correct amount of data was written */ + if(ctx->status < JOURNAL_STATUS_OK){ + CFSTORE_ERRLOG("%s:Error: FlashJournal_log() failed (ret=%d)\n", __func__, (int) ctx->status); + /* move to ready state. cfstore client is expected to Uninitialize() before further calls */ + cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_ready, ctx); + ctx->status = cfstore_flash_map_error(ctx->status); + } + else + { /* ctx->status >= 0 (status == 0 when everything is deleted) */ + if(ctx->status == (int32_t)ctx->expected_blob_size){ + /* move to the committing state to commit to flash*/ + ctx->status = cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_committing, ctx); + } else { + CFSTORE_ERRLOG("%s:Error: FlashJournal_log() failed to log the expected number of bytes (ctx->expected_blob_size=%d, committed=%d)\n", __func__, (int) ctx->expected_blob_size, (int) ctx->status); + ctx->status = ARM_DRIVER_ERROR; + } + } + return ctx->status; +} + + +static int32_t cfstore_fsm_log_on_exit(void* context) +{ + (void) context; + CFSTORE_FENTRYLOG("%s:entered:\n", __func__); + return ARM_DRIVER_OK; +} + + +/* @brief fsm handler when entering committing state + * @note + * Its unnecessary to provide CS protection for the flashJouranl_commit() as the all the + * _log() operations affecting the commit have been performed, and no more _log() operations + * can happen until we're back in the ready state + */ +static int32_t cfstore_fsm_commit_on_entry(void* context) +{ + int32_t ret = JOURNAL_STATUS_OK; + cfstore_ctx_t* ctx = (cfstore_ctx_t*) context; + + CFSTORE_FENTRYLOG("%s:entered:\n", __func__); + if(ctx->area_0_head && ctx->area_dirty_flag == true) + { + ret = FlashJournal_commit(&ctx->jrnl); + CFSTORE_TP(CFSTORE_TP_FSM, "%s:debug: FlashJournal_commit() (ret=%d)\n", __func__, (int) ret); + if(ret < JOURNAL_STATUS_OK){ + CFSTORE_ERRLOG("%s:Error: FlashJournal_commit() failed (ret=%d)\n", __func__, (int) ret); + /* move to ready state. cfstore client is expected to Uninitialize() before further calls */ + cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_ready, ctx); + } else if(ret > 0){ + /* read has completed synchronously*/ + cfstore_flash_journal_callback(ret, FLASH_JOURNAL_OPCODE_COMMIT); + ret = ctx->status; + } + } + else + { + /* a commit should not be made because there have been no flashJournal_log() calls since the last commit. + * If a _commit() call was made without any _log() calls then it would result in the flash being erased + * because flash journal essentially contains a mirror image of the configuration store sram area, which + * has to be *** FULLY*** repopulated before each _commit(). */ + cfstore_flash_journal_callback(ARM_DRIVER_OK_DONE, FLASH_JOURNAL_OPCODE_COMMIT); + ret = ctx->status; + } + /* wait for async callback */ + CFSTORE_FENTRYLOG("%s:exiting: FlashJournal_commit() (ret=%d)\n", __func__, (int) ret); + return ret; +} + + +/* @brief fsm handler when in committing state + * @note + * Its unnecessary to provide CS protection for the flashJouranl_commit() as the all the + * _log() operations affecting the commit have been performed, and no more _log() operations + * can happen until we're back in the ready state + */ +static int32_t cfstore_fsm_committing(void* context) +{ + cfstore_ctx_t* ctx = (cfstore_ctx_t*) context; + + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + CFSTORE_ASSERT(ctx->fsm.state == cfstore_fsm_state_committing); + CFSTORE_ASSERT(ctx->cmd_code == FLASH_JOURNAL_OPCODE_COMMIT); + + /* check the correct amount of data was written */ + if(ctx->status < JOURNAL_STATUS_OK){ + CFSTORE_ERRLOG("%s:Error: FlashJournal_commit() failed (ret=%d)\n", __func__, (int) ctx->status); + /* move to ready state. cfstore client is expected to Uninitialize() before further calls */ + cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_ready, ctx); + ctx->status = cfstore_flash_map_error(ctx->status); + } + else if(ctx->status == JOURNAL_STATUS_OK) + { + ctx->status = cfstore_flash_map_error(ctx->status); + } + else + { /* ctx->status > 0. for flash-journal-strategy-sequential version >0.4.0, commit() return no longer reports size of commit block */ + ctx->status = cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_ready, ctx); + } + return ctx->status; +} + +static int32_t cfstore_fsm_commit_on_exit(void* context) +{ + cfstore_ctx_t* ctx = (cfstore_ctx_t*) context; + + CFSTORE_FENTRYLOG("%s:entered:\n", __func__); + ctx->area_dirty_flag = false; + /* notify client of commit status */ + cfstore_client_notify_data_init(&ctx->client_notify_data, CFSTORE_OPCODE_FLUSH, ctx->status, NULL); + ctx->client_callback_notify_flag = true; + return ARM_DRIVER_OK; +} + +/* int32_t cfstore_fsm_reset_on_entry(void* context){ (void) context;} */ +/* int32_t cfstore_fsm_resetting(void* context){ (void) context;} */ +/* int32_t cfstore_fsm_reset_on_exit(void* context){ (void) context;} */ + +static int32_t cfstore_fsm_ready_on_commit_req(void* context) +{ + cfstore_ctx_t* ctx = (cfstore_ctx_t*) context; + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + return cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_logging, ctx); +} + +/* int32_t cfstore_fsm_ready_on_entry(void* context){ (void) context;} */ +/* int32_t cfstore_fsm_ready(void* context){ (void) context;} */ +/* int32_t cfstore_fsm_ready_on_exit(void* context){ (void) context;} */ + + + +/* handler functions while in state */ +static cfstore_fsm_handler cfstore_flash_fsm[cfstore_fsm_state_max][cfstore_fsm_event_max] = +{ +/* state\event: init_done read_done log_done commit_req commit_done reset_done */ +/* stopped */ {cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null }, +/* init */ {cfstore_fsm_initing, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null }, +/* reading */ {cfstore_fsm_null, cfstore_fsm_reading, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null }, +/* logging */ {cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_logging, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null }, +/* committing */ {cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_committing, cfstore_fsm_null }, +/* resetting */ {cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null }, +/* ready */ {cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_null, cfstore_fsm_ready_on_commit_req, cfstore_fsm_null, cfstore_fsm_null }, +}; + +/* handler functions for entering the state*/ +cfstore_fsm_handler cfstore_fsm_on_entry[cfstore_fsm_state_max] = +{ + cfstore_fsm_stop_on_entry, + cfstore_fsm_init_on_entry, + cfstore_fsm_read_on_entry, + cfstore_fsm_log_on_entry, + cfstore_fsm_commit_on_entry, + cfstore_fsm_null, /* cfstore_fsm_reset_on_entry */ + cfstore_fsm_null /* cfstore_fsm_ready_on_entry */ +}; + +/* handler functions for exiting state, currently none used */ +cfstore_fsm_handler cfstore_fsm_on_exit[cfstore_fsm_state_max] = +{ + cfstore_fsm_null, /* cfstore_fsm_stop_on_exit */ + cfstore_fsm_null, /* cfstore_fsm_init_on_exit */ + cfstore_fsm_read_on_exit, + cfstore_fsm_log_on_exit, + cfstore_fsm_commit_on_exit, + cfstore_fsm_null, /* cfstore_fsm_reset_on_exit */ + cfstore_fsm_null /* cfstore_fsm_ready_on_exit */ +}; + + +/* @brief inject event into fsm */ +static int32_t cfstore_fsm_state_handle_event(cfstore_fsm_t* fsm, cfstore_fsm_event_t event, void* context) +{ + int32_t ret = ARM_DRIVER_ERROR; + cfstore_ctx_t* ctx = (cfstore_ctx_t*) context; + + CFSTORE_FENTRYLOG("%s:entered: fsm=%p, fsm->state=%d, event=%d (%s), ctx=%p\n", __func__, fsm, fsm->state, event, cfstore_flash_event_str[event], ctx); + CFSTORE_ASSERT(event < cfstore_fsm_event_max); + fsm->event = event; + if(cfstore_flash_fsm[fsm->state][fsm->event] != NULL){ + ret = cfstore_flash_fsm[fsm->state][fsm->event](ctx); + if(ret < ARM_DRIVER_OK){ + #ifdef CFSTORE_DEBUG + CFSTORE_ERRLOG("%s:FSM:EVT:Error: cfstore_flash_fsm[%s][%s] failed\n", __func__, (char*) cfstore_flash_state_str[fsm->state], (char*) cfstore_flash_event_str[fsm->event]); + #endif + return ret; + } + } + + /* do not clear context data set by caller as it may be used later + * fsm->event = cfstore_fsm_event_max; + * ctx->status = 0; + * ctx->cmd_code = (FlashJournal_OpCode_t)((int) FLASH_JOURNAL_OPCODE_RESET+1); + */ + return ret; +} + + +/* @brief get the current state of the fsm */ +static cfstore_fsm_state_t cfstore_fsm_state_get(cfstore_fsm_t* fsm) +{ + return fsm->state; +} + +/* @brief function to move to new fsm state, calling state exit function for old state and entry function for new state */ +static int32_t cfstore_fsm_state_set(cfstore_fsm_t* fsm, cfstore_fsm_state_t new_state, void* ctx) +{ + int32_t ret = ARM_DRIVER_ERROR; + cfstore_ctx_t* context = (cfstore_ctx_t*) ctx; + #ifdef CFSTORE_DEBUG + cfstore_fsm_state_t old_state = fsm->state; + #endif + + CFSTORE_FENTRYLOG("%s:entered: fsm=%p, ctx=%p\n", __func__, fsm, ctx); + #ifdef CFSTORE_DEBUG + CFSTORE_TP(CFSTORE_TP_FSM, "%s:FSM:REQ RX: fsm->state=%d (%s): new_state=%d (%s)\n", __func__, (int) fsm->state, cfstore_flash_state_str[fsm->state], (int) new_state, cfstore_flash_state_str[new_state]); + #endif + CFSTORE_ASSERT(fsm != NULL); + CFSTORE_ASSERT(new_state < cfstore_fsm_state_max); + CFSTORE_ASSERT(ctx != NULL); + CFSTORE_ASSERT(fsm->state < cfstore_fsm_state_max); + + if(cfstore_fsm_on_exit[fsm->state] != NULL){ + ret = cfstore_fsm_on_exit[fsm->state](ctx); + if(ret < ARM_DRIVER_OK){ + #ifdef CFSTORE_DEBUG + CFSTORE_ERRLOG("%s:FSM:REQ RX:%s:%s:Error: cfstore_fsm_on_exit() failed\n", __func__, cfstore_flash_state_str[fsm->state], cfstore_flash_state_str[new_state]); + #endif + /* handling of the error is done in the on_exit() method, which best knows how the state to move to */ + return ret; + } + } + fsm->state = new_state; + if(cfstore_fsm_on_entry[new_state] != NULL){ + ret = cfstore_fsm_on_entry[new_state](ctx); + if(ret < ARM_DRIVER_OK){ + #ifdef CFSTORE_DEBUG + CFSTORE_TP(CFSTORE_TP_FSM, "%s:FSM:REQ RX: fsm->state=%d (%s): new_state=%d (%s): Error: cfstore_fsm_on_entry() failed (ret=%" PRId32 ")\n", __func__, (int) fsm->state, cfstore_flash_state_str[fsm->state], (int) new_state, cfstore_flash_state_str[new_state], ret); + #endif + /* handling of the error is done in the on_entry() method, which best knows how the state to move to */ + return ret; + } + } + if(context->client_callback_notify_flag == true) + { + cfstore_client_notify_data_t notify_data; + + CFSTORE_TP(CFSTORE_TP_FSM, "%s:doing client callback\n", __func__); + + /* only one set of client notify data is required as there can only be 1 outstanding flash journal async notificaion + * at one time. */ + context->client_callback_notify_flag = false; /* prevents re-calling callback if this function gets called again */ + memcpy(¬ify_data, &context->client_notify_data, sizeof(cfstore_client_notify_data_t)); + /* clear context state before initiating call */ + cfstore_client_notify_data_init(&context->client_notify_data, CFSTORE_OPCODE_MAX, ARM_DRIVER_ERROR, NULL); + cfstore_ctx_client_notify(ctx, ¬ify_data); + } + CFSTORE_TP(CFSTORE_TP_FSM, "%s:FSM:REQ DONE: fsm->state=%d (%s): new_state=%d (%s)\n", __func__, (int) old_state, cfstore_flash_state_str[old_state], (int) new_state, cfstore_flash_state_str[new_state]); + return ret; +} + +static bool cfstore_flash_journal_is_async_op_pending(cfstore_ctx_t* ctx) +{ + CFSTORE_FENTRYLOG("%s:entered: fsm->state=%s\n", __func__, (char*) cfstore_flash_state_str[cfstore_fsm_state_get(&ctx->fsm)]); + if(cfstore_fsm_state_get(&ctx->fsm) != cfstore_fsm_state_ready) + { + /* flash journal async operation is in progress */ + return true; + } + return false; +} + +static int32_t cfstore_flash_init(void) +{ + int32_t ret = ARM_DRIVER_ERROR; + cfstore_ctx_t* ctx = cfstore_ctx_get(); + + CFSTORE_FENTRYLOG("%s:entered: \n", __func__); + CFSTORE_FENTRYLOG("%s:: CFSTORE_CONFIG_BACKEND_FLASH_ENABLED=%d\n", __func__, (int) CFSTORE_CONFIG_BACKEND_FLASH_ENABLED); + ctx->cmd_code = (FlashJournal_OpCode_t)((int) FLASH_JOURNAL_OPCODE_RESET+1); + ctx->expected_blob_size = 0; + ctx->fsm.event = cfstore_fsm_event_max; + ctx->fsm.state = cfstore_fsm_state_stopped; + memset(&ctx->info, 0, sizeof(ctx->info)); + ret = cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_initing, ctx); + if(ret < 0){ + CFSTORE_DBGLOG("%s:Error: cfstore_fsm_state_set() failed\n", __func__); + return ret; + } + return ret; +} + + +/* @brief de-initialise the flash journal */ +static int32_t cfstore_flash_deinit(void) +{ + int32_t ret = ARM_DRIVER_ERROR; + cfstore_ctx_t* ctx = cfstore_ctx_get(); + + CFSTORE_FENTRYLOG("%s:entered: fsm->state=%s\n", __func__, (char*) cfstore_flash_state_str[cfstore_fsm_state_get(&ctx->fsm)]); + ret = cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_stopped, ctx); + if(ret < 0){ + CFSTORE_TP(CFSTORE_TP_INIT, "%s:Error: cfstore_fsm_state_set() failed\n", __func__); + } + return ret; +} + +/* +static int32_t cfstore_flash_reset(void) +{ + int32_t ret = ARM_DRIVER_ERROR; + cfstore_ctx_t* ctx = cfstore_ctx_get(); + + ret = FlashJournal_reset(&ctx->jrnl); + if(ret != JOURNAL_STATUS_OK){ + CFSTORE_ERRLOG("%s:Error: failed to reset flash journal (ret=%" PRId32 ")\n", __func__, ret); + goto out0; + } +out0: + return ret; +} +*/ + +static int32_t cfstore_flash_flush(cfstore_ctx_t* ctx) +{ + int32_t ret = ARM_DRIVER_OK; + + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + /* put the async completion code state variables into a known state */ + ctx->status = ARM_DRIVER_OK; + ctx->cmd_code = (FlashJournal_OpCode_t)((int) FLASH_JOURNAL_OPCODE_RESET+1); + + /* cfstore_fsm_state_handle_event() is called at intr context via + * cfstore_flash_journal_callback(), and hence calls from app context are + * protected with CSs */ + cfstore_critical_section_lock(&ctx->rw_area0_lock, __func__); + ret = cfstore_fsm_state_handle_event(&ctx->fsm, cfstore_fsm_event_commit_req, (void*) ctx); + cfstore_critical_section_unlock(&ctx->rw_area0_lock, __func__); + return ret; +} + +#else /* CFSTORE_CONFIG_BACKEND_FLASH_ENABLED */ + +static bool cfstore_flash_journal_is_async_op_pending(cfstore_ctx_t* ctx) { CFSTORE_FENTRYLOG("%s:SRAM:entered:\n", __func__); (void) ctx; return false; } + +/* @brief generate the CFSTORE_OPCODE_INITIALIZE callback notification */ +static int32_t cfstore_flash_init(void) +{ + cfstore_client_notify_data_t notify_data; + cfstore_ctx_t* ctx = cfstore_ctx_get(); + + CFSTORE_FENTRYLOG("%s:SRAM:entered:\n", __func__); + cfstore_client_notify_data_init(¬ify_data, CFSTORE_OPCODE_INITIALIZE, ARM_DRIVER_OK, NULL); + cfstore_ctx_client_notify(ctx, ¬ify_data); + return ARM_DRIVER_OK; +} + +static int32_t cfstore_flash_deinit(void){ CFSTORE_FENTRYLOG("%s:SRAM:entered:\n", __func__); return ARM_DRIVER_OK; } +/* static int32_t cfstore_flash_reset(void) { CFSTORE_FENTRYLOG("%s:SRAM:entered:\n", __func__); return ARM_DRIVER_OK; }*/ +static int32_t cfstore_flash_flush(cfstore_ctx_t* ctx) +{ + cfstore_client_notify_data_t notify_data; + + CFSTORE_FENTRYLOG("%s:SRAM:entered:\n", __func__); + cfstore_client_notify_data_init(¬ify_data, CFSTORE_OPCODE_FLUSH, ARM_DRIVER_OK, NULL); + cfstore_ctx_client_notify(ctx, ¬ify_data); + return ARM_DRIVER_OK; +} + +#endif /* CFSTORE_CONFIG_BACKEND_FLASH_ENABLED */ + +/** @brief internal delete helper function. + * @note must be called within critical section. + */ +static int32_t cfstore_delete_ex(cfstore_area_hkvt_t* hkvt) +{ + uint8_t* ptr = NULL; + int32_t ret = ARM_DRIVER_ERROR; + ARM_CFSTORE_SIZE kv_size = 0; + ARM_CFSTORE_SIZE area_size = 0; + ARM_CFSTORE_SIZE realloc_size = 0; /* size aligned to flash program_unit size */ + cfstore_ctx_t* ctx = cfstore_ctx_get(); + cfstore_file_t* file; + cfstore_list_node_t* node; + cfstore_list_node_t* file_list = &ctx->file_list; + + CFSTORE_FENTRYLOG("%s:entered:(ctx->area_0_head=%p, ctx->area_0_tail=%p)\n", __func__, ctx->area_0_head, ctx->area_0_tail); + kv_size = cfstore_hkvt_get_size(hkvt); + area_size = cfstore_ctx_get_area_len(); + memmove(hkvt->head, hkvt->tail, ctx->area_0_tail - hkvt->tail); + /* zero the deleted KV memory */ + memset(ctx->area_0_tail-kv_size, 0, kv_size); + + /* In the general case the new ((area_size - kv_size) % program_unit > 0). The new area_size is + * aligned to a program_unit boundary to facilitate r/w to flash and so the memory realloc size + * is calculated to align, as follows */ + /* setup the reallocation memory size. */ + realloc_size = area_size - kv_size; + if(realloc_size % cfstore_ctx_get_program_unit(ctx) > 0){ + realloc_size += (cfstore_ctx_get_program_unit(ctx) - (realloc_size % cfstore_ctx_get_program_unit(ctx))); + } + /* realloc() can return non-zero ptr for size = 0 when the last KV is deleted */ + if(realloc_size > 0) + { + ptr = (uint8_t*) CFSTORE_REALLOC((void*) ctx->area_0_head, realloc_size); + /* realloc can return NULL when the last KV is deleted. + * It also appears that realloc can return non-zero ptr even when realloc_size = 0 */ + if(ptr == NULL){ + CFSTORE_ERRLOG("%s:Error:realloc failed\n", __func__); + cfstore_ctx_reset(ctx); + return ARM_CFSTORE_DRIVER_ERROR_OUT_OF_MEMORY; + } + /* check realloc() hasnt move area in memory from cfstore_ctx_g.area_0_head */ + if(ptr != ctx->area_0_head){ + CFSTORE_TP(CFSTORE_TP_DELETE, "%s: cfstore_ctx_g.area_0_head pointer changed (cfstore_ctx_g.area_0_head=%p, cfstore_ctx_g.area_0_tail=%p)\n", __func__, ctx->area_0_head, ptr); + /* realloc() has moved the area in memory */ + ctx->area_0_head = ptr; + } + /* set tail to be the end of the new area, which will be updated by cfstore_flash_set_tail */ + ctx->area_0_tail = ptr + area_size - kv_size; + ret = cfstore_flash_set_tail(); + if(ret < ARM_DRIVER_OK){ + CFSTORE_ERRLOG("%s:Error: cfstore_flash_set_tail() failed (ret=%" PRId32 ")\n", __func__, ret); + goto out0; + } + + /* now have to walk the file list updating head pointers for the KVs that remain*/ + node = file_list->next; + while(node != file_list){ + /* Any KV positioned later in the area than the deleted KV will require file head pointers updating. + * If file's head pointer is beyond the deleted KV tail then the file->head needs to be updated + * to reflect the memove */ + file = (cfstore_file_t*) node; + if(file->head >= hkvt->head){ + file->head -= kv_size; + } + node = node->next; + } + } + else + { + /* realloc_size = 0 */ + CFSTORE_FREE((void*) ctx->area_0_head); + ctx->area_0_head = NULL; + ctx->area_0_tail = NULL; + } + ret = ARM_DRIVER_OK; +out0: + return ret; +} + + +/* + * File operations + */ + +static cfstore_file_t* cfstore_file_get(ARM_CFSTORE_HANDLE hkey) +{ + return (cfstore_file_t*) hkey; +} + +static cfstore_file_t* cfstore_file_create(cfstore_area_hkvt_t* hkvt, ARM_CFSTORE_FMODE flags, ARM_CFSTORE_HANDLE hkey, cfstore_list_node_t *list_head) +{ + int32_t ret = ARM_DRIVER_ERROR; + cfstore_file_t* file = (cfstore_file_t*) hkey; + + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + if(file != NULL){ + memset(file, 0, sizeof(cfstore_file_t)); + CFSTORE_INIT_LIST_HEAD(&file->node); + ret = cfstore_hkvt_refcount_inc(hkvt, NULL); + if(ret < ARM_DRIVER_OK){ + CFSTORE_ERRLOG("%s:Error: cfstore_hkvt_refcount_inc() failed (ret=%" PRId32 ")\n", __func__, ret); + return NULL; + } + file->head = hkvt->head; + file->flags.read = flags.read; + file->flags.write = flags.write; + if(list_head != NULL){ + cfstore_listAdd(list_head, &file->node, list_head); + } + } + return file; +} + +/* @brief required to be in critical section when called. */ +static int32_t cfstore_file_destroy(cfstore_file_t* file) +{ + int32_t ret = ARM_DRIVER_ERROR; + cfstore_area_hkvt_t hkvt; + uint8_t refcount = 0; + + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + if(file) { + hkvt = cfstore_get_hkvt_from_head_ptr(file->head); + CFSTORE_ASSERT(cfstore_hkvt_is_valid(&hkvt, cfstore_ctx_get()->area_0_tail) == true); + ret = ARM_DRIVER_OK; + cfstore_hkvt_refcount_dec(&hkvt, &refcount); + CFSTORE_TP(CFSTORE_TP_FILE, "%s:refcount =%d\n", __func__, (int)refcount); + if(refcount == 0){ + /* check for delete */ + CFSTORE_TP(CFSTORE_TP_FILE, "%s:checking delete flag\n", __func__); + if(cfstore_hkvt_get_flags_delete(&hkvt)){ + ret = cfstore_delete_ex(&hkvt); + } + /* reset client buffer to empty ready for reuse */ + /* delete the file even if not deleting the KV*/ + cfstore_listDel(&file->node); + memset(file, 0, sizeof(cfstore_file_t)); + } + } + return ret; +} + + +/** + * @brief check whether this is an valid buffer + * + * @param hkey + * IN: The key handle to be validated + * + * ctx + * IN: cfstore context block + */ +static bool cfstore_file_is_valid(ARM_CFSTORE_HANDLE hkey, cfstore_ctx_t* ctx) +{ + cfstore_file_t* file = cfstore_file_get(hkey); + + if(ctx->area_0_head != NULL && ctx->area_0_tail != NULL){ + if(file->head < ctx->area_0_head || file->head > ctx->area_0_tail){ + return 0; + } + return true; + } + return false; +} + +/** + * @brief check whether this is an empty buffer, or whether it + * has valid data + * + * @param hkey + * IN: The key handle to be validated + * + * ctx + * IN: cfstore context block + */ +static bool cfstore_file_is_empty(ARM_CFSTORE_HANDLE hkey) +{ + ARM_CFSTORE_HANDLE_INIT(zero); + if(hkey != NULL){ + return !memcmp(hkey, zero, CFSTORE_HANDLE_BUFSIZE); + } + return 0; +} + + +/* @brief See definition in configuration_store.h for description. */ +ARM_CFSTORE_CAPABILITIES cfstore_get_capabilities(void) +{ + /* getting capabilities doesnt change the sram area so this can happen independently of + * an oustanding async operation. its unnecessary to check the fsm state */ + return cfstore_caps_g; +} + + +/* @brief check the flags argument are supported */ +static int32_t cfstore_validate_fmode_flags(ARM_CFSTORE_FMODE flags) +{ + if(flags.continuous){ + CFSTORE_ERRLOG("%s:Error:Continuous flag not supported.\n", __func__); + return ARM_CFSTORE_DRIVER_ERROR_NOT_SUPPORTED; + } + if(flags.lazy_flush){ + CFSTORE_ERRLOG("%s:Error:Lazy flush flag not supported.\n", __func__); + return ARM_CFSTORE_DRIVER_ERROR_NOT_SUPPORTED; + } + if(flags.flush_on_close){ + CFSTORE_ERRLOG("%s:Error:Flush on close flag not supported.\n", __func__); + return ARM_CFSTORE_DRIVER_ERROR_NOT_SUPPORTED; + } + if(flags.storage_detect){ + CFSTORE_ERRLOG("%s:Error:Storage detect flag not supported.\n", __func__); + return ARM_CFSTORE_DRIVER_ERROR_NOT_SUPPORTED; + } + return ARM_DRIVER_OK; +} + + +/* @brief validate the client supplied opaque handle */ +static CFSTORE_INLINE int32_t cfstore_validate_handle(ARM_CFSTORE_HANDLE hkey) +{ + if(hkey == NULL){ + return ARM_CFSTORE_DRIVER_ERROR_INVALID_HANDLE; + } + return ARM_DRIVER_OK; +} + +/* @brief check the flash security features are valid (internal use only) */ +static int32_t cfstore_validate_flash_security_features(const ARM_STORAGE_SECURITY_FEATURES *security) +{ + CFSTORE_ASSERT(security != NULL); + + if(security->acls){ + CFSTORE_ERRLOG("%s:Error: flash security features acls flag not supported.\n", __func__); + return ARM_CFSTORE_DRIVER_ERROR_NOT_SUPPORTED; + } + if(security->internal_flash){ + CFSTORE_ERRLOG("%s:Error: flash security features internal_flash flag not supported.\n", __func__); + return ARM_CFSTORE_DRIVER_ERROR_NOT_SUPPORTED; + } + if(security->rollback_protection){ + CFSTORE_ERRLOG("%s:Error: flash security features rollback_protection flag not supported.\n", __func__); + return ARM_CFSTORE_DRIVER_ERROR_NOT_SUPPORTED; + } + if(security->tamper_proof){ + CFSTORE_ERRLOG("%s:Error: flash security features tamper_proof flag not supported.\n", __func__); + return ARM_CFSTORE_DRIVER_ERROR_NOT_SUPPORTED; + } + if(security->board_level_attacks){ + CFSTORE_ERRLOG("%s:Error: flash security features board level attacks flag not supported.\n", __func__); + return ARM_CFSTORE_DRIVER_ERROR_NOT_SUPPORTED; + } + if(security->software_attacks){ + CFSTORE_ERRLOG("%s:Error: flash security features device_software flag not supported.\n", __func__); + return ARM_CFSTORE_DRIVER_ERROR_NOT_SUPPORTED; + } + if(security->chip_level_attacks){ + CFSTORE_ERRLOG("%s:Error: flash security features chip level attacks flag not supported.\n", __func__); + return ARM_CFSTORE_DRIVER_ERROR_NOT_SUPPORTED; + } + if(security->side_channel_attacks){ + CFSTORE_ERRLOG("%s:Error: flash security features side channel attacks flag not supported.\n", __func__); + return ARM_CFSTORE_DRIVER_ERROR_NOT_SUPPORTED; + } + return ARM_DRIVER_OK; +} + +/* @brief check the key descriptor are valid (internal use only) */ +static int32_t cfstore_validate_flash_data_retention_level(const uint8_t drl) +{ + int32_t ret = ARM_DRIVER_ERROR; + + switch(drl) + { + case ARM_RETENTION_WHILE_DEVICE_ACTIVE : + case ARM_RETENTION_ACROSS_SLEEP : + case ARM_RETENTION_ACROSS_DEEP_SLEEP : + case ARM_RETENTION_BATTERY_BACKED : + case ARM_RETENTION_NVM : + ret = ARM_DRIVER_OK; + break; + default: + CFSTORE_ERRLOG("%s:Error: data retention level (%d) not supported.\n", __func__, drl); + ret = ARM_CFSTORE_DRIVER_ERROR_NOT_SUPPORTED; + break; + + } + return ret; +} + +/* @brief check the access control list is valid (internal use only) */ +static int32_t cfstore_validate_access_control_list(const ARM_CFSTORE_ACCESS_CONTROL_LIST acl) +{ + if(acl.perm_owner_execute) + { + CFSTORE_ERRLOG("%s:Error: Access control list with permission owner execute set is not supported.\n", __func__); + return ARM_CFSTORE_DRIVER_ERROR_NOT_SUPPORTED; + } + if(acl.perm_other_execute) + { + CFSTORE_ERRLOG("%s:Error: Access control list with permission other execute set is not supported.\n", __func__); + return ARM_CFSTORE_DRIVER_ERROR_NOT_SUPPORTED; + } + return ARM_DRIVER_OK; +} + +/* @brief check the key descriptor is valid */ +static int32_t cfstore_validate_key_desc(const ARM_CFSTORE_KEYDESC *kdesc) +{ + int32_t ret = ARM_DRIVER_ERROR; + + if(kdesc == NULL){ + return ARM_CFSTORE_DRIVER_ERROR_INVALID_KEY_DESCRIPTOR; + } + ret = cfstore_validate_access_control_list(kdesc->acl); + if(ret < ARM_DRIVER_OK){ + return ret; + } + ret = cfstore_validate_flash_data_retention_level(kdesc->drl); + if(ret < ARM_DRIVER_OK){ + return ret; + } + ret = cfstore_validate_flash_security_features(&kdesc->security); + if(ret < ARM_DRIVER_OK){ + return ret; + } + ret = cfstore_validate_fmode_flags(kdesc->flags); + if(ret < ARM_DRIVER_OK){ + return ret; + } + return ARM_DRIVER_OK; +} + +/** + * @brief check the key_len pointer is valid + * + * @param hkey + * IN: The key handle to be validated + */ +static CFSTORE_INLINE int32_t cfstore_validate_len_ptr(ARM_CFSTORE_SIZE *len) +{ + if(len == NULL){ + return ARM_CFSTORE_DRIVER_ERROR_INVALID_KEY_LEN; + } + return ARM_DRIVER_OK; +} + +/* @brief return a pointer to the next { or }, or NULL if not present */ +static inline char* cfstore_validate_pos_next_brace(const char* pos) +{ + char* pos_open = strchr(pos, '{'); + char* pos_close = strchr(pos, '}'); + if(pos_open != NULL) { + if(pos_close != NULL){ + return pos_open < pos_close ? pos_open : pos_close; + } + return pos_open; + } + return pos_close; +} + + +static int32_t cfstore_validate_key_name_ex(const char* key_name, const char* permissible) +{ + char* pos = NULL; + int brace_count = 0; + ARM_CFSTORE_SIZE len = 0; + ARM_CFSTORE_SIZE valid_len = 0; + + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + if(key_name != NULL){ + /* check the key_name is terminated by a 0 */ + pos = (char*) memchr(key_name, '\0', CFSTORE_KEY_NAME_MAX_LENGTH+1); + if(pos == NULL){ + CFSTORE_ERRLOG("%s:key_name does not have terminating null.\n", __func__); + return ARM_CFSTORE_DRIVER_ERROR_INVALID_KEY_NAME; + } + /* check for zero length key_name*/ + if(strlen(key_name) == 0){ + CFSTORE_ERRLOG("%s:Error: invalid key_name.\n", __func__); + return ARM_CFSTORE_DRIVER_ERROR_INVALID_KEY_NAME; + } + /* check the key_name len is less than the max length (220) */ + len = strlen(key_name); + if(len > CFSTORE_KEY_NAME_MAX_LENGTH){ + CFSTORE_ERRLOG("%s:key_name string is longer (%d) than the supported maximum (%d).\n", __func__, (int) len, (int) CFSTORE_KEY_NAME_MAX_LENGTH); + return ARM_CFSTORE_DRIVER_ERROR_INVALID_KEY_NAME; + } + /* check the key_name only contains permissible characters */ + valid_len = strspn(key_name, permissible); + if(valid_len != len){ + CFSTORE_ERRLOG("%s:Invalid character (%c) found in key_name (key_name=%s).\n", __func__, key_name[valid_len], key_name); + return ARM_CFSTORE_DRIVER_ERROR_INVALID_KEY_NAME; + } + + /*check there isnt a leading '.' on the kv name */ + if(key_name[0] == '.'){ + CFSTORE_ERRLOG("%s:Leading (.) character found in key_name (key_name=%s) is not allowed.\n", __func__, key_name); + return ARM_CFSTORE_DRIVER_ERROR_INVALID_KEY_NAME; + } + + /* - check for matching '{' for each '}' present + * - only check a string if either { or } are present + * i.e. dont process string without + * checking for existence of single brace, and checking for either { or } so + * that the case where } is the first brace is convered. + * - start loop at first { or } char, both {} covers case where } is the first brace + * - (brace_count >=0 && brace_count <= 1) must always be true + * - brace_count must == 0 at end of string + */ + pos = cfstore_validate_pos_next_brace(key_name); + while(pos != NULL && brace_count >= 0 && brace_count <= 1) + { + switch(*pos) + { + case '{': + brace_count++; + break; + case '}': + brace_count--; + break; + default: + break; + } + pos++; + pos = cfstore_validate_pos_next_brace(pos); + } + if(brace_count != 0){ + CFSTORE_ERRLOG("%s: Unmatched brace found in key_name (count=%" PRId32 ".\n", __func__, brace_count); + return ARM_CFSTORE_DRIVER_ERROR_INVALID_KEY_NAME; + } + } + return ARM_DRIVER_OK; +} + + +/* @brief check the key name is valid */ +static int32_t cfstore_validate_key_name(const char* key_name) +{ + int32_t ret = ARM_DRIVER_ERROR; + + ret = cfstore_uvisor_security_context_prefix_check(key_name); + if(ret < ARM_DRIVER_OK){ + CFSTORE_ERRLOG("%s:Error: failed uvisor security context check.\n", __func__); + return ret; + } + return cfstore_validate_key_name_ex(key_name, CFSTORE_KEY_NAME_CHARS_ACCEPTABLE); +} + +/* @brief check the key name query is valid */ +static int32_t cfstore_validate_key_name_query(const char* key_name_query) +{ + return cfstore_validate_key_name_ex(key_name_query, CFSTORE_KEY_NAME_QUERY_CHARS_ACCEPTABLE); +} + + +/** + * @brief check the value length field is valid + * + * @param key_name + * IN: The key name string to be validated + * @note This will be replaced with the actual uvisor call, when available. + */ +static CFSTORE_INLINE int32_t cfstore_validate_value_len(ARM_CFSTORE_SIZE value_len) +{ + if(value_len <= CFSTORE_VALUE_SIZE_MAX) { + return ARM_DRIVER_OK; + } + return ARM_CFSTORE_DRIVER_ERROR_VALUE_SIZE_TOO_LARGE; +} + + +/* @brief See definition in configuration_store.h for description. */ +static int32_t cfstore_get_key_name_ex(cfstore_area_hkvt_t *hkvt, char* key_name, uint8_t *key_name_len) +{ + int32_t ret = ARM_DRIVER_OK; + int32_t max_len = 0; + + max_len = cfstore_hkvt_get_key_len(hkvt) + 1; + max_len = max_len <= *key_name_len ? max_len : *key_name_len; + memcpy(key_name, (const char*) hkvt->key, max_len-1); + key_name[max_len-1] = '\0'; + *key_name_len = max_len; + return ret; +} + + +/* @brief See definition in configuration_store.h for description. */ +static int32_t cfstore_get_key_name(ARM_CFSTORE_HANDLE hkey, char* key_name, uint8_t *key_name_len) +{ + int32_t ret = ARM_DRIVER_ERROR; + cfstore_area_hkvt_t hkvt; + cfstore_client_notify_data_t notify_data; + cfstore_ctx_t* ctx = cfstore_ctx_get(); + + CFSTORE_ASSERT(key_name != NULL); + CFSTORE_ASSERT(key_name_len != NULL); + + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + if(!cfstore_ctx_is_initialised(ctx)) { + CFSTORE_ERRLOG("%s:Error: CFSTORE is not initialised.\n", __func__); + ret = ARM_CFSTORE_DRIVER_ERROR_UNINITIALISED; + goto out0; + } + /* getting a keyname doesnt change the sram area so this can happen independently of + * an oustanding async operation. its unnecessary to check the fsm state */ + ret = cfstore_validate_handle(hkey); + if(ret < ARM_DRIVER_OK){ + CFSTORE_ERRLOG("%s:Error: invalid handle.\n", __func__); + goto out0; + } + if(key_name == NULL){ + CFSTORE_ERRLOG("%s:Error: invalid handle.\n", __func__); + ret = ARM_CFSTORE_DRIVER_ERROR_INVALID_KEY_NAME; + goto out0; + } + ret = cfstore_validate_len_ptr((ARM_CFSTORE_SIZE*)key_name_len); + if(ret < ARM_DRIVER_OK){ + CFSTORE_ERRLOG("%s:Error: invalid key_name_len argument.\n", __func__); + goto out0; + } + memset(&hkvt, 0, sizeof(hkvt)); + hkvt = cfstore_get_hkvt(hkey); + if(!cfstore_hkvt_is_valid(&hkvt, ctx->area_0_tail)){ + CFSTORE_ERRLOG("%s:ARM_CFSTORE_DRIVER_ERROR_INVALID_HANDLE\n", __func__); + ret = ARM_CFSTORE_DRIVER_ERROR_INVALID_HANDLE; + goto out0; + } + ret = cfstore_get_key_name_ex(&hkvt, key_name, key_name_len); + if(ret < ARM_DRIVER_OK){ + CFSTORE_ERRLOG("%s:Error: cfstore_get_key_name_ex() returned error.\n", __func__); + goto out0; + } + ret = *key_name_len; +out0: + /* GetKeyName() always completes synchronously irrespective of flash mode, so indicate to caller */ + cfstore_client_notify_data_init(¬ify_data, CFSTORE_OPCODE_GET_KEY_NAME, ret, hkey); + cfstore_ctx_client_notify(ctx, ¬ify_data); + return ret; +} + +/* @brief See definition in configuration_store.h for description. */ +static ARM_CFSTORE_STATUS cfstore_get_status(void) +{ + ARM_CFSTORE_STATUS status; + cfstore_ctx_t* ctx = cfstore_ctx_get(); + + memset(&status, 0, sizeof(status)); + if(!cfstore_ctx_is_initialised(ctx)) { + CFSTORE_ERRLOG("%s:Error: CFSTORE is not initialised.\n", __func__); + status.error = true; + } + /* getting status doesnt change the sram area so this can happen independently of + * an oustanding async operation. */ + if(cfstore_flash_journal_is_async_op_pending(ctx)) + { + status.in_progress = true; + } + else + { + status.in_progress = false; + } + return status; +} + +/* @brief See definition in configuration_store.h for description. */ +static int32_t cfstore_get_value_len(ARM_CFSTORE_HANDLE hkey, ARM_CFSTORE_SIZE *value_len) +{ + int32_t ret = ARM_CFSTORE_DRIVER_ERROR_UNINITIALISED; + cfstore_area_hkvt_t hkvt; + cfstore_client_notify_data_t notify_data; + cfstore_ctx_t* ctx = cfstore_ctx_get(); + + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + CFSTORE_ASSERT(hkey != NULL); + CFSTORE_ASSERT(value_len != NULL); + + if(!cfstore_ctx_is_initialised(ctx)) { + CFSTORE_ERRLOG("%s:Error: CFSTORE is not initialised.\n", __func__); + goto out0; + } + /* getting a value len doesnt change the sram area so this can happen independently of + * an oustanding async operation. its unnecessary to check the fsm state */ + ret = cfstore_validate_handle(hkey); + if(ret < ARM_DRIVER_OK){ + CFSTORE_ERRLOG("%s:Error: invalid handle.\n", __func__); + goto out0; + } + ret = cfstore_validate_len_ptr(value_len); + if(ret < ARM_DRIVER_OK){ + CFSTORE_ERRLOG("%s:Error: invalid value len argument.\n", __func__); + goto out0; + } + hkvt = cfstore_get_hkvt(hkey); + if(!cfstore_hkvt_is_valid(&hkvt, ctx->area_0_tail)){ + CFSTORE_ERRLOG("%s:ARM_CFSTORE_DRIVER_ERROR_INVALID_HANDLE\n", __func__); + ret = ARM_CFSTORE_DRIVER_ERROR_INVALID_HANDLE; + goto out0; + } + *value_len = cfstore_hkvt_get_value_len(&hkvt); + ret = (int32_t) *value_len; +out0: + /* GetValueLen() always completes synchronously irrespective of flash mode, so indicate to caller */ + cfstore_client_notify_data_init(¬ify_data, CFSTORE_OPCODE_GET_VALUE_LEN, ret, hkey); + cfstore_ctx_client_notify(ctx, ¬ify_data); + return ret; +} + +#ifdef CFSTORE_DEBUG + +/* @brief debug trace a struct cfstore_area_hkvt_t, providing values for key field. */ +static CFSTORE_INLINE void cfstore_hkvt_dump(cfstore_area_hkvt_t* hkvt, const char* tag) +{ +/* #define noSymbol */ +#ifdef noSymbol + char kname[CFSTORE_KEY_NAME_MAX_LENGTH+1]; + char value[CFSTORE_KEY_NAME_MAX_LENGTH+1]; + uint32_t klen = 0; + uint32_t vlen = 0; + cfstore_ctx_t* ctx = cfstore_ctx_get(); + + memset(kname, 0, CFSTORE_KEY_NAME_MAX_LENGTH+1); + memset(value, 0, CFSTORE_KEY_NAME_MAX_LENGTH+1); + klen = cfstore_hkvt_get_key_len(hkvt); + vlen = cfstore_hkvt_get_value_len(hkvt); + memcpy((void*)kname, (void*) hkvt->key, klen); + memcpy((void*)value, (void*) hkvt->value, vlen); + kname[klen] = '\0'; + value[vlen] = '\0'; + + /* table column description + * col 1: tag, descriptive string supplied by client to identify context of table dump + * col 2: hkvt struct member that is to be reported i.e. head, key, value, tail + * col 3: the value of the pointer described in col 2. + * col 4: the value of the pointer described in col 3 as an offset from the start of the sram area + * col 5: field specified data e.g. for header, the extracted key length, value_length. + */ + CFSTORE_TP(CFSTORE_TP_VERBOSE3, "%s:hkvt->head:%8p:%8p:klen=%08d:vlen=%08d:\n", tag, hkvt->head, (void*)(hkvt->head - ctx->area_0_head), (int) klen, (int) vlen); + CFSTORE_TP(CFSTORE_TP_VERBOSE3, "%s:hkvt->key :%8p:%8p:%s\n", tag, hkvt->key, (void*)(hkvt->key - ctx->area_0_head), kname); + CFSTORE_TP(CFSTORE_TP_VERBOSE3, "%s:hkvt->val :%8p:%8p:%s\n", tag, hkvt->value, (void*)(hkvt->value - ctx->area_0_head), value); + CFSTORE_TP(CFSTORE_TP_VERBOSE3, "%s:hkvt->tail:%8p:%8p:\n", tag, hkvt->tail, (void*)(hkvt->tail - ctx->area_0_head)); + return; +#else + (void) hkvt; + (void) tag; + +#endif /* noSymbol */ +} + +static CFSTORE_INLINE void cfstore_flags_dump(ARM_CFSTORE_FMODE flag, const char* tag) +{ + int pos = 0; + char flags[9]; + + pos += snprintf(&flags[pos], 9, "%c", flag.continuous ? 'C' : 'c'); + pos += snprintf(&flags[pos], 9, "%c", flag.lazy_flush ? 'L' : 'l'); + pos += snprintf(&flags[pos], 9, "%c", flag.flush_on_close ? 'F' : 'f'); + pos += snprintf(&flags[pos], 9, "%c", flag.read ? 'R' : 'r'); + pos += snprintf(&flags[pos], 9, "%c", flag.write ? 'W' : 'w'); + pos += snprintf(&flags[pos], 9, "%c", flag.storage_detect ? 'S' : 's'); + pos += snprintf(&flags[pos], 9, "--"); + + CFSTORE_TP(CFSTORE_TP_VERBOSE3, "%s:flags :%s:(C=>continuous set, L=>lazy flush, F=>flush on close, R=>read, W=>write, S=>storage detect)\n", tag, flags); + return; +} + +static CFSTORE_INLINE void cfstore_file_dump(cfstore_file_t* file, const char* tag) +{ +#ifdef noSymbol + cfstore_area_hkvt_t hkvt; + + CFSTORE_TP(CFSTORE_TP_VERBOSE3, "%s:*** Dumping File Contents : Start ***\n", tag); + CFSTORE_TP(CFSTORE_TP_VERBOSE3, "%s:file==hkey:%p\n", tag, file); + CFSTORE_TP(CFSTORE_TP_VERBOSE3, "%s:rloc/wloc :%08u/%08u:\n", tag, (unsigned int) file->rlocation, (unsigned int) file->wlocation); + cfstore_flags_dump(file->flags, tag); + hkvt = cfstore_get_hkvt((ARM_CFSTORE_HANDLE)file); + cfstore_hkvt_dump(&hkvt, tag); + CFSTORE_TP(CFSTORE_TP_VERBOSE3, "%s:*** Dumping File Contents : End ***\n", tag); + return; +#else + (void) file; + (void) tag; + +#endif /* noSymbol */ +} + +/* dump sram contents of cfstore in a useful manner for debugging */ +static CFSTORE_INLINE void cfstore_dump_contents(const char* tag) +{ + int32_t ret = ARM_DRIVER_ERROR; + cfstore_area_hkvt_t hkvt; + cfstore_ctx_t* ctx = cfstore_ctx_get(); + + CFSTORE_TP(CFSTORE_TP_VERBOSE3, "%s:*** Dumping CFSTORE Contents : Start ***\n", tag); + CFSTORE_TP(CFSTORE_TP_VERBOSE3, "%s:cfstore_ctx_g.area_0_head=%8p\n", tag, ctx->area_0_head); + CFSTORE_TP(CFSTORE_TP_VERBOSE3, "%s:cfstore_ctx_g.area_0_tail=%8p\n", tag, ctx->area_0_tail); + ret = cfstore_get_head_hkvt(&hkvt); + if(ret == ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND){ + CFSTORE_TP(CFSTORE_TP_VERBOSE1, "%s:CFSTORE has no KVs\n", tag); + goto out0; + } else if(ret < ARM_DRIVER_OK){ + CFSTORE_ERRLOG("%s:Error: could not get head of list.\n", tag); + goto out0; + } + while(cfstore_get_next_hkvt(&hkvt, &hkvt) != ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND) + { + cfstore_hkvt_dump(&hkvt, tag); + } +out0: + CFSTORE_TP(CFSTORE_TP_VERBOSE3, "%s:*** Dumping CFSTORE Contents : End ***\n", tag); + return; +} + + + +#else +static CFSTORE_INLINE void cfstore_hkvt_dump(cfstore_area_hkvt_t* hkvt, const char* tag){ (void) hkvt; (void) tag; return; } +static CFSTORE_INLINE void cfstore_file_dump(cfstore_file_t* file, const char* tag){ (void) file; (void) tag; return; } +static CFSTORE_INLINE void cfstore_dump_contents(const char* tag){ (void) tag; return; } +static CFSTORE_INLINE void cfstore_flags_dump(ARM_CFSTORE_FMODE flag, const char* tag){ (void) flag; (void) tag; return; } +#endif /*CFSTORE_DEBUG*/ + +/* + * CS operations + */ + +/* @brief See definition in configuration_store.h for description. */ +ARM_DRIVER_VERSION cfstore_get_version(void) +{ + /* getting version info doesnt change the sram area so this can happen independently of + * an oustanding async operation. its unnecessary to check the fsm state */ + return cfstore_driver_version_g; +} + + +/* + * CS API Key-Value operations + */ + +/* @brief See definition in configuration_store.h for description. */ +static int32_t cfstore_delete(ARM_CFSTORE_HANDLE hkey) +{ + int32_t ret = ARM_DRIVER_ERROR; + cfstore_area_hkvt_t hkvt; + cfstore_ctx_t* ctx = cfstore_ctx_get(); + cfstore_client_notify_data_t notify_data; + + CFSTORE_TP((CFSTORE_TP_DELETE|CFSTORE_TP_FENTRY), "%s:entered\n", __func__); + if(!cfstore_ctx_is_initialised(ctx)) { + CFSTORE_TP(CFSTORE_TP_DELETE, "%s:Error: CFSTORE is not initialised.\n", __func__); + ret = ARM_CFSTORE_DRIVER_ERROR_UNINITIALISED; + goto out0; + } + /* deleting a key will change the sram area while a logging/flushing operation is pending, which + * should not happen while an async operation is outstanding */ + if(cfstore_flash_journal_is_async_op_pending(ctx)) { + CFSTORE_TP(CFSTORE_TP_DELETE, "%s:Debug: flash journal operation pending (awaiting asynchronous notification).\n", __func__); + ret = ARM_CFSTORE_DRIVER_ERROR_OPERATION_PENDING; + goto out0; + } + ret = cfstore_validate_handle(hkey); + if(ret < ARM_DRIVER_OK){ + CFSTORE_ERRLOG("%s:Error: invalid handle.\n", __func__); + goto out0; + } + if(!cfstore_is_kv_client_deletable((cfstore_file_t*) hkey)){ + CFSTORE_ERRLOG("%s:Error: client is not permitted to delete KV.\n", __func__); + ret = ARM_CFSTORE_DRIVER_ERROR_NO_PERMISSIONS; + goto out0; + } + hkvt = cfstore_get_hkvt(hkey); + /* check its a valid hkvt */ + if(!cfstore_hkvt_is_valid(&hkvt, ctx->area_0_tail)){ + CFSTORE_ERRLOG("%s:ARM_CFSTORE_DRIVER_ERROR_INVALID_HANDLE\n", __func__); + ret = ARM_CFSTORE_DRIVER_ERROR_INVALID_HANDLE; + goto out0; + } + /* set the delete flag so the delete occurs when the file is closed + * no further handles will be returned to this key */ + cfstore_hkvt_set_flags_delete(&hkvt, true); +out0: + /* Delete() always completes synchronously irrespective of flash mode, so indicate to caller */ + cfstore_client_notify_data_init(¬ify_data, CFSTORE_OPCODE_DELETE, ret, NULL); + cfstore_ctx_client_notify(ctx, ¬ify_data); + return ret; +} + + +/** @brief Internal find function using hkvt's. + * + * @note + * Not the following: + * - Any required locks should be taken before this function is called. + * This function does not affect refcount for underlying KVs. + * - The function assumes the arguments have been validated before calling this function + * - No acl policy is enforced by the function. + * + * @return return_value + * On success (finding a KV matching the query) ARM_DRIVER_OK is + * returned. If a KV is not found matching the description then + * ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND is returned. + */ +static int32_t cfstore_find_ex(const char* key_name_query, cfstore_area_hkvt_t *prev, cfstore_area_hkvt_t *next) +{ + int32_t ret = ARM_DRIVER_ERROR; + uint8_t next_key_len; + char key_name[CFSTORE_KEY_NAME_MAX_LENGTH+1]; + cfstore_ctx_t* ctx = cfstore_ctx_get(); + + CFSTORE_TP((CFSTORE_TP_FIND|CFSTORE_TP_FENTRY), "%s:entered: key_name_query=\"%s\", prev=%p, next=%p\n", __func__, key_name_query, prev, next); + if(prev == NULL){ + ret = cfstore_get_head_hkvt(next); + /* CFSTORE_TP(CFSTORE_TP_FIND, "%s:next->head=%p, next->key=%p, next->value=%p, next->tail=%p, \n", __func__, next->head, next->key, next->value, next->tail); */ + if(ret == ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND){ + CFSTORE_TP(CFSTORE_TP_FIND, "%s:CFSTORE has no KVs\n", __func__); + return ret; + } else if(ret < ARM_DRIVER_OK) { + CFSTORE_TP(CFSTORE_TP_FIND, "%s:failed to find the first KV in area\n", __func__); + return ret; + } + + /* check for no KVs in the store => hkvt is not valid */ + if(!cfstore_hkvt_is_valid(next, ctx->area_0_tail)){ + /* no KVs in store */ + CFSTORE_TP(CFSTORE_TP_FIND, "%s:hkvt is not valid\n", __func__); + return ARM_DRIVER_OK; + } + + } else { + /* CFSTORE_TP(CFSTORE_TP_FIND, "%s:getting hkvt from prev\n", __func__);*/ + ret = cfstore_get_next_hkvt(prev, next); + if(ret < ARM_DRIVER_OK){ + /* no more matching entries or error. + * either way, return*/ + return ret; + } + } + if(next->head == NULL){ + /* no entry*/ + CFSTORE_TP(CFSTORE_TP_FIND, "%s:No more entries found\n", __func__); + return ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND; + } + /* CFSTORE_TP(CFSTORE_TP_FIND, "%s:cfstore_ctx_g.area_0_head=%p, cfstore_ctx_g.area_0_tail=%p\n", __func__, cfstore_ctx_g.area_0_head, cfstore_ctx_g.area_0_tail);*/ + cfstore_hkvt_dump(next, __func__); + while(cfstore_hkvt_is_valid(next, ctx->area_0_tail)) + { + /* CFSTORE_TP(CFSTORE_TP_FIND, "%s:next->head=%p, next->key=%p, next->value=%p, next->tail=%p, \n", __func__, next->head, next->key, next->value, next->tail); */ + cfstore_hkvt_dump(next, __func__); + + /* if this KV is deleting then proceed to the next item */ + // Note: It is probably better not to enforce policy in this function + // but in the client + if(cfstore_hkvt_get_flags_delete(next)){ + ret = cfstore_get_next_hkvt(next, next); + if(ret == ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND) { + CFSTORE_TP(CFSTORE_TP_FIND, "%s:No more KVs found\n", __func__); + break; + } + continue; + } + /* if this KV is not readable by the client then proceed to the next item */ + // Note: It is probably better not to enforce policy in this function + // but in the client + if(!cfstore_is_kv_client_readable(next)){ + ret = cfstore_get_next_hkvt(next, next); + if(ret == ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND) { + CFSTORE_TP(CFSTORE_TP_FIND, "%s:No more KVs found\n", __func__); + break; + } + continue; + } + /* check if this key_name matches the query */ + next_key_len = cfstore_hkvt_get_key_len(next); + next_key_len++; + cfstore_get_key_name_ex(next, key_name, &next_key_len); + ret = fnmatch(key_name_query, key_name, 0); + if(ret == 0){ + /* found the entry in the store. return handle */ + CFSTORE_TP(CFSTORE_TP_FIND, "%s:Found matching key (key_name_query = \"%s\", next->key = \"%s\"),next_key_len=%d\n", __func__, key_name_query, key_name, (int) next_key_len); + cfstore_hkvt_dump(next, __func__); + return ARM_DRIVER_OK; + } else if(ret != FNM_NOMATCH){ + CFSTORE_ERRLOG("%s:Error: fnmatch() error (ret=%" PRId32 ").\n", __func__, ret); + return ARM_DRIVER_ERROR; + } + /* FNM_NOMATCH => get the next hkvt if any */ + ret = cfstore_get_next_hkvt(next, next); + if(ret == ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND) { + CFSTORE_TP(CFSTORE_TP_FIND, "%s:No more KVs found\n", __func__); + break; + } + } + return ARM_DRIVER_OK; +} + + +/* @brief See definition in configuration_store.h for description. */ +static int32_t cfstore_find(const char* key_name_query, const ARM_CFSTORE_HANDLE previous, ARM_CFSTORE_HANDLE next) +{ + char key_name[CFSTORE_KEY_NAME_MAX_LENGTH+1]; + uint8_t key_len = 0; + cfstore_area_hkvt_t hkvt_next; + cfstore_area_hkvt_t hkvt_previous; + cfstore_area_hkvt_t *phkvt_previous = NULL; + int32_t ret = ARM_DRIVER_ERROR; + ARM_CFSTORE_FMODE fmode; + cfstore_ctx_t* ctx = cfstore_ctx_get(); + cfstore_client_notify_data_t notify_data; + + CFSTORE_ASSERT(next != NULL); + CFSTORE_FENTRYLOG("%s:entered: key_name_query=\"%s\", previous=%p, next=%p\n", __func__, key_name_query, previous, next); + if(!cfstore_ctx_is_initialised(ctx)) { + CFSTORE_ERRLOG("%s:Error: CFSTORE is not initialised.\n", __func__); + ret = ARM_CFSTORE_DRIVER_ERROR_UNINITIALISED; + goto out1; + } + /* finding a key doesnt change the sram area so this can happen independently of + * an oustanding async operation. its unnecessary to check the fsm state */ + ret = cfstore_validate_key_name_query(key_name_query); + if(ret < ARM_DRIVER_OK){ + CFSTORE_ERRLOG("%s:Error: invalid key_name.\n", __func__); + goto out1; + } + ret = cfstore_validate_handle(next); + if(ret < ARM_DRIVER_OK){ + CFSTORE_ERRLOG("%s:Error: invalid next argument.\n", __func__); + goto out1; + } + /* note previous can be NULL if this is the first call the find */ + memset(&hkvt_next, 0, sizeof(hkvt_next)); + memset(&fmode, 0, sizeof(fmode)); + if(previous != NULL && cfstore_file_is_valid(previous, ctx)){ + ret = cfstore_validate_handle(previous); + if(ret < ARM_DRIVER_OK){ + CFSTORE_ERRLOG("%s:Error: invalid handle.\n", __func__); + goto out1; + } + phkvt_previous = &hkvt_previous; + memset(phkvt_previous, 0, sizeof(hkvt_previous)); + hkvt_previous = cfstore_get_hkvt(previous); + cfstore_hkvt_dump(&hkvt_previous, __func__); + if(!cfstore_hkvt_is_valid(phkvt_previous, ctx->area_0_tail)){ + ret = ARM_CFSTORE_DRIVER_ERROR_INVALID_HANDLE; + goto out1; + } + } else if(!cfstore_file_is_empty(previous)){ + ret = ARM_CFSTORE_DRIVER_ERROR_INVALID_HANDLE_BUF; + goto out1; + } + ret = cfstore_find_ex(key_name_query, phkvt_previous, &hkvt_next); + if(ret < ARM_DRIVER_OK){ + /* either no more entries or error but either way, return */ + CFSTORE_TP(CFSTORE_TP_FIND, "%s:No more KVs found.\n", __func__); + goto out2; + } + + if(!cfstore_hkvt_is_valid(&hkvt_next, ctx->area_0_tail)){ + CFSTORE_TP(CFSTORE_TP_FIND, "%s:Did not find any matching KVs.\n", __func__); + ret = ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND; + goto out2; + } + + /* Have a valid kv. cfstore_find_ex() checked the client has + * permission to read the KV, so dont have to perform this check again here. */ + + /* return handle to client */ + cfstore_file_create(&hkvt_next, fmode, next, &ctx->file_list); + ret = ARM_DRIVER_OK; +out2: + /* previous handle is being returned to CFSTORE with this call so destroy file struct */ + if(previous != NULL && cfstore_file_is_valid(previous, ctx)) + { + /* do not use ret in this stanza as will loose return state from above */ + /* CFSTORE_TP(CFSTORE_TP_FIND, "%s:about to destroy KV, previous=%p.\n", __func__, previous); */ + cfstore_file_dump((cfstore_file_t*) previous, __func__); + + key_len = CFSTORE_KEY_NAME_MAX_LENGTH+1; + memset(key_name, 0, CFSTORE_KEY_NAME_MAX_LENGTH+1); + if(cfstore_get_key_name_ex(&hkvt_next, key_name, &key_len) < ARM_DRIVER_OK){ + /* either no more entries or error but either way, return */ + CFSTORE_TP(CFSTORE_TP_FIND, "%s:debug: cfstore_get_key_name_ex failed or no more kvs.\n", __func__); + goto out1; + } + cfstore_file_destroy(cfstore_file_get(previous)); + /* now get hkvt_next again based on the name to overcome the fact that the hkvt + * may be invalid due to the possible deletion of the previous KV.x */ + if(cfstore_find_ex(key_name, NULL, &hkvt_next) < ARM_DRIVER_OK){ + /* either no more entries or error but either way, return */ + CFSTORE_TP(CFSTORE_TP_FIND, "%s:find failed key_name=%s ret=%" PRId32 ".\n", __func__, key_name, ret); + goto out1; + } + cfstore_hkvt_dump(&hkvt_next, __func__); + } +out1: + /* Find() always completes synchronously irrespective of flash mode, so indicate to caller */ + cfstore_client_notify_data_init(¬ify_data, CFSTORE_OPCODE_FIND, ret, next); + cfstore_ctx_client_notify(ctx, ¬ify_data); + return ret; +} + + +/* @brief grow/shrink pre-existing KV. + * + * @note rw_lock must be held by the caller of this function rw_area0_lock */ +static int32_t cfstore_recreate(const char* key_name, ARM_CFSTORE_SIZE value_len, ARM_CFSTORE_HANDLE hkey, cfstore_area_hkvt_t* hkvt) +{ + uint8_t* ptr = NULL; + int32_t kv_size_diff = 0; + ARM_CFSTORE_SIZE area_size = 0; + ARM_CFSTORE_FMODE flags; + cfstore_ctx_t* ctx = cfstore_ctx_get(); + + CFSTORE_FENTRYLOG("%s:entered: key_name=\"%s\", value_len=%d\n", __func__, key_name, (int) value_len); + cfstore_dump_contents(__func__); + memset(&flags, 0, sizeof(flags)); + flags.read = true; + flags.write = true; + kv_size_diff = value_len - cfstore_hkvt_get_value_len(hkvt); + if(kv_size_diff == 0){ + /* nothing more to do*/ + CFSTORE_TP(CFSTORE_TP_CREATE, "%s:new value length the same as the old\n", __func__); + return ARM_DRIVER_OK; + } + + CFSTORE_TP(CFSTORE_TP_CREATE, "%s:cfstore_ctx_g.area_0_head=%p, cfstore_ctx_g.area_0_tail=%p\n", __func__, ctx->area_0_head, ctx->area_0_tail); + CFSTORE_TP(CFSTORE_TP_CREATE, "%s:sizeof(header)=%d, sizeof(key)=%d, sizeof(value)=%d, kv_size_diff=%d, area_size=%d\n", __func__, (int) sizeof(cfstore_area_header_t), (int)(strlen(key_name)), (int)value_len, (int) kv_size_diff, (int) area_size); + + /* grow the area by the size of the new KV */ + area_size = cfstore_ctx_get_area_len(); + if (kv_size_diff < 0){ + /* value blob size shrinking => do memmove() before realloc() which will free memory */ + memmove(hkvt->tail + kv_size_diff, hkvt->tail, ctx->area_0_tail - hkvt->tail); + //todo: wip: do we have to update file pointers for KVs after the one thats changed size? + } + ptr = (uint8_t*) CFSTORE_REALLOC((void*) ctx->area_0_head, area_size + kv_size_diff); + if(ptr == NULL){ + CFSTORE_ERRLOG("%s:realloc failed for key_name=%s\n", __func__, key_name); + cfstore_ctx_reset(ctx); + return ARM_CFSTORE_DRIVER_ERROR_OUT_OF_MEMORY; + } + if(ptr != ctx->area_0_head){ + CFSTORE_TP(CFSTORE_TP_CREATE, "%s:cfstore_ctx_g.area_0_head pointer changed (cfstore_ctx_g.area_0_head=%p, cfstore_ctx_g.area_0_tail=%p)\n", __func__, ctx->area_0_head, ptr); + /* This covers the cases where CFSTORE_REALLOC() has moved the area in memory + * As realloc() has caused the memory to move, hkvt needs re-initialising */ + hkvt->head += ptr - ctx->area_0_head; + hkvt->key += ptr - ctx->area_0_head; + hkvt->value += ptr - ctx->area_0_head; + hkvt->tail += ptr - ctx->area_0_head; + /* Set head and tail to old relative position in new area */ + ctx->area_0_head = ptr; + ctx->area_0_tail = ctx->area_0_head + area_size; + //todo: wip: do we have to update file pointers for KVs after the memory has moved? + } + + if(kv_size_diff > 0) { + /* value blob size growing requires memmove() after realloc() */ + memset(ctx->area_0_tail, 0, kv_size_diff); + memmove(hkvt->tail+kv_size_diff, hkvt->tail, ctx->area_0_tail - hkvt->tail); + //todo: wip: do we have to update file pointers for KVs after the one thats changed size? + } + /* hkvt->head, hkvt->key and hkvt->value remain unchanged but hkvt->tail has moved. Update it.*/ + hkvt->tail = hkvt->tail + kv_size_diff; + + /* set the new value length in the header */ + cfstore_hkvt_set_value_len(hkvt, value_len); + ctx->area_0_tail = ctx->area_0_head + area_size + kv_size_diff; + cfstore_file_create(hkvt, flags, hkey, &ctx->file_list); + ctx->area_dirty_flag = true; + +#ifdef CFSTORE_DEBUG + cfstore_hkvt_dump(hkvt, __func__); + cfstore_dump_contents(__func__); +#endif + return ARM_DRIVER_OK; +} + + +/* @brief See definition in configuration_store.h for description. */ +static int32_t cfstore_create(const char* key_name, ARM_CFSTORE_SIZE value_len, const ARM_CFSTORE_KEYDESC* kdesc, ARM_CFSTORE_HANDLE hkey) +{ + bool b_acl_default = false; + uint8_t* ptr = NULL; + int32_t ret = ARM_DRIVER_ERROR; + int32_t cfstore_uvisor_box_id = 0; + ARM_CFSTORE_SIZE area_size = 0; + ARM_CFSTORE_SIZE kv_size = 0; + ARM_CFSTORE_SIZE realloc_size = 0; + cfstore_area_header_t* hdr; + cfstore_area_hkvt_t hkvt; + cfstore_ctx_t* ctx = cfstore_ctx_get(); + ARM_CFSTORE_FMODE flags; + cfstore_client_notify_data_t notify_data; + + CFSTORE_FENTRYLOG("%s:entered: key_name=\"%s\", value_len=%d, kdesc=%p\n", __func__, key_name, (int)value_len, kdesc); + CFSTORE_ASSERT(kdesc != NULL); + CFSTORE_ASSERT(hkey != NULL); + + memset(&flags, 0, sizeof(flags)); + if(!cfstore_ctx_is_initialised(ctx)) { + CFSTORE_ERRLOG("%s:Error: CFSTORE is not initialised.\n", __func__); + return ARM_CFSTORE_DRIVER_ERROR_UNINITIALISED; + } + /* creating a key cannot happen while a flashJournal_log() is pending as it would change the sram area being logged*/ + if(cfstore_flash_journal_is_async_op_pending(ctx)) { + CFSTORE_TP(CFSTORE_TP_CREATE, "%s:Debug: flash journal operation pending (awaiting asynchronous notification).\n", __func__); + return ARM_CFSTORE_DRIVER_ERROR_OPERATION_PENDING; + } + ret = cfstore_validate_key_name(key_name); + if(ret < ARM_DRIVER_OK){ + CFSTORE_ERRLOG("%s:Error: invalid key_name (%s).\n", __func__, key_name); + goto out0; + } + ret = cfstore_validate_handle(hkey); + if(ret < ARM_DRIVER_OK){ + CFSTORE_ERRLOG("%s:Error: invalid handle.\n", __func__); + goto out0; + } + ret = cfstore_validate_value_len(value_len); + if(ret < ARM_DRIVER_OK){ + CFSTORE_ERRLOG("%s:Error: invalid key_name.\n", __func__); + goto out0; + } + /* check uvisor security */ + if(cfstore_is_client_kv_owner(key_name, &cfstore_uvisor_box_id) != ARM_DRIVER_OK){ + CFSTORE_ERRLOG("%s:Error: Client has insufficient permissions to create KV.\n", __func__); + ret = ARM_CFSTORE_DRIVER_ERROR_NO_PERMISSIONS; + goto out0; + } + /* the cfstore (uvisor) client is the owner of the KV and therefore is permitted to created it */ + /* A null kdesc is permitted if client is growing/shrinking pre-existing key. + * Hence, find if key_name pre-exists before validating kdesc */ + ret = cfstore_find_ex(key_name, NULL, &hkvt); + if(ret < ARM_DRIVER_OK && ret != ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND){ + CFSTORE_ERRLOG("%s:CFSTORE find() returned error (%" PRId32 ")\n", __func__, ret); + goto out1; + } + + if(ret != ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND && cfstore_hkvt_is_valid(&hkvt, ctx->area_0_tail)){ + /* found pre-existing entry; */ + if(cfstore_hkvt_get_flags_delete(&hkvt)){ + CFSTORE_ERRLOG("%s:CFSTORE pre-existing KV with key_name=\"%s\" deleting\n", __func__, key_name); + ret = ARM_CFSTORE_DRIVER_ERROR_PREEXISTING_KEY_DELETING; + goto out1; + } + if(kdesc != NULL) { + CFSTORE_ERRLOG("%s:CFSTORE contains pre-existing KV with key_name=\"%s\". Cannot create a new KV with the same name\n", __func__, key_name); + ret = ARM_CFSTORE_DRIVER_ERROR_PREEXISTING_KEY; + goto out1; + } + + /* client is requesting to grow/shrink pre-existing key */ + ret = cfstore_recreate(key_name, value_len, hkey, &hkvt); + goto out1; + } + /* not a valid hkvt implying the key_name wasnt found */ + + /* create new key */ + ret = cfstore_validate_key_desc(kdesc); + if(ret < ARM_DRIVER_OK){ + CFSTORE_ERRLOG("%s:Error: invalid key descriptor.\n", __func__); + goto out1; + } + /* insert the KV into the area */ + kv_size = strlen(key_name); + kv_size += value_len; + kv_size += sizeof(cfstore_area_header_t); + + /* grow the area by the size of the new KV + * In the general case the new ((area_size + kv_size) % program_unit > 0). The new area_size is + * aligned to a program_unit boundary to facilitate r/w to flash and so the memory realloc size + * is calculated to align, as follows */ + area_size = cfstore_ctx_get_area_len(); + // moved to flash_init() and program_unit stored in ctx + /* + status = FlashJournal_getInfo(&ctx->jrnl, &info); + if(status < JOURNAL_STATUS_OK){ + CFSTORE_TP(CFSTORE_TP_CREATE, "%s:Error: failed get journal info (status=%d)\n", __func__, (int) status); + ret = cfstore_flash_map_error(status); + goto out1; + } + */ + /* setup the reallocation memory size. */ + realloc_size = area_size + kv_size; + if(realloc_size % cfstore_ctx_get_program_unit(ctx) > 0){ + realloc_size += (cfstore_ctx_get_program_unit(ctx) - (realloc_size % cfstore_ctx_get_program_unit(ctx))); + } + ptr = (uint8_t*) CFSTORE_REALLOC((void*) ctx->area_0_head, realloc_size); + if(ptr == NULL){ + CFSTORE_ERRLOG("%s:realloc failed for key_name=%s\n", __func__, key_name); + cfstore_ctx_reset(ctx); + ret = ARM_CFSTORE_DRIVER_ERROR_OUT_OF_MEMORY; + goto out1; + } + if(ptr != ctx->area_0_head){ + CFSTORE_TP(CFSTORE_TP_CREATE, "%s:cfstore_ctx_g.area_0_head pointer changed (cfstore_ctx_g.area_0_head=%p, cfstore_ctx_g.area_0_tail=%p)\n", __func__, ctx->area_0_head, ptr); + /* this covers the following cases: + * - this is the first KV insertion in the area, which is special as both area head/tail pointers need setting. + * - realloc() has move the area in memory */ + ctx->area_0_head = ptr; + ctx->area_0_tail = ctx->area_0_head + area_size; + } + + /* check realloc() hasnt move area in memory from cfstore_ctx_g.area_0_head*/ + CFSTORE_TP(CFSTORE_TP_CREATE, "%s:cfstore_ctx_g.area_0_head=%p, ptr=%p\n", __func__, ctx->area_0_head, ptr); + + /* determine if should adopt a default behavior for acl permission setting */ + if(cfstore_acl_is_default(kdesc->acl)){ + /* set as read-write by default default */ + CFSTORE_TP(CFSTORE_TP_CREATE, "%s:Note: No ACL bits set. Adopting default permissions of owner read and write.\n", __func__); + b_acl_default = true; + } + /* set the header up, then copy key_name into header */ + memset(ctx->area_0_tail, 0, kv_size); + hdr = (cfstore_area_header_t*) ctx->area_0_tail; + hdr->klength = (uint8_t) strlen(key_name); + hdr->vlength = value_len; + hdr->perm_owner_read = b_acl_default ? true : kdesc->acl.perm_owner_read; + hdr->perm_owner_write = b_acl_default ? true : kdesc->acl.perm_owner_write; + hdr->perm_owner_execute = kdesc->acl.perm_owner_execute; + hdr->perm_other_read = kdesc->acl.perm_other_read; + hdr->perm_other_write = kdesc->acl.perm_other_write; + hdr->perm_other_execute = kdesc->acl.perm_other_execute; + strncpy((char*)hdr + sizeof(cfstore_area_header_t), key_name, strlen(key_name)); + /* Updating the area_0_tail pointer reveals the inserted KV to other operations. See [NOTE1] for details.*/ + ctx->area_0_tail = ctx->area_0_head + area_size + kv_size; + hkvt = cfstore_get_hkvt_from_head_ptr((uint8_t*) hdr); + if(cfstore_flags_is_default(kdesc->flags)){ + /* set as read-only by default default */ + flags.read = true; + flags.write = true; + } else { + flags.read = kdesc->flags.read; + flags.write = kdesc->flags.write; + } + cfstore_file_create(&hkvt, flags, hkey, &ctx->file_list); + ctx->area_dirty_flag = true; + ret = ARM_DRIVER_OK; +out1: + cfstore_hkvt_dump(&hkvt, __func__); +out0: + cfstore_dump_contents(__func__); + /* Create() always completes synchronously irrespective of flash mode, so indicate to caller */ + cfstore_client_notify_data_init(¬ify_data, CFSTORE_OPCODE_CREATE, ret, hkey); + cfstore_ctx_client_notify(ctx, ¬ify_data); + return ret; +} + + +/* @brief See definition in configuration_store.h for description. */ +static int32_t cfstore_open(const char* key_name, ARM_CFSTORE_FMODE flags, ARM_CFSTORE_HANDLE hkey) +{ + int32_t ret = ARM_DRIVER_ERROR; + cfstore_area_hkvt_t hkvt; + cfstore_file_t *file = NULL; + cfstore_ctx_t* ctx = cfstore_ctx_get(); + cfstore_client_notify_data_t notify_data; + + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + cfstore_flags_dump(flags, __func__); + CFSTORE_ASSERT(key_name != NULL); + CFSTORE_ASSERT(hkey != NULL); + if(!cfstore_ctx_is_initialised(ctx)) { + CFSTORE_ERRLOG("%s:Error: CFSTORE is not initialised.\n", __func__); + ret = ARM_CFSTORE_DRIVER_ERROR_UNINITIALISED; + goto out1; + } + ret = cfstore_validate_key_name(key_name); + if(ret < ARM_DRIVER_OK){ + CFSTORE_ERRLOG("%s:Error: invalid key_name.\n", __func__); + goto out1; + } + ret = cfstore_validate_fmode_flags(flags); + if(ret < ARM_DRIVER_OK){ + CFSTORE_ERRLOG("%s:Error: invalid flags.\n", __func__); + goto out1; + } + if(flags.write){ + /* opening a pre-existing key for writing can result in the sram area being changed, which + * cannot happen while a flashJournal_xxx() async completion notification is outstanding */ + if(cfstore_flash_journal_is_async_op_pending(ctx)) { + CFSTORE_TP(CFSTORE_TP_OPEN, "%s:Debug: flash journal operation pending (awaiting asynchronous notification).\n", __func__); + ret = ARM_CFSTORE_DRIVER_ERROR_OPERATION_PENDING; + goto out1; + } + } + ret = cfstore_validate_handle(hkey); + if(ret < ARM_DRIVER_OK){ + CFSTORE_ERRLOG("%s:Error: invalid handle.\n", __func__); + goto out1; + } + /* find the KV and return a handle */ + cfstore_hkvt_init(&hkvt); + ret = cfstore_find_ex(key_name, NULL, &hkvt); + if(ret < ARM_DRIVER_OK){ + /* either no more entries or error but either way, return */ + CFSTORE_TP(CFSTORE_TP_OPEN, "%s:debug: find failed or no more kvs.\n", __func__); + goto out1; + } + if(!cfstore_hkvt_is_valid(&hkvt, ctx->area_0_tail)) + { + CFSTORE_ERRLOG("%s:Error: Could not find pre-existing key to open with key_name=(%s).\n", __func__, key_name); + ret = ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND; + goto out1; + } + /* if this KV is deleting then do not allow item to be opened */ + if(cfstore_hkvt_get_flags_delete(&hkvt)){ + CFSTORE_ERRLOG("%s:Error: Pre-existing key key_name=(%s) is deleting.\n", __func__, key_name); + ret = ARM_CFSTORE_DRIVER_ERROR_PREEXISTING_KEY_DELETING; + goto out1; + } + /* key found, check permissions */ + if(cfstore_flags_is_default(flags)){ + /* set as read-only by default default */ + flags.read = true; + } + if(flags.read == true && !cfstore_is_kv_client_readable(&hkvt)){ + CFSTORE_ERRLOG("%s:Error: Client has no read access to KV (key_name=%s).\n", __func__, key_name); + ret = ARM_CFSTORE_DRIVER_ERROR_PERM_NO_READ_ACCESS; + goto out1; + } + if(flags.write == true && !cfstore_is_kv_client_writable(&hkvt)){ + CFSTORE_ERRLOG("%s:Error: Client has no write access to KV (key_name=%s).\n", __func__, key_name); + ret = ARM_CFSTORE_DRIVER_ERROR_PERM_NO_WRITE_ACCESS; + goto out1; + } + if(flags.execute == true && !cfstore_is_kv_client_executable(&hkvt)){ + CFSTORE_ERRLOG("%s:Error: Client has no execute access to KV (key_name=%s).\n", __func__, key_name); + ret = ARM_CFSTORE_DRIVER_ERROR_PERM_NO_EXECUTE_ACCESS; + goto out1; + } + /* return handle to client */ + file = cfstore_file_create(&hkvt, flags, hkey, &ctx->file_list); + if(file) { + cfstore_file_dump(file, __func__); + } else { + CFSTORE_ERRLOG("%s:Error: failed to create file (key_name=%s).\n", __func__, key_name); + } +out1: + /* Open() always completes synchronously irrespective of flash mode, so indicate to caller */ + cfstore_client_notify_data_init(¬ify_data, CFSTORE_OPCODE_OPEN, ret, hkey); + cfstore_ctx_client_notify(ctx, ¬ify_data); + return ret; +} + + +/* @brief See definition in configuration_store.h for description. */ +static int32_t cfstore_close(ARM_CFSTORE_HANDLE hkey) +{ + int32_t ret = ARM_DRIVER_ERROR; + cfstore_ctx_t* ctx = cfstore_ctx_get(); + cfstore_client_notify_data_t notify_data; + cfstore_area_hkvt_t hkvt; + + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + if(!cfstore_ctx_is_initialised(ctx)) { + CFSTORE_ERRLOG("%s:Error: CFSTORE is not initialised.\n", __func__); + ret = ARM_CFSTORE_DRIVER_ERROR_UNINITIALISED; + goto out0; + } + /* closing a key can lead to its deletion, which cannot happening while there are pending + * async operations outstanding */ + if(cfstore_flash_journal_is_async_op_pending(ctx)) { + CFSTORE_TP(CFSTORE_TP_CLOSE, "%s:Debug: flash journal operation pending (awaiting asynchronous notification).\n", __func__); + ret = ARM_CFSTORE_DRIVER_ERROR_OPERATION_PENDING; + goto out0; + } + ret = cfstore_validate_handle(hkey); + if(ret < ARM_DRIVER_OK){ + CFSTORE_ERRLOG("%s:Error: invalid hkey argument.\n", __func__); + goto out0; + } + /* check the hkey is valid */ + hkvt = cfstore_get_hkvt(hkey); + if(!cfstore_hkvt_is_valid(&hkvt, ctx->area_0_tail)){ + CFSTORE_ERRLOG("%s:ARM_CFSTORE_DRIVER_ERROR_INVALID_HANDLE\n", __func__); + ret = ARM_CFSTORE_DRIVER_ERROR_INVALID_HANDLE; + goto out0; + } + if(!cfstore_is_kv_client_closable((cfstore_file_t*) hkey)){ + CFSTORE_ERRLOG("%s:Error: client is not permitted to close KV.\n", __func__); + ret = ARM_CFSTORE_DRIVER_ERROR_NO_PERMISSIONS; + goto out0; + } + /* delete the file associated with this open handle */ + CFSTORE_TP(CFSTORE_TP_CLOSE, "%s:about to call cfstore_file_destroy().\n", __func__); + cfstore_file_dump((cfstore_file_t*) hkey, __func__); + ret = cfstore_file_destroy(cfstore_file_get(hkey)); +out0: + /* Close() always completes synchronously irrespective of flash mode, so indicate to caller */ + cfstore_client_notify_data_init(¬ify_data, CFSTORE_OPCODE_CLOSE, ret, NULL); + cfstore_ctx_client_notify(ctx, ¬ify_data); + return ret; +} + + +/* @brief See definition in configuration_store.h for description. */ +static int32_t cfstore_read(ARM_CFSTORE_HANDLE hkey, void* data, ARM_CFSTORE_SIZE* len) +{ + int32_t ret = ARM_DRIVER_ERROR; + ARM_CFSTORE_SIZE read_len = 0; + cfstore_area_hkvt_t hkvt; + cfstore_ctx_t* ctx = cfstore_ctx_get(); + cfstore_file_t* file = cfstore_file_get(hkey); + cfstore_client_notify_data_t notify_data; + + CFSTORE_ASSERT(data); + CFSTORE_ASSERT(len); + CFSTORE_FENTRYLOG("%s:entered, hkey=%p\n", __func__, hkey); + if(!cfstore_ctx_is_initialised(ctx)) { + CFSTORE_ERRLOG("%s:Error: CFSTORE is not initialised.\n", __func__); + ret = ARM_CFSTORE_DRIVER_ERROR_UNINITIALISED; + goto out0; + } + /* reading KVs doesnt change the sram area so this can happen independently of + * an oustanding async operation. its unnecessary to check the fsm state */ + ret = cfstore_validate_handle(hkey); + if(ret < ARM_DRIVER_OK){ + CFSTORE_ERRLOG("%s:Error: invalid handle.\n", __func__); + goto out0; + } + if(data == NULL){ + CFSTORE_ERRLOG("%s:Error: invalid read data buffer.\n", __func__); + ret = ARM_CFSTORE_DRIVER_ERROR_INVALID_READ_BUFFER; + goto out0; + } + ret = cfstore_validate_len_ptr(len); + if(ret < ARM_DRIVER_OK){ + CFSTORE_ERRLOG("%s:Error: invalid len argument.\n", __func__); + goto out0; + } + cfstore_hkvt_init(&hkvt); + hkvt = cfstore_get_hkvt(hkey); + /* check the hkey is valid */ + if(!cfstore_hkvt_is_valid(&hkvt, ctx->area_0_tail)){ + CFSTORE_ERRLOG("%s:ARM_CFSTORE_DRIVER_ERROR_INVALID_HANDLE\n", __func__); + ret = ARM_CFSTORE_DRIVER_ERROR_INVALID_HANDLE; + goto out0; + } + + if(!cfstore_is_kv_client_readable(&hkvt)){ + CFSTORE_ERRLOG("%s:Error: client does not have permission to read KV.\n", __func__); + ret = ARM_CFSTORE_DRIVER_ERROR_PERM_NO_READ_ACCESS; + goto out0; + } + read_len = *len <= (cfstore_hkvt_get_value_len(&hkvt) - file->rlocation) ? *len : cfstore_hkvt_get_value_len(&hkvt) - file->rlocation; + memcpy(data, hkvt.value + file->rlocation, read_len); + file->rlocation += read_len; + *len = read_len; + ret = read_len; +out0: + /* Read() always completes synchronously irrespective of flash mode, so indicate to caller */ + cfstore_client_notify_data_init(¬ify_data, CFSTORE_OPCODE_READ, ret, hkey); + cfstore_ctx_client_notify(ctx, ¬ify_data); + return ret; +} + + +/* @brief See definition in configuration_store.h for description. */ +static int32_t cfstore_write(ARM_CFSTORE_HANDLE hkey, const char* data, ARM_CFSTORE_SIZE* len) +{ + int32_t ret = ARM_DRIVER_ERROR; + ARM_CFSTORE_SIZE value_len = 0; + cfstore_area_hkvt_t hkvt; + cfstore_file_t* file = cfstore_file_get(hkey); + cfstore_ctx_t* ctx = cfstore_ctx_get(); + cfstore_client_notify_data_t notify_data; + + CFSTORE_FENTRYLOG("%s:entered, hkey=%p\n", __func__, hkey); + CFSTORE_ASSERT(hkey != NULL); + CFSTORE_ASSERT(len != NULL); + if(!cfstore_ctx_is_initialised(ctx)) { + CFSTORE_ERRLOG("%s:Error: CFSTORE is not initialised.\n", __func__); + ret = ARM_CFSTORE_DRIVER_ERROR_UNINITIALISED; + goto out0; + } + /* writing a key cannot happen while a flashJournal_xxx() async operation is pending */ + if(cfstore_flash_journal_is_async_op_pending(ctx)) { + CFSTORE_TP(CFSTORE_TP_WRITE, "%s:Debug: flash journal operation pending (awaiting asynchronous notification).\n", __func__); + ret = ARM_CFSTORE_DRIVER_ERROR_OPERATION_PENDING; + goto out0; + } + ret = cfstore_validate_handle(hkey); + if(ret < ARM_DRIVER_OK){ + CFSTORE_ERRLOG("%s:Error: invalid handle.\n", __func__); + goto out0; + } + if(data == NULL){ + CFSTORE_ERRLOG("%s:Error: invalid write data buffer.\n", __func__); + ret = ARM_CFSTORE_DRIVER_ERROR_INVALID_WRITE_BUFFER; + goto out0; + } + ret = cfstore_validate_len_ptr(len); + if(ret < ARM_DRIVER_OK){ + CFSTORE_ERRLOG("%s:Error: invalid len argument.\n", __func__); + goto out0; + } + ret = cfstore_validate_value_len(*len); + if (ret < ARM_DRIVER_OK) { + CFSTORE_ERRLOG("%s:Error: invalid key_name.\n", __func__); + goto out0; + } + /*check file has write permission set */ + if(!file->flags.write){ + CFSTORE_ERRLOG("%s:Error: KV is read-only.\n", __func__); + ret = ARM_CFSTORE_DRIVER_ERROR_KEY_READ_ONLY; + goto out0; + } + memset(&hkvt, 0, sizeof(hkvt)); + hkvt = cfstore_get_hkvt(hkey); + if(!cfstore_hkvt_is_valid(&hkvt, ctx->area_0_tail)){ + CFSTORE_ERRLOG("%s:Error: ARM_CFSTORE_DRIVER_ERROR_INVALID_HANDLE.\n", __func__); + ret = ARM_CFSTORE_DRIVER_ERROR_INVALID_HANDLE; + goto out0; + } + if(!cfstore_is_kv_client_writable(&hkvt)){ + CFSTORE_ERRLOG("%s:Error: client does not have permission to write KV.\n", __func__); + ret = ARM_CFSTORE_DRIVER_ERROR_PERM_NO_WRITE_ACCESS; + goto out0; + } + value_len = (ARM_CFSTORE_SIZE) cfstore_hkvt_get_value_len(&hkvt); + *len = *len < value_len ? *len: value_len; + memcpy(hkvt.value + file->wlocation, data, *len); + file->wlocation += *len; + cfstore_hkvt_dump(&hkvt, __func__); + ctx->area_dirty_flag = true; + ret = *len; +out0: + /* Write() always completes synchronously irrespective of flash mode, so indicate to caller */ + cfstore_client_notify_data_init(¬ify_data, CFSTORE_OPCODE_WRITE, ret, hkey); + cfstore_ctx_client_notify(ctx, ¬ify_data); + return ret; +} + + +/* @brief See definition in configuration_store.h for description. */ +static int32_t cfstore_rseek(ARM_CFSTORE_HANDLE hkey, ARM_CFSTORE_OFFSET offset) +{ + int32_t ret = ARM_DRIVER_ERROR; + cfstore_area_hkvt_t hkvt; + cfstore_file_t* file = cfstore_file_get(hkey); + cfstore_ctx_t* ctx = cfstore_ctx_get(); + cfstore_client_notify_data_t notify_data; + + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + if(!cfstore_ctx_is_initialised(ctx)) { + CFSTORE_ERRLOG("%s:Error: CFSTORE is not initialised.\n", __func__); + return ARM_CFSTORE_DRIVER_ERROR_UNINITIALISED; + } + /* read-seeking KVs doesnt change the sram area so this can happen independently of + * an oustanding async operation. its unnecessary to check the fsm state */ + ret = cfstore_validate_handle(hkey); + if(ret < ARM_DRIVER_OK){ + CFSTORE_ERRLOG("%s:Error: invalid handle.\n", __func__); + return ret; + } + ret = cfstore_validate_value_len(offset); + if(ret < ARM_DRIVER_OK){ + CFSTORE_ERRLOG("%s:Error: offset (%u) greater than maximum value blob size (%u).\n", __func__, (unsigned int) offset, CFSTORE_VALUE_SIZE_MAX); + return ret; + } + if(!file->flags.read){ + CFSTORE_ERRLOG("%s:Error: KV is not readable.\n", __func__); + ret = ARM_CFSTORE_DRIVER_ERROR_KEY_UNREADABLE; + goto out0; + + } + cfstore_hkvt_init(&hkvt); + hkvt = cfstore_get_hkvt(hkey); + if(!cfstore_hkvt_is_valid(&hkvt, ctx->area_0_tail)){ + CFSTORE_ERRLOG("%s:Error: ARM_CFSTORE_DRIVER_ERROR_INVALID_HANDLE.\n", __func__); + ret = ARM_CFSTORE_DRIVER_ERROR_INVALID_HANDLE; + goto out0; + } + if(!cfstore_is_kv_client_readable(&hkvt)){ + CFSTORE_ERRLOG("%s:Error: client does not have permission to read KV.\n", __func__); + ret = ARM_CFSTORE_DRIVER_ERROR_PERM_NO_READ_ACCESS; + goto out0; + } + /* check offset is in range */ + if(offset > cfstore_hkvt_get_value_len(&hkvt)){ + CFSTORE_ERRLOG("%s:Error: seeking beyond end of value.\n", __func__); + ret = ARM_CFSTORE_DRIVER_ERROR_INVALID_SEEK; + goto out0; + + } + file->rlocation = offset; + ret = (int32_t) offset; +out0: + /* Rseek() always completes synchronously irrespective of flash mode, so indicate to caller */ + cfstore_client_notify_data_init(¬ify_data, CFSTORE_OPCODE_RSEEK, ret, hkey); + cfstore_ctx_client_notify(ctx, ¬ify_data); + return ret; +} + + +/* @brief See definition in configuration_store.h for description. */ +static int32_t cfstore_flush(void) +{ + int32_t ret = ARM_DRIVER_ERROR; + cfstore_ctx_t* ctx = cfstore_ctx_get(); + + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + if(!cfstore_ctx_is_initialised(ctx)) { + CFSTORE_ERRLOG("%s:Error: CFSTORE is not initialised.\n", __func__); + ret = ARM_CFSTORE_DRIVER_ERROR_UNINITIALISED; + goto out0; + } + /* only 1 flush operation can be outstanding so check whether one is already in progress */ + if(cfstore_flash_journal_is_async_op_pending(ctx)) { + CFSTORE_TP(CFSTORE_TP_FLUSH, "%s:Debug: flash journal operation pending (awaiting asynchronous notification).\n", __func__); + return ARM_CFSTORE_DRIVER_ERROR_OPERATION_PENDING; + } + ret = cfstore_flash_flush(ctx); + if(ret < ARM_DRIVER_OK) { + CFSTORE_ERRLOG("%s:Error: cfstore_flash_flush() returned error (ret=%" PRId32 ").\n", __func__, ret); + goto out0; + } +out0: + return ret; +} + +/* @brief See definition in configuration_store.h for description. */ +static int32_t cfstore_initialise(ARM_CFSTORE_CALLBACK callback, void* client_context) +{ + int ret = ARM_DRIVER_ERROR; + cfstore_ctx_t* ctx = cfstore_ctx_get(); +#if defined CFSTORE_CONFIG_BACKEND_FLASH_ENABLED && CFSTORE_CONFIG_BACKEND_FLASH_ENABLED == 1 + ARM_STORAGE_CAPABILITIES storage_caps; +#endif /* CFSTORE_CONFIG_BACKEND_FLASH_ENABLED */ + + CFSTORE_FENTRYLOG("%s:entered: callback=%p, client_context=%p, ref_count=%d\n", __func__, callback, client_context, (int) ctx->init_ref_count); + /* init cfstore context the first time this method is called + * note ctx->rw_area0_lock has already been initialised */ + + /* CS protection required to get into the fsm into the initing state, without another client g*/ + cfstore_critical_section_lock(&ctx->rw_area0_lock, __func__); + if(ctx->init_ref_count == 0) + { + CFSTORE_TP(CFSTORE_TP_INIT, "%s:debug: first time init\n", __func__); + /* perform first time initialisation */ + ctx->init_ref_count++; + /* initially there is no memory allocated for the area */ + CFSTORE_INIT_LIST_HEAD(&ctx->file_list); + cfstore_critical_section_init(&ctx->rw_area0_lock); + ctx->area_0_head = NULL; + ctx->area_0_tail = NULL; + + CFSTORE_ASSERT(sizeof(cfstore_file_t) == CFSTORE_HANDLE_BUFSIZE); + if(sizeof(cfstore_file_t) != CFSTORE_HANDLE_BUFSIZE){ + CFSTORE_ERRLOG("%s:Error: sizeof(cfstore_file_t)=(%d) != CFSTORE_HANDLE_BUFSIZE (%d)\n", __func__,(int) sizeof(cfstore_file_t), (int) CFSTORE_HANDLE_BUFSIZE); + ret = ARM_CFSTORE_DRIVER_ERROR_INTERNAL; + goto out0; + } + ctx->client_callback = callback; + ctx->client_context = client_context; + ctx->area_dirty_flag = false; + ctx->client_callback_notify_flag = false; + + cfstore_client_notify_data_init(&ctx->client_notify_data, CFSTORE_OPCODE_MAX, ARM_DRIVER_ERROR, NULL); + ctx->power_state = ARM_POWER_FULL; + ctx->status = ARM_DRIVER_OK; + +#if defined CFSTORE_CONFIG_BACKEND_FLASH_ENABLED && CFSTORE_CONFIG_BACKEND_FLASH_ENABLED == 1 + // todo: put in cfstore_flash_init() ? + /* set the cfstore async flag according to the storage driver mode */ + storage_caps = cfstore_storage_drv->GetCapabilities(); + cfstore_caps_g.asynchronous_ops = storage_caps.asynchronous_ops; +#endif /* CFSTORE_CONFIG_BACKEND_FLASH_ENABLED */ + + ret = cfstore_flash_init(); + if(ret < ARM_DRIVER_OK) { + CFSTORE_ERRLOG("%s:Error: failed to initialise flash layer\n", __func__); + goto out0; + } + } + else + { + CFSTORE_TP(CFSTORE_TP_INIT, "%s:debug: n-th time init\n", __func__); + /* initialisation already done so only increment the ref count */ + ctx->init_ref_count++; + ret = ARM_DRIVER_OK; + } + /* if not initialised already, fsm now in the initing state so safe to come out of CS */ + cfstore_critical_section_unlock(&ctx->rw_area0_lock, __func__); +out0: + CFSTORE_FENTRYLOG("%s:exiting: callback=%p, client_context=%p, ref_count=%d\n", __func__, callback, client_context, (int) ctx->init_ref_count); + return ret; +} + + +/* @brief See prototype definition in configuration_store.h for function description. + * + * @note unitialising cfstore results in all entries that have not been flushed being lost + */ +static int32_t cfstore_uninitialise(void) +{ + int32_t ret = ARM_DRIVER_ERROR; + ARM_STORAGE_CAPABILITIES caps; + cfstore_ctx_t* ctx = cfstore_ctx_get(); + + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + memset(&caps, 0, sizeof(caps)); + + if(!cfstore_ctx_is_initialised(ctx)) { + CFSTORE_ERRLOG("%s:Error: CFSTORE is not initialised.\n", __func__); + ret = ARM_CFSTORE_DRIVER_ERROR_UNINITIALISED; + goto out; + } + /* only uninitialise when there are no flash journal async operations pending*/ + if(cfstore_flash_journal_is_async_op_pending(ctx)) { + CFSTORE_TP(CFSTORE_TP_INIT, "%s:Debug: flash journal operation pending (awaiting asynchronous notification).\n", __func__); + ret = ARM_CFSTORE_DRIVER_ERROR_OPERATION_PENDING; + goto out; + } + if(ctx->init_ref_count > 0) { + ctx->init_ref_count--; + CFSTORE_TP(CFSTORE_TP_INIT, "%s:Debug: decemented init_ref_count (%" PRId32 ").\n", __func__, ctx->init_ref_count); + } + if(ctx->init_ref_count == 0) + { + CFSTORE_TP(CFSTORE_TP_INIT, "%s:Debug: init_ref_count == 0 (%" PRId32 ") so uninitialising.\n", __func__, ctx->init_ref_count); + /* check file list is empty and if not, free the items */ + if(ctx->file_list.next != ctx->file_list.prev) + { + /* list is not empty. walk the list and free the entries */ + // todo: wip: free items on the file list + } + + ret = cfstore_flash_deinit(); + if(ret < ARM_DRIVER_OK){ + CFSTORE_ERRLOG("%s:Error: failed to uninitialise flash journal layer.\n", __func__); + goto out; + } + if(ctx->area_0_head){ + CFSTORE_FREE(ctx->area_0_head); + ctx->area_0_head = NULL; + ctx->area_0_tail = NULL; + } + } +out: + /* notify client */ + cfstore_client_notify_data_init(&ctx->client_notify_data, CFSTORE_OPCODE_UNINITIALIZE, ret, NULL); + cfstore_ctx_client_notify(ctx, &ctx->client_notify_data); + return ret; +} + + +/* @brief See definition in configuration_store.h for description. */ +static int32_t cfstore_power_control(ARM_POWER_STATE state) +{ + int32_t ret = ARM_DRIVER_ERROR; + cfstore_ctx_t* ctx = cfstore_ctx_get(); + cfstore_client_notify_data_t notify_data; + + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + if(!cfstore_ctx_is_initialised(ctx)) { + CFSTORE_ERRLOG("%s:Error: CFSTORE is not initialised.\n", __func__); + ret = ARM_CFSTORE_DRIVER_ERROR_UNINITIALISED; + goto out0; + } + /* setting power state doesnt change the sram area so this can happen independently of + * an oustanding async operation. its unnecessary to check the fsm state */ + if(state <= ARM_POWER_FULL){ + ctx->power_state = state; + /* set return to a positive value*/ + ret = (int32_t) state; + } +out0: + /* PowerControl() always completes synchronously irrespective of flash mode, so indicate to caller */ + cfstore_client_notify_data_init(¬ify_data, CFSTORE_OPCODE_POWER_CONTROL, ret, NULL); + cfstore_ctx_client_notify(ctx, ¬ify_data); + return ret; +} + + +#ifdef YOTTA_CFG_CFSTORE_UVISOR + +/* + * uvisor secure gateways for ARM_CFSTORE_DRIVER access methods. + */ + +UVISOR_EXTERN int32_t __cfstore_uvisor_close(ARM_CFSTORE_HANDLE hkey) +{ + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + return cfstore_close(hkey); +} + +static int32_t cfstore_uvisor_close(ARM_CFSTORE_HANDLE hkey) +{ + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + return secure_gateway(configuration_store, __cfstore_uvisor_close, hkey); +} + +UVISOR_EXTERN int32_t __cfstore_uvisor_create(const char* key_name, ARM_CFSTORE_SIZE value_len, const ARM_CFSTORE_KEYDESC* kdesc, ARM_CFSTORE_HANDLE hkey) +{ + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + return cfstore_create(key_name, value_len, kdesc, hkey); +} + +static int32_t cfstore_uvisor_create(const char* key_name, ARM_CFSTORE_SIZE value_len, const ARM_CFSTORE_KEYDESC* kdesc, ARM_CFSTORE_HANDLE hkey) +{ + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + return secure_gateway(configuration_store, __cfstore_uvisor_create, key_name, value_len, kdesc, hkey); +} + +UVISOR_EXTERN int32_t __cfstore_uvisor_delete(ARM_CFSTORE_HANDLE hkey) +{ + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + return cfstore_delete(hkey); +} + +static int32_t cfstore_uvisor_delete(ARM_CFSTORE_HANDLE hkey) +{ + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + return secure_gateway(configuration_store, __cfstore_uvisor_delete, hkey); +} + +UVISOR_EXTERN int32_t __cfstore_uvisor_find(const char* key_name_query, const ARM_CFSTORE_HANDLE previous, ARM_CFSTORE_HANDLE next) +{ + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + return cfstore_find(key_name_query, previous, next); +} + +static int32_t cfstore_uvisor_find(const char* key_name_query, const ARM_CFSTORE_HANDLE previous, ARM_CFSTORE_HANDLE next) +{ + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + return secure_gateway(configuration_store, __cfstore_uvisor_find, key_name_query, previous, next); +} + +UVISOR_EXTERN int32_t __cfstore_uvisor_flush(int dummy) +{ + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + (void) dummy; + return cfstore_flush(); +} + +static int32_t cfstore_uvisor_flush(void) +{ + int dummy = 0; + + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + return secure_gateway(configuration_store, __cfstore_uvisor_flush, dummy); +} + +UVISOR_EXTERN int32_t __cfstore_uvisor_get_key_name(ARM_CFSTORE_HANDLE hkey, char* key_name, uint8_t *key_name_len) +{ + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + return cfstore_get_key_name(hkey, key_name, key_name_len); +} + +static int32_t cfstore_uvisor_get_key_name(ARM_CFSTORE_HANDLE hkey, char* key_name, uint8_t *key_name_len) +{ + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + return secure_gateway(configuration_store, __cfstore_uvisor_get_key_name, hkey, key_name, key_name_len); +} + +UVISOR_EXTERN int32_t __cfstore_uvisor_get_value_len(ARM_CFSTORE_HANDLE hkey, ARM_CFSTORE_SIZE *value_len) +{ + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + return cfstore_get_value_len(hkey, value_len); +} + +static int32_t cfstore_uvisor_get_value_len(ARM_CFSTORE_HANDLE hkey, ARM_CFSTORE_SIZE *value_len) +{ + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + return secure_gateway(configuration_store, __cfstore_uvisor_get_value_len, hkey, value_len); +} + +UVISOR_EXTERN int32_t __cfstore_uvisor_initialize(ARM_CFSTORE_CALLBACK callback, void* client_context) +{ + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + return cfstore_initialise(callback, client_context); +} + +static int32_t cfstore_uvisor_initialise(ARM_CFSTORE_CALLBACK callback, void* client_context) +{ + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + return secure_gateway(configuration_store, __cfstore_uvisor_initialize, callback, client_context); +} + +/* type to convert between ARM_CFSTORE_FMODE and uint32 for passing flags through secure gw */ +typedef union cfstore_fmode_flags_t +{ + ARM_CFSTORE_FMODE flags; + uint32_t val; +} cfstore_fmode_flags_t; + +UVISOR_EXTERN int32_t __cfstore_uvisor_open(const char* key_name, uint32_t flags, ARM_CFSTORE_HANDLE hkey) +{ + cfstore_fmode_flags_t uflags; + + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + uflags.val = flags; + return cfstore_open(key_name, uflags.flags, hkey); +} + +static int32_t cfstore_uvisor_open(const char* key_name, ARM_CFSTORE_FMODE flags, ARM_CFSTORE_HANDLE hkey) +{ + cfstore_fmode_flags_t uflags; + + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + uflags.flags = flags; + return secure_gateway(configuration_store, __cfstore_uvisor_open, key_name, uflags.val, hkey); +} + +UVISOR_EXTERN int32_t __cfstore_uvisor_read(ARM_CFSTORE_HANDLE hkey, void* data, ARM_CFSTORE_SIZE* len) +{ + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + return cfstore_read(hkey, data, len); +} + +static int32_t cfstore_uvisor_read(ARM_CFSTORE_HANDLE hkey, void* data, ARM_CFSTORE_SIZE* len) +{ + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + return secure_gateway(configuration_store, __cfstore_uvisor_read, hkey, data, len); +} + +UVISOR_EXTERN int32_t __cfstore_uvisor_rseek(ARM_CFSTORE_HANDLE hkey, ARM_CFSTORE_OFFSET offset) +{ + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + return cfstore_rseek(hkey, offset); +} + +static int32_t cfstore_uvisor_rseek(ARM_CFSTORE_HANDLE hkey, ARM_CFSTORE_OFFSET offset) +{ + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + return secure_gateway(configuration_store, __cfstore_uvisor_rseek, hkey, offset); +} + +UVISOR_EXTERN int32_t __cfstore_uvisor_uninitialise(int dummy) +{ + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + (void) dummy; + return cfstore_uninitialise(); +} + +static int32_t cfstore_uvisor_uninitialize(void) +{ + int dummy = 0; + + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + return secure_gateway(configuration_store, __cfstore_uvisor_uninitialise, dummy); +} + +UVISOR_EXTERN int32_t __cfstore_uvisor_write(ARM_CFSTORE_HANDLE hkey, const char* data, ARM_CFSTORE_SIZE* len) +{ + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + return cfstore_write(hkey, data, len); +} + +static int32_t cfstore_uvisor_write(ARM_CFSTORE_HANDLE hkey, const char* data, ARM_CFSTORE_SIZE* len) +{ + CFSTORE_FENTRYLOG("%s:entered\n", __func__); + return secure_gateway(configuration_store, __cfstore_uvisor_write, hkey, data, len); +} + + +ARM_CFSTORE_DRIVER cfstore_driver = +{ + .Close = cfstore_uvisor_close, + .Create = cfstore_uvisor_create, + .Delete= cfstore_uvisor_delete, + .Find = cfstore_uvisor_find, + .Flush = cfstore_uvisor_flush, + .GetCapabilities = cfstore_get_capabilities, + .GetKeyName = cfstore_uvisor_get_key_name, + .GetStatus = cfstore_get_status, + .GetValueLen = cfstore_uvisor_get_value_len, + .GetVersion = cfstore_get_version, + .Initialize = cfstore_uvisor_initialise, + .Open = cfstore_uvisor_open, + .PowerControl = cfstore_power_control, + .Read = cfstore_uvisor_read, + .Rseek = cfstore_uvisor_rseek, + .Uninitialize = cfstore_uvisor_uninitialize, + .Write = cfstore_uvisor_write, +}; + +#else + +/* non-uvisor interface */ +ARM_CFSTORE_DRIVER cfstore_driver = +{ + .Close = cfstore_close, + .Create = cfstore_create, + .Delete= cfstore_delete, + .Find = cfstore_find, + .Flush = cfstore_flush, + .GetCapabilities = cfstore_get_capabilities, + .GetKeyName = cfstore_get_key_name, + .GetStatus = cfstore_get_status, + .GetValueLen = cfstore_get_value_len, + .GetVersion = cfstore_get_version, + .Initialize = cfstore_initialise, + .Open = cfstore_open, + .PowerControl = cfstore_power_control, + .Read = cfstore_read, + .Rseek = cfstore_rseek, + .Uninitialize = cfstore_uninitialise, + .Write = cfstore_write, +}; + +#endif /* YOTTA_CFG_CFSTORE_UVISOR */ diff --git a/storage/cfstore/tatmanjants.txt b/storage/cfstore/tatmanjants.txt new file mode 100644 index 0000000000..192bae13d5 --- /dev/null +++ b/storage/cfstore/tatmanjants.txt @@ -0,0 +1,30 @@ +/* In order to support ARM toolchain and simplify the number of newlib posix files used, + * this have been copied from collate.c, and the license for this code has been included at the + * here: + * + * Copyright (c) 1995 Alex Tatmanjants + * at Electronni Visti IA, Kiev, Ukraine. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ \ No newline at end of file From 34f3c5da356e0fe3bc01fe480d92d3b05c9fb22f Mon Sep 17 00:00:00 2001 From: Simon D Hughes Date: Wed, 8 Jun 2016 16:28:02 +0100 Subject: [PATCH 2/2] Fix warnings to remove unused variables --- storage/cfstore/source/cfstore_fnmatch.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/storage/cfstore/source/cfstore_fnmatch.c b/storage/cfstore/source/cfstore_fnmatch.c index bc3bf9689c..8ef6ae085f 100644 --- a/storage/cfstore/source/cfstore_fnmatch.c +++ b/storage/cfstore/source/cfstore_fnmatch.c @@ -131,9 +131,6 @@ int __collate_range_cmp (c1, c2) { static char s1[2], s2[2]; int ret; -#ifndef ASCII_COMPATIBLE_COLLATE - int as1, as2, al1, al2; -#endif c1 &= UCHAR_MAX; c2 &= UCHAR_MAX;