takashi kadono / Mbed OS Nucleo_446

Dependencies:   ssd1331

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers configuration_store.c Source File

configuration_store.c

Go to the documentation of this file.
00001 /** @file configuration_store.c
00002  *
00003  * mbed Microcontroller Library
00004  * Copyright (c) 2006-2016 ARM Limited
00005  *
00006  * Licensed under the Apache License, Version 2.0 (the "License");
00007  * you may not use this file except in compliance with the License.
00008  * You may obtain a copy of the License at
00009  *
00010  *     http://www.apache.org/licenses/LICENSE-2.0
00011  *
00012  * Unless required by applicable law or agreed to in writing, software
00013  * distributed under the License is distributed on an "AS IS" BASIS,
00014  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00015  * See the License for the specific language governing permissions and
00016  * limitations under the License.
00017  */
00018 
00019 // This file is deprecated so deprecation warnings when building it are silenced
00020 #if   defined ( __CC_ARM )
00021 #pragma diag_suppress 1361  // Deprecated declaration
00022 #elif defined ( __GNUC__ )
00023 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
00024 #endif
00025 
00026 #include "cfstore_config.h"
00027 #include "cfstore_debug.h"
00028 #include "cfstore_list.h"
00029 #include "cfstore_fnmatch.h"
00030 #include "configuration_store.h"
00031 
00032 #if defined CFSTORE_CONFIG_MBED_OS_VERSION && CFSTORE_CONFIG_MBED_OS_VERSION == 3
00033 #include <core-util/critical.h>
00034 #endif /* CFSTORE_CONFIG_MBED_OS_VERSION == 3 */
00035 
00036 #ifdef CFSTORE_CONFIG_BACKEND_FLASH_ENABLED
00037 #include "cfstore_svm.h"
00038 #include "flash_journal_strategy_sequential.h"
00039 #include "flash_journal.h"
00040 #include "Driver_Common.h"
00041 #endif /* CFSTORE_CONFIG_BACKEND_FLASH_ENABLED */
00042 
00043 #include <stdio.h>
00044 #include <stdlib.h>
00045 #include <string.h>
00046 #include <assert.h>
00047 #include <inttypes.h>
00048 
00049 
00050 #ifdef CFSTORE_DEBUG
00051 uint32_t cfstore_optDebug_g = 1;
00052 uint32_t cfstore_optLogLevel_g = CFSTORE_LOG_NONE; /*CFSTORE_LOG_NONE|CFSTORE_LOG_ERR|CFSTORE_LOG_DEBUG|CFSTORE_LOG_FENTRY */
00053 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; */
00054 #endif
00055 
00056 
00057 /*
00058  * Externs
00059  */
00060 #ifdef CFSTORE_CONFIG_BACKEND_FLASH_ENABLED
00061 extern ARM_DRIVER_STORAGE ARM_Driver_Storage_MTD_K64F;
00062 ARM_DRIVER_STORAGE *cfstore_storage_drv = &ARM_Driver_Storage_MTD_K64F;
00063 #endif /* CFSTORE_CONFIG_BACKEND_FLASH_ENABLED */
00064 
00065 struct _ARM_DRIVER_STORAGE cfstore_journal_mtd;
00066 
00067 /*
00068  * Defines
00069  *
00070  * CFSTORE_FLASH_STACK_BUF_SIZE
00071  *  when performing flush, if the program_unit <= CFSTORE_FLASH_STACK_BUF_SIZE octets then a
00072  *  stack buffer is used to perform the tail write. Otherwise a buffer is malloced
00073  *
00074  * CFSTORE_FLASH_AREA_SIZE_MIN
00075  *  valid sizes of areas should always be greater than the size of the header, and therefore
00076  *  greater than this value, which is defined as smaller than the header size
00077  *
00078  * CFSTORE_FLASH_NUMSLOTS
00079  *  number of flash journal slots
00080  *
00081  * ARM_DRIVER_OK_DONE
00082  *   value that indicates an operation has been done i.e. a value > 0
00083  */
00084 #define CFSTORE_KEY_NAME_CHARS_ACCEPTABLE           "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ{}.-_@"
00085 #define CFSTORE_KEY_NAME_QUERY_CHARS_ACCEPTABLE     CFSTORE_KEY_NAME_CHARS_ACCEPTABLE"*"
00086 #define CFSTORE_HKVT_REFCOUNT_MAX                   0xff
00087 #define CFSTORE_LOCK_REFCOUNT_MAX                   0xffff
00088 #define CFSTORE_FILE_CREATE_MODE_DEFAULT            (ARM_CFSTORE_FMODE)0
00089 #define CFSTORE_FLASH_STACK_BUF_SIZE                64
00090 #define CFSTORE_FLASH_AREA_SIZE_MIN                 (sizeof(cfstore_area_header_t) - 1)
00091 #define CFSTORE_FLASH_NUMSLOTS                      4
00092 #define cfstore_fsm_null                            NULL
00093 #define CFSTORE_SENTINEL                            0x7fffffff
00094 #define CFSTORE_CALLBACK_RET_CODE_DEFAULT           0x1
00095 #define ARM_DRIVER_OK_DONE                          1
00096 
00097 /*
00098  * Simple Types
00099  */
00100 #define CFSTORE_LOCK uint32_t
00101 
00102 
00103 /*
00104  * Structures
00105  */
00106 
00107 /** @brief
00108  *
00109  * @param   key_permissions
00110  *          bottom 6 bits contain the ACLs-bits (owner read/write/execute,
00111  *           other read/write/execute). The remaining bits in this field are
00112  *          used for the Device Data Security Protection Features bit field,
00113  *          bits are low-active
00114  * @param   perm_owner_read
00115  *          if set => this KV is owner readable
00116  * @param   perm_owner_write
00117  *          if set => this KV is owner writable
00118  * @param   perm_owner_execute
00119  *          if set => this KV is owner executable
00120  * @param   perm_other_read
00121  *          if set => this KV is world readable
00122  * @param   perm_other_write
00123  *          if set => this KV is world writable
00124  * @param   perm_other_execute
00125  *          if set => this KV is world executable
00126  * @param   klength
00127  *          key name size including zero-padding
00128  * @param   vlength
00129  *          this value fragment length
00130  * @param   refcount
00131  *          Number of handles open on this hkvt
00132  *
00133  * @param   delete
00134  *          indicates this KV is being deleted
00135  */
00136 typedef struct cfstore_area_header_t 
00137 {
00138     uint32_t vlength;
00139     uint8_t klength;
00140     uint8_t perm_owner_read : 1;
00141     uint8_t perm_owner_write : 1;
00142     uint8_t perm_owner_execute : 1;
00143     uint8_t perm_other_read : 1;
00144     uint8_t perm_other_write : 1;
00145     uint8_t perm_other_execute : 1;
00146     uint8_t reserved : 2;
00147     uint8_t refcount;
00148     struct flags_t {
00149         uint8_t delete : 1;
00150         uint8_t reserved : 7;
00151     } flags ;
00152 } cfstore_area_header_t ;
00153 
00154 
00155 /* helper struct */
00156 typedef struct cfstore_area_hkvt_t
00157 {
00158     uint8_t *head;
00159     uint8_t *key;
00160     uint8_t *value;
00161     uint8_t *tail;
00162 } cfstore_area_hkvt_t;
00163 
00164 
00165 /* helper struct */
00166 typedef struct cfstore_client_notify_data_t
00167 {
00168     uint32_t opcode;
00169     int32_t status;
00170     ARM_CFSTORE_HANDLE  handle;
00171 } cfstore_client_notify_data_t;
00172 
00173 /* @brief  test fsm states and events */
00174 typedef enum cfstore_fsm_state_t {
00175     cfstore_fsm_state_stopped = 0,
00176     cfstore_fsm_state_initing,
00177     cfstore_fsm_state_reading,
00178     cfstore_fsm_state_logging,
00179     cfstore_fsm_state_committing,
00180     cfstore_fsm_state_resetting,
00181     cfstore_fsm_state_ready,        /* ready for next flash journal command to arise */
00182     cfstore_fsm_state_formatting,   /* flash formatting in progress */
00183     cfstore_fsm_state_max
00184 } cfstore_fsm_state_t;
00185 
00186 /* @brief  test fsm events */
00187 typedef enum cfstore_fsm_event_t {
00188     cfstore_fsm_event_init_done = 0,
00189     cfstore_fsm_event_read_done,
00190     cfstore_fsm_event_log_done,
00191     cfstore_fsm_event_commit_req,
00192     cfstore_fsm_event_commit_done,
00193     cfstore_fsm_event_reset_done,
00194     cfstore_fsm_event_format_done,
00195     cfstore_fsm_event_max,
00196 } cfstore_fsm_event_t;
00197 
00198 typedef int32_t (*cfstore_fsm_handler)(void* ctx);
00199 
00200 /* @brief   flash finite state machine helper function */
00201 typedef struct cfstore_fsm_t
00202 {
00203     cfstore_fsm_state_t state;
00204     cfstore_fsm_event_t event;
00205 } cfstore_fsm_t;
00206 
00207 
00208 #ifdef CFSTORE_DEBUG
00209 #ifdef CFSTORE_CONFIG_BACKEND_FLASH_ENABLED
00210 /* strings used for debug trace */
00211 static const char* cfstore_flash_opcode_str[] =
00212 {
00213     "FLASH_JOURNAL_OPCODE_FORMAT",
00214     "FLASH_JOURNAL_OPCODE_INITIALIZE",
00215     "FLASH_JOURNAL_OPCODE_GET_INFO",
00216     "FLASH_JOURNAL_OPCODE_READ_BLOB",
00217     "FLASH_JOURNAL_OPCODE_LOG_BLOB",
00218     "FLASH_JOURNAL_OPCODE_COMMIT",
00219     "FLASH_JOURNAL_OPCODE_RESET",
00220 };
00221 
00222 static const char* cfstore_flash_state_str[] =
00223 {
00224     "stopped",
00225     "initializing",
00226     "reading",
00227     "logging",
00228     "committing",
00229     "resetting",
00230     "ready",
00231     "formatting",
00232     "unknown"
00233 };
00234 
00235 static const char* cfstore_flash_event_str[] =
00236 {
00237     "init_done",
00238     "read_done",
00239     "log_done",
00240     "commit_req",
00241     "commit_done",
00242     "reset_done",
00243     "format_done",
00244     "unknown"
00245 };
00246 #endif /* CFSTORE_CONFIG_BACKEND_FLASH_ENABLED */
00247 #endif /* CFSTORE_DEBUG */
00248 
00249 
00250 /*
00251  * Forward decl
00252  */
00253 #ifdef CFSTORE_CONFIG_BACKEND_FLASH_ENABLED
00254 static int32_t cfstore_fsm_state_handle_event(cfstore_fsm_t* fsm, cfstore_fsm_event_t event, void* context);
00255 static int32_t cfstore_fsm_state_set(cfstore_fsm_t* fsm, cfstore_fsm_state_t new_state, void* ctx);
00256 #endif  /* CFSTORE_CONFIG_BACKEND_FLASH_ENABLED */
00257 static int32_t cfstore_get_key_name_ex(cfstore_area_hkvt_t *hkvt, char* key_name, uint8_t *key_name_len);
00258 
00259 
00260 /* Walking Area HKVT's While Inserting   a New HKVT:
00261  * Implementation Note 1 [NOTE1]
00262  *
00263  * The implementation must address the following problem:
00264  * - client1 may be creating a new KV into area_0, which means inserting the
00265  *   header-key-value-tail data into area_0.
00266  * - concurrently, client2 (through a call to Find()) is walking KVs in area_0,
00267  *   and the walk has to be safe against the insertion of the new KV.
00268  *
00269  * This problem is addressed in the by using the cfstore_ctx_g.rw_lock to police
00270  * access to the area when making changes.
00271  * - Walking the KVs in area_0 is performed using the header structures,
00272  *   which contain key and value lengths required to find the start of the
00273  *   next hkvt. These must not change under the client.
00274  * - The Find() walk is terminated when the hkvt header pointer is found to
00275  *   point to cfstore_ctx_g.area_0_tail i.e. when this arises then the
00276  *   iterator knows its come to the end of the hkvt's in the area.
00277  *
00278  * Memory Management (todo: future support)
00279  * Implementation Note 2 [NOTE2]
00280  * CFSTORE supports using a client provisioned SRAM slab rather than using realloc() to allocated heap
00281  * memory. This has the following advantages:
00282  * - the client is in control of the memory allocation.
00283  * - realloc() cannot fail (e.g. due to memory leaks losing memory) as the sram has been preprovisioned.
00284  *   This makes the system more resilient.
00285  * The client specifes the sram slab in the following way:
00286  * - having target.json defined yotta_config.h symbol for CFSTORE_SRAM_START_ADDR, CFSTORE_SRAM_SIZE
00287  *   and #ifdef on these values to use that memory area for area_0 rather than using malloc.
00288  * - for the case where a client tries to create a KV which causes area_0 to exceed CFSTORE_SRAM_SIZE
00289  *   then the operation is failed.
00290  * - modify the API so that the client is responsible for allocating the memory the the CFSTORE internal
00291  *   data structures, with the size of the internal data structure exposed through a #define.
00292  *   The contents of the buffer are opaque to the client. The reasons for this are as follows:
00293  *   - to allow the cfstore implementation not to use malloc().
00294  *   - the memory allocation policy for allocating the memory of CFSTORE internal data structures
00295  *     can be decided and implemented by the client
00296  *   - for clients written in C++, its possible to have a static class with the memory for the
00297  *     internal context, and the static class memory area is given to CFSTORE for use, so it
00298  *     provides good C++ support.
00299  *   - The SRAM area can be allocated with the previous point, and the handle associated data
00300  *     structures i.e. cfstore_file_t, can be covered by the supplied buffers to those functions
00301  *     creating handles.
00302  * - currently neither target.json nor config.json allow a symbol in yotta_config.h to be defined
00303  *   for the current case of CFSTORE being a yotta module/library.
00304  *
00305  * UVISOR Integration (todo)
00306  * Implementation Note 3 [NOTE3]
00307  * Outstanding Questions:
00308  * - uvisor_ctx. Should all functions use this to access the global data context?
00309  *   - see cfstore_ctx_get() for an implementation
00310  *   - compile in cfstore_ctx_g only when not using uvisor
00311  * - how do you allocate heap memory objects with uvisor protections?
00312  *   - doesnt seem to be an api for this yet.
00313  *   - will be required for sram storage of KVs i.e. "the area".
00314  *   - will be required for file objects
00315  * - Q: is it safe to store the caller_box_id in the cfstore_file_t?
00316  *   A: no, because the cfstore_file_t is held in client controlled memory (opaque hkey)
00317  *      so the client can modify from under cfstore, breaching security if it was used
00318  *      by other cfstore methods.
00319  * - method for securing access:
00320  *   - create()/open() checks namespace etc, and then creates/opens cfstore_file_t
00321  *     and returns hkey (opaque cfstore_file_t) for subsequent use by api calls.
00322  *   - read/write/rseek etc check the kv pathname accessible via cfstore_file_t::head
00323  *     is within the callers namespace.
00324  *   - we are trusting the caller to be secure and not be malicious?
00325  *  - put "uvisor-lib" : "^2.0.0" in module.json. not necessary as mbed-drivers has this dep.
00326  *  - flash-journal change from using NVIC_Set/GetVector() to VIRQ_Set/GetVector()
00327  *
00328  */
00329 
00330 /*
00331  * @brief   CS global context that maintains state
00332  *
00333  * @param   area_0_start
00334  *          pointer to start of malloc-ed memory block for containing area_0
00335  *
00336  * @param   area_0_head
00337  *          pointer to area_0 header struct within the memblock.
00338  *          - ((cfstore_area_header_t*) area_0)->refcount is the number of
00339  *            open handles in the whole of area_0.
00340  *          - accessed in app & intr context; hence needs CS protection.
00341  *
00342  * @param   area_0_tail
00343  *          pointer to address in the sram after the last byte of the last
00344  *          KV. Note there can be padding after the area_0_tail to align the
00345  *          sram area with flash program_unit (or 1 if SRAM only version)
00346  *          to facilitate reading/writing to flash.
00347  *          - accessed in app & intr context; hence needs CS protection.
00348  *
00349  * @param   area_0_len
00350  *          length of the area used for storing KVs, including padding to
00351  *          round to nearest program unit
00352  *
00353  * @param   rw_area0_lock
00354  *          lock used to make CS re-entrant e.g. only 1 flush operation can be
00355  *          performed at a time while no readers/writers have handles open
00356  *          to KVs. The lock is to protect access to the following:
00357  *          - cfstore_ctx_g.area_0_head/cfstore_ctx_g.area_0_tail. Realloc()
00358  *            in Delete() and Create() can cause these pointers to change.
00359  *
00360  * @param   client_notify_data
00361  *          fsm handler functions set a flag for a client notification call
00362  *          to be made after fsm handler functions have been completed. This
00363  *          block holds the client notification status data for the callback.
00364  *
00365  * @param   area_dirty_flag
00366  *          flag indicating that the area has been written and therefore is
00367  *          dirty with respect to the data persisted to flash.
00368  *
00369  * @expected_blob_size  expected_blob_size = area_0_tail - area_0_head + pad
00370  *          In the case of reading from flash into sram, this will be be size
00371  *          of the flash blob (rounded to a multiple program_unit if not
00372  *          already so).
00373  *          In the case of writing to flash, this the size of all the KV's
00374  *          plus padding so the sram blob size is a multiple of flash
00375  *          program_unit.
00376  *          - accessed in app & intr context; hence needs CS protection.
00377  */
00378 typedef struct cfstore_ctx_t
00379 {
00380     cfstore_list_node_t file_list;
00381     int32_t init_ref_count;
00382     CFSTORE_LOCK rw_area0_lock;
00383     ARM_POWER_STATE power_state;
00384     uint8_t *area_0_head;
00385     uint8_t *area_0_tail;
00386     size_t area_0_len;
00387     cfstore_fsm_t fsm;
00388     int32_t status;
00389 
00390     /* client notification data */
00391     void* client_context;
00392     ARM_CFSTORE_CALLBACK client_callback;
00393     cfstore_client_notify_data_t client_notify_data;
00394 
00395     /* flags */
00396     uint32_t client_callback_notify_flag : 1;
00397     uint32_t area_dirty_flag : 1;
00398     uint32_t f_reserved0 : 30;
00399 
00400 #ifdef CFSTORE_CONFIG_BACKEND_FLASH_ENABLED
00401     /* flash journal related data */
00402     FlashJournal_t jrnl;
00403     FlashJournal_Info_t info;
00404     FlashJournal_OpCode_t cmd_code;
00405     uint64_t expected_blob_size;
00406 #endif /* CFSTORE_CONFIG_BACKEND_FLASH_ENABLED */
00407 } cfstore_ctx_t;
00408 
00409 
00410 /*
00411  * @brief   file structure for KV, one per open file handle.
00412  *
00413  * @param   head
00414  *          pointer to head of KV
00415  *
00416  * @param   rlocation
00417  *          read location of rseek to move
00418  *
00419  * @param   read
00420  *          indicates file is readable,
00421  * @param   writable
00422  *          indicates file is readable,
00423  * @param   executable
00424  *          indicates file is readable,
00425  * @param   uvisor_client_box_id
00426  *          box id of caller using this file. set on create/open and thereafter used by other methods to check accesses.
00427  *          Q: is it safe to store this here? Is it of any value? i.e. a client can change the value
00428  *          after cfstore has set it so cfstore cant rely on it being secure.
00429  */
00430 typedef struct cfstore_file_t
00431 {
00432     cfstore_list_node_t node;
00433     uint32_t rlocation;
00434     uint32_t wlocation;
00435     uint8_t *head;
00436     ARM_CFSTORE_FMODE flags;
00437 } cfstore_file_t;
00438 
00439 /* @brief   structure used to compose table for mapping flash journal error codes to cfstore error codes */
00440 typedef struct cfstore_flash_journal_error_code_node
00441 {
00442     int32_t flash_journal_error_code;
00443     int32_t cfstore_error_code;
00444 } cfstore_flash_journal_error_code_node;
00445 
00446 
00447 /*
00448  * Globals
00449  */
00450 #ifndef CFSTORE_STORAGE_DRIVER_CONFIG_HARDWARE_MTD_ASYNC_OPS
00451 static ARM_CFSTORE_CAPABILITIES cfstore_caps_g = { .asynchronous_ops = 1 };
00452 #else
00453 static ARM_CFSTORE_CAPABILITIES cfstore_caps_g = { .asynchronous_ops = CFSTORE_STORAGE_DRIVER_CONFIG_HARDWARE_MTD_ASYNC_OPS };
00454 #endif /* CFSTORE_STORAGE_DRIVER_CONFIG_HARDWARE_MTD_ASYNC_OPS */
00455 
00456 static const ARM_DRIVER_VERSION cfstore_driver_version_g = { .api = ARM_CFSTORE_API_VERSION, .drv = ARM_CFSTORE_DRV_VERSION };
00457 
00458 static cfstore_ctx_t cfstore_ctx_g = {
00459         .file_list.next = NULL,
00460         .file_list.prev = NULL,
00461         .init_ref_count = 0,
00462         .rw_area0_lock = 0,
00463         .power_state = ARM_POWER_FULL,
00464         .area_0_head = NULL,
00465         .area_0_tail = NULL,
00466         .client_callback = NULL,
00467         .client_context = NULL,
00468         .f_reserved0 = 0,
00469 };
00470 
00471 /*
00472  * client notifier helper function
00473  */
00474 static void cfstore_client_notify_data_init(cfstore_client_notify_data_t* data, uint32_t opcode, int32_t status, ARM_CFSTORE_HANDLE  handle)
00475 {
00476     memset(data, 0, sizeof(cfstore_client_notify_data_t));
00477     data->opcode = opcode;
00478     data->status = status;
00479     data->handle = handle;
00480 }
00481 
00482 /*
00483  * cfstore_ctx_t methods
00484  */
00485 
00486 /* @brief   helper function to report whether the initialisation flag has been set in the cfstore_ctx_g */
00487 static bool cfstore_ctx_is_initialised(cfstore_ctx_t* ctx)
00488 {
00489     CFSTORE_ASSERT(ctx!= NULL);
00490     return ctx->init_ref_count > 0 ? true : false;
00491 }
00492 
00493 /* @brief   helper function to return a pointer to the global cfstore context. */
00494 static inline cfstore_ctx_t* cfstore_ctx_get(void)
00495 {
00496     return &cfstore_ctx_g;
00497 }
00498 
00499 /** @brief   helper function to compute the total size of the KVs stored in the
00500  *           sram area in bytes.
00501  *
00502  * Note:
00503  *  - sram_area_size =  cfstore_ctx_get_kv_total_len() + padding
00504  *  - padding rounds up cfstore_ctx_get_kv_total_len() to
00505  *    be a multiple of flash program_unit size.
00506  */
00507 static ARM_CFSTORE_SIZE cfstore_ctx_get_kv_total_len(void)
00508 {
00509     ARM_CFSTORE_SIZE size = 0;
00510     cfstore_ctx_t* ctx = cfstore_ctx_get();
00511 
00512     size = (ARM_CFSTORE_SIZE) (ctx->area_0_tail - ctx->area_0_head);
00513     return size;
00514 }
00515 
00516 /* @brief   helper function to get the program_unit */
00517 static inline uint32_t cfstore_ctx_get_program_unit(cfstore_ctx_t* ctx)
00518 {
00519     CFSTORE_ASSERT(ctx!= NULL);
00520 #ifdef CFSTORE_CONFIG_BACKEND_FLASH_ENABLED
00521     return ctx->info.program_unit;
00522 #else
00523     /* the program unit is 1 so byte aligned when no flash backend present */
00524     (void) ctx;
00525     return 1;
00526 #endif /* CFSTORE_CONFIG_BACKEND_FLASH_ENABLED */
00527 
00528 }
00529 
00530 static inline void cfstore_ctx_client_notify(cfstore_ctx_t* ctx, cfstore_client_notify_data_t* data)
00531 {
00532     CFSTORE_FENTRYLOG("%s:entered: ctx=%p, ctx->client_callback=%p, ctx->client_context=%p\n", __func__, ctx, ctx->client_callback, ctx->client_context);
00533     CFSTORE_TP(CFSTORE_TP_CALLBACK, "%s:data=%p, data->opcode=%d, data->status=%d, data->handle=%p\n", __func__, data, (int) data->opcode, (int) data->status, data->handle);
00534     if(ctx->client_callback){
00535         ctx->client_callback(data->status, (ARM_CFSTORE_OPCODE) data->opcode, ctx->client_context, data->handle);
00536     }
00537     return;
00538 }
00539 
00540 /*
00541  * CFSTORE_YOTTA_CFG_CFSTORE_SRAM_ADDR
00542  *  client can supply a SRAM slab address and size for
00543  *  CFSTORE internal use. This is a default addr
00544  *  for development use. Should be defined by client
00545  * CFSTORE_YOTTA_CFG_CFSTORE_SRAM_SIZE
00546  *  size of sram area. Should be define by client
00547  */
00548 #ifndef CFSTORE_YOTTA_CFG_CFSTORE_SRAM_ADDR
00549 /* if the client doesnt provide a memory slab then CFSTORE uses realloc internally*/
00550 
00551 #ifndef CFSTORE_DEBUG
00552 #define CFSTORE_FREE        free
00553 #define CFSTORE_MALLOC      malloc
00554 #define CFSTORE_REALLOC     realloc
00555 #else
00556 
00557 static uint32_t cfstore_malloc_size_g = 0;
00558 #define CFSTORE_MALLOC      malloc
00559 
00560 static void* CFSTORE_REALLOC(void *ptr, size_t size)
00561 {
00562     void* mem;
00563 
00564     mem = realloc(ptr, size);
00565     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);
00566     cfstore_malloc_size_g = size;
00567     return mem;
00568 }
00569 
00570 static void CFSTORE_FREE(void *ptr)
00571 {
00572     free(ptr);
00573     CFSTORE_TP(CFSTORE_TP_MEM, "%s:ptr=%p, old_size=%u, new_size=%u.\n", __func__, ptr, (int) cfstore_malloc_size_g, 0);
00574     cfstore_malloc_size_g = 0;
00575     return;
00576 }
00577 #endif /* CFSTORE_DEBUG */
00578 
00579 /* memory tracking */
00580 
00581 #else
00582 #define CFSTORE_FREE        CFSTORE_ASSERT(0)
00583 #define CFSTORE_MALLOC      CFSTORE_ASSERT(0)
00584 #define CFSTORE_REALLOC     cfstore_realloc
00585 
00586 
00587 
00588 /* function to realloc from a client provided memory slab
00589  * size = new size of area used by sram
00590  * ptr is always head of slab
00591  *
00592  * The cfstore_realloc() function changes the size of the memory
00593  * block pointed to by ptr to size bytes, backed by the client
00594  * provided memory slab. The contents will be unchanged in the
00595  * range from the start of the region up to the minimum of the
00596  * old and new sizes. If the new size is larger than the old size,
00597  * the added memory will not be initialized.
00598  *
00599  * ptr
00600  * ptr should be set to null on the first call to this function and
00601  * for size > 0 && size <= CFSTORE_YOTTA_CFG_CFSTORE_SRAM_SIZE
00602  * CFSTORE_YOTTA_CFG_CFSTORE_SRAM_ADDR will be returned.
00603  * On subsequent calls, ptr must have been returned by an earlier
00604  * call to this function.
00605  *
00606  * size
00607  * if size is equal to zero, and ptr is not NULL, then the call is
00608  * equivalent to reseting the memory area and NULL will be returned.
00609  */
00610 void *cfstore_realloc(void *ptr, ARM_CFSTORE_SIZE size)
00611 {
00612     static uint8_t *cfstore_sram_head = NULL;
00613     static uint8_t *cfstore_sram_tail = NULL;
00614 
00615     if(size > 0) {
00616         if(size <= CFSTORE_YOTTA_CFG_CFSTORE_SRAM_SIZE) {
00617             if(ptr == NULL) {
00618                 memset(CFSTORE_YOTTA_CFG_CFSTORE_SRAM_ADDR, 0, CFSTORE_YOTTA_CFG_CFSTORE_SRAM_SIZE);
00619                 cfstore_sram_head = CFSTORE_YOTTA_CFG_CFSTORE_SRAM_ADDR;
00620             }
00621             cfstore_sram_tail = cfstore_sram_head + size;
00622             return (void*) cfstore_sram_head;
00623         }
00624         /* requested size is too big so fail the operation by setting
00625          * head/tail to NULL */
00626     }
00627     /* size == 0 => reset */
00628     cfstore_sram_head = NULL;
00629     cfstore_sram_tail = NULL;
00630     return (void*) cfstore_sram_head;
00631 }
00632 
00633 #endif /* CFSTORE_YOTTA_CFG_CFSTORE_SRAM_ADDR */
00634 
00635 
00636 #ifdef CFSTORE_TARGET_LIKE_X86_LINUX_NATIVE
00637 static inline void cfstore_critical_section_lock(CFSTORE_LOCK* lock, const char* tag){ (void) tag; __sync_fetch_and_add(lock, 1); }
00638 static inline void cfstore_critical_section_unlock(CFSTORE_LOCK* lock, const char* tag){(void) tag;  __sync_fetch_and_sub(lock, 1); }
00639 
00640 static CFSTORE_INLINE int32_t cfstore_hkvt_refcount_dec(cfstore_area_hkvt_t* hkvt, uint8_t *refcount)
00641 {
00642     cfstore_area_header_t  *hdr = (cfstore_area_header_t *) hkvt->head;
00643     uint32_t __refcount;
00644 
00645     __refcount =__sync_fetch_and_sub(&hdr->refcount, 1);
00646     if(refcount) *refcount = __refcount;
00647     return ARM_DRIVER_OK;
00648 }
00649 
00650 static CFSTORE_INLINE int32_t cfstore_hkvt_refcount_inc(cfstore_area_hkvt_t* hkvt, uint8_t *refcount)
00651 {
00652     int32_t ret = ARM_CFSTORE_DRIVER_ERROR_HANDLE_COUNT_MAX;
00653     uint32_t __refcount;
00654     cfstore_area_header_t  *hdr = (cfstore_area_header_t *) hkvt->head;
00655 
00656     if( (__refcount = __sync_fetch_and_add(&hdr->refcount, 1)) < CFSTORE_LOCK_REFCOUNT_MAX) {
00657         if(refcount) *refcount = __refcount;
00658         ret = ARM_DRIVER_OK;
00659     } else {
00660         /* maximum count reach, back down and return error*/
00661         __sync_fetch_and_sub(&hdr->refcount, 1);
00662     }
00663     return ret;
00664 }
00665 
00666 
00667 #else
00668 
00669 /*
00670  * Platform Specific Function Implementations
00671  */
00672 
00673 static inline void cfstore_critical_section_unlock(CFSTORE_LOCK* lock, const char* tag)
00674 {
00675     (void) lock;
00676     (void) tag;
00677     CFSTORE_DBGLOG("%s:before critical_section_exit()(lock=%lu)\n", tag, *lock);
00678     (*lock)--;
00679     /* todo: put mbedosv3++ critical section exit here */
00680     CFSTORE_DBGLOG("%s:after critical_section_exit()(lock=%lu)\n", tag, *lock);
00681 }
00682 
00683 static inline void cfstore_critical_section_lock(CFSTORE_LOCK* lock, const char* tag)
00684 {
00685     (void) lock;
00686     (void) tag;
00687     CFSTORE_DBGLOG("%s:before critical_section_enter()(lock=%lu)\n", tag, *lock);
00688     /* todo: put mbedosv3++ critical section enter here */
00689     (*lock)++;
00690     CFSTORE_DBGLOG("%s:after critical_section_enter()(lock=%lu)\n", tag, *lock);
00691 }
00692 
00693 static CFSTORE_INLINE int32_t cfstore_hkvt_refcount_dec(cfstore_area_hkvt_t* hkvt, uint8_t *refcount)
00694 {
00695     cfstore_area_header_t  *hdr = (cfstore_area_header_t *) hkvt->head;
00696 
00697     /* todo: put mbedosv3++ critical section enter here */
00698     hdr->refcount--;
00699     if(refcount) *refcount = hdr->refcount;
00700     /* todo: put mbedosv3++ critical section exit here */
00701     return ARM_DRIVER_OK;
00702 }
00703 
00704 static CFSTORE_INLINE int32_t cfstore_hkvt_refcount_inc(cfstore_area_hkvt_t* hkvt, uint8_t *refcount)
00705 {
00706     int32_t ret = ARM_CFSTORE_DRIVER_ERROR_HANDLE_COUNT_MAX;
00707     cfstore_area_header_t  *hdr = (cfstore_area_header_t *) hkvt->head;
00708 
00709     /* todo: put mbedosv3++ critical section enter here */
00710     if(hdr->refcount < CFSTORE_HKVT_REFCOUNT_MAX)
00711     {
00712         hdr->refcount++;
00713         if(refcount) *refcount = hdr->refcount;
00714         ret = ARM_DRIVER_OK;
00715     }
00716     /* todo: put mbedosv3++ critical section exit here */
00717     return ret;
00718 }
00719 
00720 #endif /* CFSTORE_TARGET_LIKE_X86_LINUX_NATIVE */
00721 
00722 
00723 /*
00724  * security/permissions helper functions
00725  */
00726 
00727 /**
00728  * @brief   check that the cfstore client (caller, which is a uvisor box)
00729  *          is only trying to access its own namespace.
00730  *
00731  * @note    This function is the cfstore equivalent of "is_calling_box_allowed"
00732  */
00733 static int32_t cfstore_uvisor_security_context_prefix_check(const char* key_name)
00734 {
00735     /*todo: implement : A client uvisor security context should exist with
00736      *      a security_prefix_name that matches the first part of the
00737      *      key_name. Make sure this is the case. */
00738 
00739     // if the caller is the main box then deny access, as only secure uvisor boxes
00740     // are permitted to access cfstore.
00741 
00742     // get box_id of caller
00743     // get namespace of caller
00744     // if the keyname is in the namespace then permit, otherwise deny
00745 
00746     (void) key_name;
00747     return ARM_DRIVER_OK;
00748 }
00749 
00750 /* @brief   check that a client (cfstore-uvisor client box) is the "owner" of the
00751  *          KV (wrapper). see cfstore_uvisor_is_client_kv_owner() for more details.
00752  */
00753 static int32_t cfstore_is_client_kv_owner(const char* key_name, int32_t* cfstore_uvisor_box_id)
00754 {
00755     CFSTORE_FENTRYLOG("%s:entered\n", __func__);
00756     (void) key_name;
00757     (void) cfstore_uvisor_box_id;
00758     return ARM_DRIVER_OK;
00759 }
00760 
00761 /* @brief   helper function to determine whether this client can close a given KV */
00762 static bool cfstore_is_kv_client_closable(cfstore_file_t* file)
00763 {
00764     /* todo: integrate with uvisor to get boxId (security prefix name)
00765      * - check the kv key_name prefix matches the security context to determine whether client is
00766      *   allowed to close the given key_name.
00767      */
00768     /* until can implement this functionality, assume client can close KV */
00769     (void) file;
00770     return true;
00771 }
00772 
00773 /* @brief   helper function to determine whether this client can delete a given KV */
00774 static bool cfstore_is_kv_client_deletable(cfstore_file_t* file)
00775 {
00776     /* todo: integrate with uvisor to get boxId (security prefix name)
00777      * - check the kv key_name prefix matches the security context to determine whether client is
00778      *   allowed to delete the given key_name.
00779      */
00780     /* until can implement this functionality, assume client can delete KV */
00781     (void) file;
00782     return true;
00783 }
00784 
00785 /* @brief   helper function to determine whether this client can read a given KV */
00786 static bool cfstore_is_kv_client_readable(cfstore_area_hkvt_t* hkvt)
00787 {
00788     /* todo: integrate with uvisor to get boxId (security prefix name)
00789      * - check the kv key_name prefix matches the security context to determine whether client is
00790      *   owner or other.
00791      * - if(owner)
00792      *   {
00793      *      // client is owner of kv
00794      *      if( ((cfstore_area_header_t*)(hkvt->head))->perm_owner_read == true) {
00795      *          return true;
00796      *      }
00797      *   } else {
00798      *      // client is other
00799      *      if( ((cfstore_area_header_t*)(hkvt->head))->perm_other_read == true) {
00800      *          return true;
00801      *   }
00802      *   return false;
00803      */
00804     /* until can implement this functionality, assume client has read access to KV */
00805     (void) hkvt;
00806     return true;
00807 }
00808 
00809 /* @brief   helper function to determine whether this client can write a given KV */
00810 static bool cfstore_is_kv_client_writable(cfstore_area_hkvt_t* hkvt)
00811 {
00812     cfstore_area_header_t  *hdr = (cfstore_area_header_t *) hkvt->head;
00813 
00814     /* todo: integrate with uvisor to get boxId (security prefix name)
00815      * - check the kv key_name prefix matches the security context to determine whether client is
00816      *   owner or other.
00817      * - if(owner)
00818      *   {
00819      *      // client is owner of kv
00820      *      if( ((cfstore_area_header_t*)(hkvt->head))->perm_owner_write == true) {
00821      *          return true;
00822      *      }
00823      *   } else {
00824      *      // client is other
00825      *      if( ((cfstore_area_header_t*)(hkvt->head))->perm_other_write == true) {
00826      *          return true;
00827      *   }
00828      *   return false;
00829      */
00830     /* until can implement this functionality, assume client has write access to KV */
00831 
00832     /* check that the owner has write permission */
00833     return hdr->perm_owner_write;
00834 }
00835 
00836 /* @brief   helper function to determine whether this client can execute a given KV */
00837 static bool cfstore_is_kv_client_executable(cfstore_area_hkvt_t* hkvt)
00838 {
00839     /* todo: integrate with uvisor to get boxId (security prefix name)
00840      * - check the kv key_name prefix matches the security context to determine whether client is
00841      *   owner or other.
00842      * - if(owner)
00843      *   {
00844      *      // client is owner of kv
00845      *      if( ((cfstore_area_header_t*)(hkvt->head))->perm_owner_execute == true) {
00846      *          return true;
00847      *      }
00848      *   } else {
00849      *      // client is other
00850      *      if( ((cfstore_area_header_t*)(hkvt->head))->perm_other_execute == true) {
00851      *          return true;
00852      *   }
00853      *   return false;
00854      */
00855     /* until can implement this functionality, assume client has execute access to KV */
00856     (void) hkvt;
00857     return true;
00858 }
00859 
00860 
00861 /*
00862  * flags helper function
00863  */
00864 static bool cfstore_acl_is_default(ARM_CFSTORE_ACCESS_CONTROL_LIST acl)
00865 {
00866     if(     acl.perm_owner_read == false                &&
00867             acl.perm_owner_write == false               &&
00868             acl.perm_owner_execute == false             &&
00869             acl.perm_other_read == false                &&
00870             acl.perm_other_write == false               &&
00871             acl.perm_other_execute == false             )
00872     {
00873         /* flags are set to indicate "adopt some meaningful default behaviour" */
00874         return true;
00875     }
00876     return false;
00877 }
00878 
00879 /*
00880  * flags helper function
00881  */
00882 static bool cfstore_flags_is_default(ARM_CFSTORE_FMODE flags)
00883 {
00884     if( flags.read == 0             &&
00885         flags.write == 0            &&
00886         flags.continuous == 0       &&
00887         flags.flush_on_close == 0   &&
00888         flags.lazy_flush == 0       &&
00889         flags.storage_detect == 0   )
00890     {
00891         /* flags are set to indicate "adopt some meaningful default behaviour" */
00892         return true;
00893     }
00894     return false;
00895 }
00896 
00897 static CFSTORE_INLINE bool cfstore_hkvt_get_flags_delete(cfstore_area_hkvt_t *hkvt)
00898 {
00899     return ((cfstore_area_header_t *) hkvt->head)->flags.delete;
00900 }
00901 
00902 static CFSTORE_INLINE void cfstore_hkvt_set_flags_delete(cfstore_area_hkvt_t *hkvt, bool flag)
00903 {
00904     CFSTORE_ASSERT(hkvt != NULL);
00905     ((cfstore_area_header_t *) hkvt->head)->flags.delete = flag;
00906 }
00907 
00908 
00909 /*
00910  * struct cfstore_area_hkvt_t helper operations
00911  */
00912 static CFSTORE_INLINE uint8_t cfstore_hkvt_get_key_len(cfstore_area_hkvt_t* hkvt)
00913 {
00914     cfstore_area_header_t  *header;
00915     CFSTORE_ASSERT(hkvt != NULL);
00916     header = (cfstore_area_header_t *) hkvt->head;
00917     return header->klength;
00918 }
00919 
00920 static CFSTORE_INLINE uint32_t cfstore_hkvt_get_value_len(cfstore_area_hkvt_t* hkvt)
00921 {
00922     cfstore_area_header_t  *header;
00923     CFSTORE_ASSERT(hkvt != NULL);
00924     header = (cfstore_area_header_t *) hkvt->head;
00925     return header->vlength;
00926 }
00927 
00928 static CFSTORE_INLINE ARM_CFSTORE_SIZE cfstore_hkvt_get_size(cfstore_area_hkvt_t* hkvt)
00929 {
00930     ARM_CFSTORE_SIZE kv_size = 0;
00931 
00932     kv_size += sizeof(cfstore_area_header_t );
00933     kv_size += cfstore_hkvt_get_key_len(hkvt);
00934     kv_size += cfstore_hkvt_get_value_len(hkvt);
00935     return kv_size;
00936 }
00937 
00938 static CFSTORE_INLINE void cfstore_hkvt_init(cfstore_area_hkvt_t* hkvt)
00939 {
00940     memset(hkvt, 0, sizeof(cfstore_area_hkvt_t));
00941 }
00942 
00943 
00944 static CFSTORE_INLINE bool cfstore_hkvt_is_valid(cfstore_area_hkvt_t *hkvt, uint8_t *area_0_tail)
00945 {
00946     if(hkvt->head && hkvt->head != area_0_tail && hkvt->key && hkvt->value && hkvt->tail) {
00947         return true;
00948     }
00949     return false;
00950 }
00951 
00952 static CFSTORE_INLINE uint32_t cfstore_hkvt_set_value_len(cfstore_area_hkvt_t* hkvt, uint32_t value_len)
00953 {
00954     uint32_t vlength;
00955     cfstore_area_header_t  *hdr;
00956     CFSTORE_ASSERT(hkvt != NULL);
00957     hdr = (cfstore_area_header_t *) hkvt->head;
00958     vlength = hdr->vlength;
00959     hdr->vlength = value_len;
00960     return vlength;
00961 }
00962 
00963 /* @brief   helper function to detect if there are any KV's stored in the sram area */
00964 static bool cfstore_area_has_hkvt(void)
00965 {
00966     cfstore_ctx_t* ctx = cfstore_ctx_get();
00967 
00968     /* head and tail pointer equal means there are no KVs stored */
00969     if(ctx->area_0_head == ctx->area_0_tail){
00970         /* there are no KV's stored*/
00971         return false;
00972     }
00973     return true;
00974 }
00975 
00976 
00977 /* @brief   helper function to get the first KV in the sram area */
00978 static cfstore_area_hkvt_t cfstore_get_hkvt_from_head_ptr(uint8_t* head)
00979 {
00980     cfstore_area_hkvt_t hkvt;
00981 
00982     CFSTORE_ASSERT(head != NULL);
00983     memset((void*) &hkvt, 0, sizeof(hkvt));
00984     hkvt.head = head;
00985     hkvt.key = hkvt.head + sizeof(cfstore_area_header_t );
00986     hkvt.value = hkvt.key + ((cfstore_area_header_t *) hkvt.head)->klength;
00987     hkvt.tail = hkvt.value + ((cfstore_area_header_t *) hkvt.head)->vlength;
00988     return hkvt;
00989 }
00990 
00991 
00992 /* @brief   helper function to convert a opaque handle to a struct cfstore_area_hkvt_t */
00993 static cfstore_area_hkvt_t cfstore_get_hkvt(ARM_CFSTORE_HANDLE  hkey)
00994 {
00995     cfstore_file_t* file = (cfstore_file_t*) hkey;
00996     return cfstore_get_hkvt_from_head_ptr((uint8_t*) file->head);
00997 }
00998 
00999 
01000 /* @brief   helper function to convert a opaque handle to a struct cfstore_area_hkvt_t */
01001 static int32_t cfstore_get_head_hkvt(cfstore_area_hkvt_t* hkvt)
01002 {
01003     cfstore_ctx_t* ctx = cfstore_ctx_get();
01004 
01005     CFSTORE_FENTRYLOG("%s:entered\n", __func__);
01006     CFSTORE_ASSERT(hkvt != NULL);
01007     if(!cfstore_area_has_hkvt()){
01008         CFSTORE_TP(CFSTORE_TP_VERBOSE1, "%s:CFSTORE has no KVs\n", __func__);
01009         memset((void*) hkvt, 0, sizeof(cfstore_area_hkvt_t));
01010         return ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND;
01011     }
01012 
01013     CFSTORE_TP(CFSTORE_TP_VERBOSE1, "%s:CFSTORE has KVs\n", __func__);
01014     *hkvt = cfstore_get_hkvt_from_head_ptr(ctx->area_0_head);
01015     return ARM_DRIVER_OK;
01016 }
01017 
01018 
01019 /* @brief   helper function to walk the sram area from the previous hkvt to
01020  *          the next hkvt.
01021  * @param   prev
01022  *          pointer to previous hkvt. If null then the search is started
01023  *          from the beginning of the sram area.
01024  * @param   next
01025  *          pointer to next hkvt for which the pointers need calculating.
01026  */
01027 static int32_t cfstore_get_next_hkvt(cfstore_area_hkvt_t* prev, cfstore_area_hkvt_t* next)
01028 {
01029     cfstore_ctx_t* ctx = cfstore_ctx_get();
01030 
01031     CFSTORE_ASSERT(prev != NULL);
01032     CFSTORE_ASSERT(next != NULL);
01033     CFSTORE_ASSERT(prev->tail <= ctx->area_0_tail);
01034 
01035     if(prev->tail == ctx->area_0_tail){
01036         CFSTORE_TP(CFSTORE_TP_VERBOSE1, "%s:reached the end of the list. return NULL entry\n", __func__);
01037         memset((void*) next, 0, sizeof(cfstore_area_hkvt_t));
01038         return ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND;
01039     }
01040     /* use the prev tail pointer to find the next head pointer */
01041     *next = cfstore_get_hkvt_from_head_ptr((uint8_t*) prev->tail);
01042     return ARM_DRIVER_OK;
01043 }
01044 
01045 
01046 /*
01047  * Flash support functions
01048  */
01049 
01050 static CFSTORE_INLINE void cfstore_hkvt_dump(cfstore_area_hkvt_t* hkvt, const char* tag);
01051 
01052 /** @brief  Set the context tail pointer area_0_tail to point to the end of the
01053  *          last KV in the memory area.
01054  *
01055  * This function walks hkvt entries in the KV area to find the memory
01056  * address after the end of the last KV, and then sets the area tail pointer
01057  * area_0_tail to that address. The function therefore relies on the
01058  * head, key, value, tail fields being correct.
01059  *
01060  * Notes:
01061  * - This function should only be called after the memory area is loaded from
01062  *   flash and the area_0_tail pointer needs setting. The only way to do this
01063  *   (at the present time) is to walk the list of KVs, which is what this function
01064  *   does. The only other place the code sets area_0_tail is cfstore_realloc_ex(),
01065  *   and this state of affairs shouldnt change i.e. its unnecessary for
01066  *   other functions to change area_0_tail.
01067  * - When loading the area_0 image from falsh, cfstore_realloc_ex() is used
01068  *   to allocate the memory with ctx->expected_blob_size as the size. Thus
01069  *   area_0_tail will be initially set to
01070  *     area_0_tail = area_0_head + expected_blob_size       (1)
01071  *   and thereby may include padding used to align the area size to a
01072  *   flash program unit boundary. cfstore_flash_set_tail() is used to
01073  *   set area_0_tail correctly.
01074  */
01075 static int32_t cfstore_flash_set_tail(void)
01076 {
01077     int32_t ret = ARM_DRIVER_ERROR;
01078     uint8_t* ptr = NULL;
01079     cfstore_ctx_t* ctx = cfstore_ctx_get();
01080     uint8_t* tail = NULL;
01081     cfstore_area_hkvt_t hkvt;
01082 
01083     CFSTORE_FENTRYLOG("%s:entered: \n", __func__);
01084     CFSTORE_ASSERT(ctx != NULL);
01085     cfstore_hkvt_init(&hkvt);
01086 
01087     /* Check for cases where the tail pointer is already set correctly
01088      * e.g. where the area is of zero length */
01089     if(cfstore_ctx_get_kv_total_len() == 0) {
01090         /* tail pointer already set correctly */
01091         return ARM_DRIVER_OK;
01092     }
01093     ptr = ctx->area_0_head;
01094     tail = ctx->area_0_tail;
01095     while(ptr <= tail) {
01096         CFSTORE_FENTRYLOG("%s:ptr=%p, tail=%p: \n", __func__, ptr, tail);
01097         hkvt = cfstore_get_hkvt_from_head_ptr(ptr);
01098         if(cfstore_hkvt_is_valid(&hkvt, tail) == false) {
01099             CFSTORE_ERRLOG("%s:Error:found invalid hkvt entry in area\n", __func__);
01100             break;
01101         }
01102         cfstore_hkvt_dump(&hkvt, __func__);
01103         /* when the length between the hkvt.tail and tail
01104          * is less than the minimum KV length then we have found the last KV, and can set the
01105          * area_0_tail correctly to the end of the last KV. This works OK for the present support
01106          * (where flash_program_unit ~ sizeof(cfstore_area_header_t)) but may need
01107          * revisiting where flash_program_unit > sizeof(cfstore_area_header_t) */
01108         if((uint32_t)(tail - hkvt.tail) < sizeof(cfstore_area_header_t )){
01109             /* ptr is last KV in area as there isn't space for another header  */
01110             ctx->area_0_tail = hkvt.tail;
01111             ret = ARM_DRIVER_OK;
01112             break;
01113         }
01114         ptr = hkvt.tail;
01115     }
01116     return ret;
01117 }
01118 
01119 
01120 /** @brief  Function to realloc the SRAM area used to store KVs.
01121  *
01122  * This function consolidates the code needed to:
01123  * - realloc the memory
01124  * - when the start of the SRAM area moves, update data structures
01125  *   which point into SRAM area (e.g. open files cfstore_file_t head pointers).
01126  *
01127  * The function assumes:
01128  * - the cfstore_file_t::head pointers are valid i.e. point to the
01129  *   correct locations in the KV area for each file.
01130  *
01131  * @param   size
01132  * total KV size in bytes storage required. Note this does not include
01133  * padding to round up to the nearest multiple of flash program unit
01134  * as this is computed and added in this function.
01135  *
01136  * @param   allocated_size
01137  * total size in bytes that was allocated (value returned to caller).
01138  * This may be larger than the requested size due to rounding to align with a
01139  * flash program unit boundary.
01140  */
01141 static int32_t cfstore_realloc_ex(ARM_CFSTORE_SIZE size, uint64_t *allocated_size)
01142 {
01143     uint8_t* ptr = NULL;
01144     int32_t ret = ARM_DRIVER_ERROR;
01145     int32_t len_diff = 0;
01146     cfstore_ctx_t* ctx = cfstore_ctx_get();
01147     cfstore_file_t* file;
01148     cfstore_list_node_t* node;
01149     cfstore_list_node_t* file_list = &ctx->file_list;
01150     ARM_CFSTORE_SIZE total_kv_size = size;
01151 
01152     /* Switch on the size of the sram area to create:
01153      * - if size > 0 (but may be shrinking) then use REALLOC.
01154      * - if size == 0 then the area is being deleted so free the memory
01155      * Note:
01156      * - realloc can return NULL when the last KV is deleted
01157      * - It also appears that realloc can return non-zero ptr when size = 0.
01158      *   Hence for this case free() is used.
01159      */
01160     CFSTORE_FENTRYLOG("%s:entered:\n", __func__);
01161     CFSTORE_TP(CFSTORE_TP_MEM, "%s:cfstore_ctx_g.area_0_head=%p, cfstore_ctx_g.area_0_tail=%p, cfstore_ctx_g.area_0_len=%d, size=%d, \n", __func__, ctx->area_0_head, ctx->area_0_tail, (int) ctx->area_0_len, (int) size);
01162 
01163     if(size > 0)
01164     {
01165         /* In the general case (size % program_unit > 0). The new area_0 size is
01166          * aligned to a flash program_unit boundary to facilitate r/w to flash
01167          * and so the memory realloc size is calculated to align, as follows */
01168         if(size % cfstore_ctx_get_program_unit(ctx) > 0){
01169             size += (cfstore_ctx_get_program_unit(ctx) - (size % cfstore_ctx_get_program_unit(ctx)));
01170         }
01171 
01172         ptr = (uint8_t*) CFSTORE_REALLOC((void*) ctx->area_0_head, size);
01173         if (ptr == NULL) {
01174             if (total_kv_size <= ctx->area_0_len) {
01175                 /* Size is shrinking so a realloc failure is recoverable.
01176                  * Update ptr so it matches the previous head.
01177                  */
01178                 ptr = ctx->area_0_head;
01179             }
01180         }
01181         if(ptr == NULL){
01182             CFSTORE_ERRLOG("%s:Error: unable to allocate memory (size=%d)\n", __func__, (int) size);
01183             /* realloc() has failed to allocate the required memory object. If previously
01184              * allocation has been made, the old memory object remains allocated. On error, the client
01185              * is expected to clean up including making a call to Uninitialize() which will free the
01186              * old memory object.
01187              */
01188             return ARM_CFSTORE_DRIVER_ERROR_OUT_OF_MEMORY;
01189         }
01190         /* check realloc() hasn't move area in memory from cfstore_ctx_g.area_0_head */
01191         if(ptr != ctx->area_0_head){
01192             /* realloc() has moved the area in memory */
01193             CFSTORE_TP(CFSTORE_TP_MEM, "%s: realloc() has moved memory area and area_0_head ptr must change. old cfstore_ctx_g.area_0_head=%p, new head ptr=%p)\n", __func__, ctx->area_0_head, ptr);
01194 
01195             /* now have to walk the file list updating head pointers to point into the realloc-ed
01196              * To begin with, leave the relative position of the file pointers unaltered */
01197             node = file_list->next;
01198             while(node != file_list){
01199                 file = (cfstore_file_t*) node;
01200                 file->head = (uint8_t *) (file->head - ctx->area_0_head);
01201                 file->head = (uint8_t *) ((int32_t) file->head + (int32_t) ptr);
01202                 node = node->next;
01203             }
01204             ctx->area_0_head = ptr;
01205         }
01206 
01207         /* If the area is growing then zero the new space at the end of the area */
01208         len_diff = size - (int32_t) ctx->area_0_len;
01209         if(len_diff > 0) {
01210             memset(ptr + ctx->area_0_len, 0, len_diff);
01211         }
01212         /* Set area_0_tail to be the memory address after the end of the last KV in the memory area.
01213          * This is the only place that area_0_tail should be changed, apart from cfstore_flash_set_tail()
01214          * which is only called when attributes are loaded from flash.
01215          */
01216         ctx->area_0_len = size;
01217         ctx->area_0_tail = ptr + total_kv_size;
01218         if(allocated_size != NULL) {
01219             *allocated_size = size;
01220         }
01221     }
01222     else
01223     {
01224         /* size = 0 so delete the memory */
01225         CFSTORE_FREE((void*) ctx->area_0_head);
01226         ctx->area_0_head = NULL;
01227         ctx->area_0_tail = NULL;
01228         ctx->area_0_len = 0;
01229     }
01230     CFSTORE_TP(CFSTORE_TP_MEM, "%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);
01231     ret = ARM_DRIVER_OK;
01232     return ret;
01233 
01234 }
01235 
01236 
01237 #ifdef CFSTORE_CONFIG_BACKEND_FLASH_ENABLED
01238 
01239 /*
01240  * flash helper functions
01241  */
01242 
01243 /* @brief   table for mapping flash journal error codes to equivalent cfstore error codes */
01244 static cfstore_flash_journal_error_code_node cfstore_flash_journal_error_code_map[]=
01245 {
01246     { JOURNAL_STATUS_OK,                                ARM_DRIVER_OK},
01247     { JOURNAL_STATUS_ERROR,                             ARM_CFSTORE_DRIVER_ERROR_JOURNAL_STATUS_ERROR},
01248     { JOURNAL_STATUS_BUSY,                              ARM_CFSTORE_DRIVER_ERROR_JOURNAL_STATUS_BUSY},
01249     { JOURNAL_STATUS_TIMEOUT,                           ARM_CFSTORE_DRIVER_ERROR_JOURNAL_STATUS_TIMEOUT},
01250     { JOURNAL_STATUS_UNSUPPORTED,                       ARM_CFSTORE_DRIVER_ERROR_JOURNAL_STATUS_UNSUPPORTED},
01251     { JOURNAL_STATUS_PARAMETER,                         ARM_CFSTORE_DRIVER_ERROR_JOURNAL_STATUS_PARAMETER},
01252     { JOURNAL_STATUS_BOUNDED_CAPACITY,                  ARM_CFSTORE_DRIVER_ERROR_JOURNAL_STATUS_BOUNDED_CAPACITY},
01253     { JOURNAL_STATUS_STORAGE_API_ERROR,                 ARM_CFSTORE_DRIVER_ERROR_JOURNAL_STATUS_STORAGE_API_ERROR},
01254     { JOURNAL_STATUS_STORAGE_IO_ERROR,                  ARM_CFSTORE_DRIVER_ERROR_JOURNAL_STATUS_STORAGE_IO_ERROR},
01255     { JOURNAL_STATUS_NOT_INITIALIZED,                   ARM_CFSTORE_DRIVER_ERROR_JOURNAL_STATUS_NOT_INITIALIZED},
01256     { JOURNAL_STATUS_EMPTY,                             ARM_CFSTORE_DRIVER_ERROR_JOURNAL_STATUS_EMPTY},
01257     { JOURNAL_STATUS_SMALL_LOG_REQUEST,                 ARM_CFSTORE_DRIVER_ERROR_JOURNAL_STATUS_SMALL_LOG_REQUEST},
01258     { CFSTORE_SENTINEL, CFSTORE_SENTINEL}
01259 };
01260 
01261 static int32_t cfstore_flash_map_error(int32_t flash_journal_status_code)
01262 {
01263     cfstore_flash_journal_error_code_node* node = cfstore_flash_journal_error_code_map;
01264 
01265     while(node->flash_journal_error_code != (int32_t) CFSTORE_SENTINEL)
01266     {
01267         if(flash_journal_status_code == node->flash_journal_error_code)
01268         {
01269             return node->cfstore_error_code;
01270         }
01271     }
01272     return ARM_CFSTORE_DRIVER_ERROR_INTERNAL;
01273 }
01274 
01275 
01276 /* @brief   Callback registered with flash journal for async operation
01277  *          completion notifications.
01278  *
01279  * @note    The callback is called at interrupt context.
01280  *          The critical section to used police access to context variables
01281  *          modified by both the interrupt and application context processing.
01282  *          The interrupt context prevents application context from running and
01283  *          hence its only necessary to use the critical_section_xxx in the
01284  *          application execution context.
01285  *
01286  *          In flash journal async mode, when:
01287  *              - a FlashJournal_xxx() function has been invoked, and
01288  *              - before the async completion has been received and processed
01289  *          the application context code should always coordinate access to
01290  *          context variables modified by interrupt and application context
01291  *          by use of the critical_section_xxx.
01292  */
01293 static void cfstore_flash_journal_callback(int32_t status, FlashJournal_OpCode_t cmd_code)
01294 {
01295     cfstore_ctx_t* ctx = cfstore_ctx_get();
01296 
01297     CFSTORE_FENTRYLOG("%s:entered: status=%d, cmd_code=%d (%s)\n", __func__, (int) status, (int) cmd_code, cfstore_flash_opcode_str[cmd_code]);
01298     switch(cmd_code)
01299     {
01300     case FLASH_JOURNAL_OPCODE_FORMAT:
01301         ctx->fsm.event = cfstore_fsm_event_format_done;
01302         break;
01303     case FLASH_JOURNAL_OPCODE_INITIALIZE:
01304         ctx->fsm.event = cfstore_fsm_event_init_done;
01305         break;
01306     case FLASH_JOURNAL_OPCODE_READ_BLOB:
01307         ctx->fsm.event = cfstore_fsm_event_read_done;
01308         break;
01309     case FLASH_JOURNAL_OPCODE_LOG_BLOB:
01310         ctx->fsm.event = cfstore_fsm_event_log_done;
01311         break;
01312     case FLASH_JOURNAL_OPCODE_COMMIT:
01313         ctx->fsm.event = cfstore_fsm_event_commit_done;
01314         break;
01315     case FLASH_JOURNAL_OPCODE_RESET:
01316         ctx->fsm.event = cfstore_fsm_event_reset_done;
01317         break;
01318     case FLASH_JOURNAL_OPCODE_GET_INFO:
01319     default:
01320         CFSTORE_ERRLOG("%s:Error: notification of unsupported cmd_code event (status=%d, cmd_code=%d)\n", __func__, (int) status, (int) cmd_code);
01321         return;
01322     }
01323     ctx->status = status;
01324     ctx->cmd_code = cmd_code;
01325     cfstore_fsm_state_handle_event(&ctx->fsm, ctx->fsm.event, (void*) ctx);
01326     return;
01327 }
01328 
01329 
01330 /* @brief */
01331 static int32_t cfstore_fsm_stop_on_entry(void* context)
01332 {
01333     cfstore_ctx_t* ctx = (cfstore_ctx_t*) context;
01334 
01335     /* reset fsm state */
01336     CFSTORE_FENTRYLOG("%s:entered\n", __func__);
01337     CFSTORE_ASSERT(ctx->fsm.state == cfstore_fsm_state_stopped);
01338 
01339     ctx->fsm.event = cfstore_fsm_event_max;
01340     ctx->cmd_code = (FlashJournal_OpCode_t)((int) FLASH_JOURNAL_OPCODE_RESET+1);
01341     return ARM_DRIVER_OK;
01342 }
01343 
01344 /* static int32_t cfstore_fsm_stop_on_exit(void* context) {(void) context; }*/
01345 
01346 
01347 /* @brief   fsm on entry function for the initing state
01348  * @note
01349  *  flash journal sync mode: (see async mode notes)
01350  *  flash journal async mode:
01351  *      This is typically called in app context (not intr context) for both flash
01352  *      journal sync and asyc modes. There are no outstanding async requests
01353  *      so it cannot be interrupted, and therefore doesnt need CS protection.
01354  */
01355 static int32_t cfstore_fsm_init_on_entry(void* context)
01356 {
01357     int32_t ret = ARM_DRIVER_ERROR;
01358     cfstore_ctx_t* ctx = (cfstore_ctx_t*) context;
01359 
01360     CFSTORE_FENTRYLOG("%s:entered\n", __func__);
01361 
01362     ret = cfstore_svm_init(&cfstore_journal_mtd);
01363     if(ret < ARM_DRIVER_OK){
01364         CFSTORE_DBGLOG("%s:Error: Unable to initialize storage volume manager\n", __func__);
01365         cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_formatting, ctx);
01366         return ARM_DRIVER_OK;
01367     }
01368 
01369     ret = FlashJournal_initialize(&ctx->jrnl, (ARM_DRIVER_STORAGE *) &cfstore_journal_mtd, &FLASH_JOURNAL_STRATEGY_SEQUENTIAL, cfstore_flash_journal_callback);
01370     CFSTORE_TP(CFSTORE_TP_FSM, "%s:FlashJournal_initialize ret=%d\n", __func__, (int) ret);
01371     if(ret < ARM_DRIVER_OK){
01372         if(ret == JOURNAL_STATUS_NOT_FORMATTED) {
01373             CFSTORE_DBGLOG("%s:Error: flash not formatted\n", __func__);
01374             cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_formatting, ctx);
01375             return ARM_DRIVER_OK;
01376         }
01377         if(ret == JOURNAL_STATUS_METADATA_ERROR) {
01378             CFSTORE_ERRLOG("%s:Error: flash meta-data (CRC) error detected when initializing flash. Reformatting flash.\n", __func__);
01379             cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_formatting, ctx);
01380             return ARM_DRIVER_OK;
01381         }
01382         CFSTORE_ERRLOG("%s:Error: failed to initialize flash journaling layer (ret=%d)\n", __func__, (int) ret);
01383         cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_stopped, ctx);
01384     }
01385     else if(ret > 0){
01386         /* operation completed synchronously*/
01387         cfstore_flash_journal_callback(ret, FLASH_JOURNAL_OPCODE_INITIALIZE);
01388     }
01389     return ret;
01390 }
01391 
01392 
01393 /* @brief   fsm initing state handler function
01394  * @note
01395  *  flash journal sync mode:
01396  *      CS protection not required as there are no callbacks.
01397  *  flash journal async mode:
01398  *      This is typically called at intr context (not app context) when flash
01399  *      journal invokes the callback handler for FLASH_JOURNAL_OPCODE_INITIALIZE
01400  *      Hence as running at intr level, no CS protection is required.
01401  */
01402 static int32_t cfstore_fsm_initing(void* context)
01403 {
01404     int32_t ret = ARM_DRIVER_OK;
01405     cfstore_ctx_t* ctx = (cfstore_ctx_t*) context;
01406 
01407     CFSTORE_FENTRYLOG("%s:entered\n", __func__);
01408     CFSTORE_ASSERT(ctx->fsm.state == cfstore_fsm_state_initing);
01409     CFSTORE_ASSERT(ctx->cmd_code == FLASH_JOURNAL_OPCODE_INITIALIZE);
01410 
01411     /* only change state if status > 0*/
01412     if(ctx->status > 0){
01413         ret = cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_reading, ctx);
01414     } else if(ctx->status < 0) {
01415         CFSTORE_ERRLOG("%s:Error: failed to initialize flash journaling layer (ret=%d)\n", __func__, (int) ctx->status);
01416         cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_stopped, ctx);
01417     }
01418     return ret;
01419 }
01420 
01421 /* static int32_t cfstore_fsm_init_on_exit(void* context) */
01422 
01423 
01424 /* @brief   fsm on entry function for the reading state
01425  * @note
01426  *  flash journal sync mode:
01427  *      CS protection not required as there are no callbacks.
01428  *  flash journal async mode:
01429  *      This is typically called at intr context (not app context) when flash
01430  *      journal invokes the callback handler for FLASH_JOURNAL_OPCODE_INITIALIZE
01431  *      Hence as running at intr level, no CS protection is required.
01432  */
01433 static int32_t cfstore_fsm_read_on_entry(void* context)
01434 {
01435     int32_t ret = 0;
01436     FlashJournal_Status_t status = JOURNAL_STATUS_ERROR;
01437     cfstore_ctx_t* ctx = (cfstore_ctx_t*) context;
01438 
01439     CFSTORE_FENTRYLOG("%s:entered\n", __func__);
01440     CFSTORE_ASSERT(ctx != NULL);
01441     /* FlashJournal_getInfo() is synchronous */
01442     status = FlashJournal_getInfo(&ctx->jrnl, &ctx->info);
01443     if(status < JOURNAL_STATUS_OK){
01444         CFSTORE_TP(CFSTORE_TP_FSM, "%s:Error: failed get journal info (status=%d)\n", __func__, (int) status);
01445         /* move to ready state. cfstore client is expected to Uninitialize() before further calls */
01446         cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_ready, ctx);
01447         ret = ARM_CFSTORE_DRIVER_ERROR_INTERNAL;
01448         goto out;
01449     }
01450     if(ctx->info.sizeofJournaledBlob > 0)
01451     {
01452         /* setup the expected blob size for writing */
01453         ctx->expected_blob_size = ctx->info.sizeofJournaledBlob;
01454         ret = cfstore_realloc_ex(ctx->expected_blob_size, &ctx->expected_blob_size);
01455         if(ret < ARM_DRIVER_OK){
01456             CFSTORE_ERRLOG("%s:Error: cfstore_realloc_ex() failed (ret=%d)\n", __func__, (int) ret);
01457             /* move to ready state. cfstore client is expected to Uninitialize() before further calls */
01458             cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_ready, ctx);
01459             goto out;
01460         }
01461         ret = FlashJournal_read(&ctx->jrnl, (void*) ctx->area_0_head, ctx->info.sizeofJournaledBlob);
01462         if(ret < ARM_DRIVER_OK){
01463             CFSTORE_ERRLOG("%s:Error: failed to initialize flash journaling layer (ret=%d)\n", __func__, (int) ret);
01464             /* move to ready state. cfstore client is expected to Uninitialize() before further calls */
01465             cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_ready, ctx);
01466             goto out;
01467         } else if(ret > 0){
01468             /* read has completed synchronously*/
01469             CFSTORE_TP(CFSTORE_TP_FSM, "%s:debug:ret > 0: (ret=%d)\n", __func__, (int) ret);
01470             cfstore_flash_journal_callback(ret, FLASH_JOURNAL_OPCODE_READ_BLOB);
01471             ret = ctx->status;
01472             goto out;
01473         }
01474         /* keep lock and wait for async callback */
01475     } else {
01476         /* there is no blob, move to next state. need a +ve status value to indicate async completion
01477          * to the fsm reading state handler. use CFSTORE_FLASH_AREA_SIZE_MIN for this value */
01478         ctx->expected_blob_size = CFSTORE_FLASH_AREA_SIZE_MIN;
01479         status = (FlashJournal_Status_t) CFSTORE_FLASH_AREA_SIZE_MIN;
01480         cfstore_flash_journal_callback(status, FLASH_JOURNAL_OPCODE_READ_BLOB);
01481         ret = ctx->status;
01482         goto out;
01483     }
01484 out:
01485     return ret;
01486 }
01487 
01488 
01489 /* @brief  fsm handler when in reading state */
01490 static int32_t cfstore_fsm_reading(void* context)
01491 {
01492     int32_t ret = ARM_DRIVER_ERROR;
01493     cfstore_ctx_t* ctx = (cfstore_ctx_t*) context;
01494 
01495     CFSTORE_FENTRYLOG("%s:entered\n", __func__);
01496     CFSTORE_ASSERT(ctx->fsm.state == cfstore_fsm_state_reading);
01497     CFSTORE_ASSERT(ctx->cmd_code == FLASH_JOURNAL_OPCODE_READ_BLOB);
01498     if(ctx->status > 0)
01499     {
01500         if(ctx->status > (int32_t) CFSTORE_FLASH_AREA_SIZE_MIN)
01501         {
01502             CFSTORE_TP(CFSTORE_TP_FSM, "%s:debug:ctx->status > (int32_t) CFSTORE_FLASH_AREA_SIZE_MIN:\n", __func__);
01503             /* check the correct amount of data was read, which is the status code */
01504             if(ctx->status == (int32_t) ctx->expected_blob_size)
01505             {
01506                 /* now have to allow for the fact that there may have been some padding
01507                  * at the end of the last _log() to flash, so the read back area may have
01508                  * padding at the end, and the tail_pointer needs to not point to the
01509                  * end where the padding is located, but to the end of the last KV.
01510                  */
01511                 ret = cfstore_flash_set_tail();
01512                 if(ret < ARM_DRIVER_OK){
01513                     CFSTORE_ERRLOG("%s:Error: cfstore_flash_set_tail() failed (ret=%d)\n", __func__, (int) ret);
01514                     /* move to ready state. cfstore client is expected to Uninitialize() before further calls */
01515                     cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_ready, ctx);
01516                     memset(&ctx->info, 0, sizeof(ctx->info));
01517                     goto out;
01518                 }
01519                 ret = cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_ready, ctx);
01520                 if(ret < ARM_DRIVER_OK){
01521                     CFSTORE_ERRLOG("%s:Error: cfstore_fsm_state_set() failed (ret=%d)\n", __func__, (int) ret);
01522                     goto out;
01523                 }
01524                 ret = ctx->status;
01525             }
01526             else
01527             {
01528                 CFSTORE_ERRLOG("%s:Error: read bytes (%d) does not equal requested read size (%d)\n", __func__, (int) ctx->status, (int) ctx->expected_blob_size);
01529                 ret = cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_ready, ctx);
01530                 if(ret < ARM_DRIVER_OK){
01531                     /* move to ready state. cfstore client is expected to Uninitialize() before further calls */
01532                     CFSTORE_ERRLOG("%s:Error: cfstore_fsm_state_set() failed (ret=%d)\n", __func__, (int) ret);
01533                     goto out;
01534                 }
01535                 ret = ctx->status;
01536             }
01537         }
01538         else
01539         {
01540             CFSTORE_TP(CFSTORE_TP_FSM, "%s:debug:ctx->status <= (int32_t) CFSTORE_FLASH_AREA_SIZE_MIN:\n", __func__);
01541             ret = cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_ready, ctx);
01542             if(ret < ARM_DRIVER_OK){
01543                 /* move to ready state. cfstore client is expected to Uninitialize() before further calls */
01544                 CFSTORE_ERRLOG("%s:Error: cfstore_fsm_state_set() failed (ret=%d)\n", __func__, (int) ret);
01545                 goto out;
01546             }
01547             ret = ctx->status;
01548         }
01549     }
01550     else if(ctx->status < 0)
01551     {
01552         CFSTORE_TP(CFSTORE_TP_FSM, "%s:debug:ctx->status < 0:\n", __func__);
01553         ret = ctx->status;
01554     }
01555 out:
01556     return ret;
01557 }
01558 
01559 
01560 static int32_t cfstore_fsm_read_on_exit(void* context)
01561 {
01562     cfstore_ctx_t* ctx = (cfstore_ctx_t*) context;
01563 
01564     CFSTORE_FENTRYLOG("%s:entered:\n", __func__);
01565     /* notify client of initialisation status */
01566     cfstore_client_notify_data_init(&ctx->client_notify_data, CFSTORE_OPCODE_INITIALIZE, ctx->status, NULL);
01567     ctx->client_callback_notify_flag = true;
01568     return ARM_DRIVER_OK;
01569 }
01570 
01571 /* int32_t cfstore_fsm_log_on_entry(void* context){ (void) context;} */
01572 
01573 /* @brief   on entry to writing state, update value */
01574 int32_t cfstore_fsm_log_on_entry(void* context)
01575 {
01576     int32_t ret = 0;
01577     cfstore_ctx_t* ctx = (cfstore_ctx_t*) context;
01578     FlashJournal_Info_t info;
01579     FlashJournal_Status_t status = JOURNAL_STATUS_ERROR;
01580 
01581     CFSTORE_FENTRYLOG("%s:entered:\n", __func__);
01582     memset(&info, 0, sizeof(info));
01583 
01584     status = FlashJournal_getInfo(&ctx->jrnl, &info);
01585     if(status < JOURNAL_STATUS_OK){
01586         CFSTORE_ERRLOG("%s:Error: failed get journal info (status=%d)\n", __func__, (int) status);
01587         /* move to ready state. cfstore client is expected to Uninitialize() before further calls */
01588         cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_ready, ctx);
01589         return cfstore_flash_map_error(status);
01590     }
01591     /* compute the expected_blob_size = area_size plus the padding at the end of the area to align with program_unit*/
01592     ctx->expected_blob_size = cfstore_ctx_get_kv_total_len();
01593     if(ctx->expected_blob_size % info.program_unit > 0){
01594         ctx->expected_blob_size += (info.program_unit - (ctx->expected_blob_size % info.program_unit));
01595     }
01596     /* log the changes to flash even when the area has shrunk to 0, as its necessary to erase the flash */
01597     if(ctx->area_dirty_flag == true)
01598     {
01599         if(ctx->expected_blob_size > 0){
01600             CFSTORE_TP(CFSTORE_TP_FLUSH, "%s:logging: ctx->area_0_head=%p, ctx->expected_blob_size-%d\n", __func__, ctx->area_0_head, (int) ctx->expected_blob_size);
01601             ret = FlashJournal_log(&ctx->jrnl, (const void*) ctx->area_0_head, ctx->expected_blob_size);
01602             if(ret < JOURNAL_STATUS_OK){
01603                 CFSTORE_ERRLOG("%s:Error: FlashJournal_commit() failed (ret=%d)\n", __func__, (int) ret);
01604                 ret = cfstore_flash_map_error(status);
01605                 /* move to ready state. cfstore client is expected to Uninitialize() before further calls */
01606                 cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_ready, ctx);
01607                 goto out0;
01608             } else if(ret > 0){
01609                 /* read has completed synchronously*/
01610                 cfstore_flash_journal_callback(ret, FLASH_JOURNAL_OPCODE_LOG_BLOB);
01611                 ret = ctx->status;
01612             }
01613             /* wait for async completion handler*/
01614         } else {
01615             /* expected_blob_size == 0
01616              * There are no entries in the cfstore (e.g. last entry has been deleted) and this needs
01617              * reflecting in the flash. A log is not required (as there is not data). Initiate the
01618              * commit which will zero the flash
01619              * */
01620             CFSTORE_TP(CFSTORE_TP_FLUSH, "%s:skip logging: initiate commit to erase flash\n", __func__);
01621             ret = JOURNAL_STATUS_OK;
01622             cfstore_flash_journal_callback(ret, FLASH_JOURNAL_OPCODE_LOG_BLOB);
01623         }
01624     }
01625     else
01626     {
01627         /* nothing to be logged so move back to ready state indicating success*/
01628         CFSTORE_TP(CFSTORE_TP_FLUSH, "%s:not logging: ctx->area_0_head=%p, ctx->expected_blob_size-=%d\n", __func__, ctx->area_0_head, (int) ctx->expected_blob_size);
01629         cfstore_flash_journal_callback(ctx->expected_blob_size, FLASH_JOURNAL_OPCODE_LOG_BLOB);
01630     }
01631 out0:
01632     return ret;
01633 }
01634 
01635 /* @brief  fsm handler when in reading state */
01636 static int32_t cfstore_fsm_logging(void* context)
01637 {
01638     cfstore_ctx_t* ctx = (cfstore_ctx_t*) context;
01639 
01640     CFSTORE_FENTRYLOG("%s:entered:ctx->status=%ld\n", __func__, ctx->status);
01641     /* check the correct amount of data was written */
01642     if(ctx->status < JOURNAL_STATUS_OK){
01643         CFSTORE_ERRLOG("%s:Error: FlashJournal_log() failed (ret=%d)\n", __func__, (int) ctx->status);
01644         /* move to ready state. cfstore client is expected to Uninitialize() before further calls */
01645         cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_ready, ctx);
01646         ctx->status = cfstore_flash_map_error(ctx->status);
01647     }
01648     else
01649     {   /* ctx->status >= 0 (status == 0 when everything is deleted) */
01650         if(ctx->status == (int32_t)ctx->expected_blob_size){
01651             /* move to the committing state to commit to flash*/
01652             ctx->status = cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_committing, ctx);
01653         } else {
01654             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);
01655             ctx->status = ARM_DRIVER_ERROR;
01656         }
01657     }
01658     return ctx->status;
01659 }
01660 
01661 
01662 static int32_t cfstore_fsm_log_on_exit(void* context)
01663 {
01664     (void) context;
01665     CFSTORE_FENTRYLOG("%s:entered:\n", __func__);
01666     return ARM_DRIVER_OK;
01667 }
01668 
01669 
01670 /* @brief  fsm handler when entering committing state
01671  * @note
01672  * Its unnecessary to provide CS protection for the flashJouranl_commit() as the all the
01673  * _log() operations affecting the commit have been performed, and no more _log() operations
01674  * can happen until we're back in the ready state
01675  */
01676 static int32_t cfstore_fsm_commit_on_entry(void* context)
01677 {
01678     int32_t ret = JOURNAL_STATUS_OK;
01679     cfstore_ctx_t* ctx = (cfstore_ctx_t*) context;
01680 
01681     CFSTORE_FENTRYLOG("%s:entered:\n", __func__);
01682     if(ctx->area_dirty_flag == true)
01683     {
01684         ret = FlashJournal_commit(&ctx->jrnl);
01685         CFSTORE_TP(CFSTORE_TP_FSM, "%s:debug: FlashJournal_commit() (ret=%d)\n", __func__, (int) ret);
01686         if(ret < JOURNAL_STATUS_OK){
01687             CFSTORE_ERRLOG("%s:Error: FlashJournal_commit() failed (ret=%d)\n", __func__, (int) ret);
01688             /* move to ready state. cfstore client is expected to Uninitialize() before further calls */
01689             cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_ready, ctx);
01690         } else if(ret > 0){
01691             /* read has completed synchronously*/
01692             cfstore_flash_journal_callback(ret, FLASH_JOURNAL_OPCODE_COMMIT);
01693             ret = ctx->status;
01694         }
01695     }
01696     else
01697     {
01698         /* a commit should not be made because there have been no flashJournal_log() calls since the last commit.
01699          * If a _commit() call was made without any _log() calls then it would result in the flash being erased
01700          * because flash journal essentially contains a mirror image of the configuration store sram area, which
01701          * has to be *** FULLY*** repopulated before each _commit(). */
01702         cfstore_flash_journal_callback(ARM_DRIVER_OK_DONE, FLASH_JOURNAL_OPCODE_COMMIT);
01703         ret = ctx->status;
01704     }
01705     /* wait for async callback */
01706     CFSTORE_FENTRYLOG("%s:exiting: FlashJournal_commit() (ret=%d)\n", __func__, (int) ret);
01707     return ret;
01708 }
01709 
01710 
01711 /* @brief  fsm handler when in committing state
01712  * @note
01713  * Its unnecessary to provide CS protection for the flashJouranl_commit() as the all the
01714  * _log() operations affecting the commit have been performed, and no more _log() operations
01715  * can happen until we're back in the ready state
01716  */
01717 static int32_t cfstore_fsm_committing(void* context)
01718 {
01719     cfstore_ctx_t* ctx = (cfstore_ctx_t*) context;
01720 
01721     CFSTORE_FENTRYLOG("%s:entered\n", __func__);
01722     CFSTORE_ASSERT(ctx->fsm.state == cfstore_fsm_state_committing);
01723     CFSTORE_ASSERT(ctx->cmd_code == FLASH_JOURNAL_OPCODE_COMMIT);
01724 
01725     /* check the correct amount of data was written */
01726     if(ctx->status < JOURNAL_STATUS_OK){
01727         CFSTORE_ERRLOG("%s:Error: FlashJournal_commit() failed (ret=%d)\n", __func__, (int) ctx->status);
01728         /* move to ready state. cfstore client is expected to Uninitialize() before further calls */
01729         cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_ready, ctx);
01730         ctx->status = cfstore_flash_map_error(ctx->status);
01731     }
01732     else if(ctx->status == JOURNAL_STATUS_OK)
01733     {
01734         ctx->status = cfstore_flash_map_error(ctx->status);
01735     }
01736     else
01737     {   /* ctx->status > 0. for flash-journal-strategy-sequential version >0.4.0, commit() return no longer reports size of commit block */
01738         ctx->status = cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_ready, ctx);
01739     }
01740     return ctx->status;
01741 }
01742 
01743 static int32_t cfstore_fsm_commit_on_exit(void* context)
01744 {
01745     cfstore_ctx_t* ctx = (cfstore_ctx_t*) context;
01746 
01747     CFSTORE_FENTRYLOG("%s:entered:\n", __func__);
01748     ctx->area_dirty_flag = false;
01749     /* notify client of commit status */
01750     cfstore_client_notify_data_init(&ctx->client_notify_data, CFSTORE_OPCODE_FLUSH, ctx->status, NULL);
01751     ctx->client_callback_notify_flag = true;
01752     return ARM_DRIVER_OK;
01753 }
01754 
01755 /* int32_t cfstore_fsm_reset_on_entry(void* context){ (void) context;} */
01756 /* int32_t cfstore_fsm_resetting(void* context){ (void) context;} */
01757 /* int32_t cfstore_fsm_reset_on_exit(void* context){ (void) context;} */
01758 
01759 
01760 static int32_t cfstore_fsm_ready_on_commit_req(void* context)
01761 {
01762     cfstore_ctx_t* ctx = (cfstore_ctx_t*) context;
01763     CFSTORE_FENTRYLOG("%s:entered\n", __func__);
01764     return cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_logging, ctx);
01765 }
01766 
01767 /* int32_t cfstore_fsm_ready_on_entry(void* context){ (void) context;} */
01768 /* int32_t cfstore_fsm_ready(void* context){ (void) context;} */
01769 /* int32_t cfstore_fsm_ready_on_exit(void* context){ (void) context;} */
01770 
01771 
01772 /** @brief  fsm handler when entering the formatting state
01773  */
01774 static int32_t cfstore_fsm_format_on_entry(void* context)
01775 {
01776     int32_t ret = ARM_DRIVER_ERROR;
01777     cfstore_ctx_t* ctx = (cfstore_ctx_t*) context;
01778 
01779     CFSTORE_FENTRYLOG("%s:entered\n", __func__);
01780 
01781     ret = flashJournalStrategySequential_format((ARM_DRIVER_STORAGE *) &cfstore_journal_mtd, CFSTORE_FLASH_NUMSLOTS, cfstore_flash_journal_callback);
01782     CFSTORE_TP(CFSTORE_TP_FSM, "%s:flashJournalStrategySequential_format ret=%d\n", __func__, (int) ret);
01783     if(ret < ARM_DRIVER_OK){
01784         CFSTORE_ERRLOG("%s:Error: failed to format flash (ret=%d)\n", __func__, (int) ret);
01785         cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_stopped, ctx);
01786     }
01787     else if(ret > 0){
01788         /* operation completed synchronously*/
01789         cfstore_flash_journal_callback(ret, FLASH_JOURNAL_OPCODE_FORMAT);
01790     }
01791     return ret;
01792 }
01793 
01794 /** @brief  fsm handler when in formatting state
01795  */
01796 int32_t cfstore_fsm_formatting(void* context)
01797 {
01798     int32_t ret = ARM_DRIVER_OK;
01799     cfstore_ctx_t* ctx = (cfstore_ctx_t*) context;
01800 
01801     CFSTORE_FENTRYLOG("%s:entered\n", __func__);
01802     CFSTORE_ASSERT(ctx->fsm.state == cfstore_fsm_state_formatting);
01803     CFSTORE_ASSERT(ctx->cmd_code == FLASH_JOURNAL_OPCODE_FORMAT);
01804 
01805     /* only change state if status > 0*/
01806     if(ctx->status > 0){
01807         ret = cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_initing, ctx);
01808     } else if(ctx->status < 0) {
01809         CFSTORE_ERRLOG("%s:Error: failed to format flash (ret=%d)\n", __func__, (int) ctx->status);
01810         cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_stopped, ctx);
01811     }
01812     return ret;
01813 }
01814 
01815 /* int32_t cfstore_fsm_format_on_exit(void* context){ (void) context;} */
01816 
01817 
01818 /* handler functions while in state */
01819 static cfstore_fsm_handler cfstore_flash_fsm[cfstore_fsm_state_max][cfstore_fsm_event_max] =
01820 {
01821 /* state\event:   init_done               read_done             log_done              commit_req                            commit_done               reset_done                format_done, */
01822 /* stopped    */  {cfstore_fsm_null,      cfstore_fsm_null,     cfstore_fsm_null,     cfstore_fsm_null,                     cfstore_fsm_null,         cfstore_fsm_null,     cfstore_fsm_null        },
01823 /* init       */  {cfstore_fsm_initing,   cfstore_fsm_null,     cfstore_fsm_null,     cfstore_fsm_null,                     cfstore_fsm_null,         cfstore_fsm_null,     cfstore_fsm_null        },
01824 /* reading    */  {cfstore_fsm_null,      cfstore_fsm_reading,  cfstore_fsm_null,     cfstore_fsm_null,                     cfstore_fsm_null,         cfstore_fsm_null,     cfstore_fsm_null        },
01825 /* logging    */  {cfstore_fsm_null,      cfstore_fsm_null,     cfstore_fsm_logging,  cfstore_fsm_null,                     cfstore_fsm_null,         cfstore_fsm_null,     cfstore_fsm_null        },
01826 /* committing */  {cfstore_fsm_null,      cfstore_fsm_null,     cfstore_fsm_null,     cfstore_fsm_null,                     cfstore_fsm_committing,   cfstore_fsm_null,     cfstore_fsm_null        },
01827 /* resetting  */  {cfstore_fsm_null,      cfstore_fsm_null,     cfstore_fsm_null,     cfstore_fsm_null,                     cfstore_fsm_null,         cfstore_fsm_null,     cfstore_fsm_null        },
01828 /* ready      */  {cfstore_fsm_null,      cfstore_fsm_null,     cfstore_fsm_null,     cfstore_fsm_ready_on_commit_req,      cfstore_fsm_null,         cfstore_fsm_null,     cfstore_fsm_null        },
01829 /* formatting */  {cfstore_fsm_null,      cfstore_fsm_null,     cfstore_fsm_null,     cfstore_fsm_null,                     cfstore_fsm_null,         cfstore_fsm_null,     cfstore_fsm_formatting  },
01830 };
01831 
01832 /* handler functions for entering the state*/
01833 cfstore_fsm_handler cfstore_fsm_on_entry[cfstore_fsm_state_max] =
01834 {
01835     cfstore_fsm_stop_on_entry,
01836     cfstore_fsm_init_on_entry,
01837     cfstore_fsm_read_on_entry,
01838     cfstore_fsm_log_on_entry,
01839     cfstore_fsm_commit_on_entry,
01840     cfstore_fsm_null,               /* cfstore_fsm_reset_on_entry */
01841     cfstore_fsm_null,               /* cfstore_fsm_ready_on_entry */
01842     cfstore_fsm_format_on_entry     /* cfstore_fsm_format_on_entry */
01843 };
01844 
01845 /* handler functions for exiting state, currently none used */
01846 cfstore_fsm_handler cfstore_fsm_on_exit[cfstore_fsm_state_max] =
01847 {
01848     cfstore_fsm_null,             /* cfstore_fsm_stop_on_exit */
01849     cfstore_fsm_null,             /* cfstore_fsm_init_on_exit */
01850     cfstore_fsm_read_on_exit,
01851     cfstore_fsm_log_on_exit,
01852     cfstore_fsm_commit_on_exit,
01853     cfstore_fsm_null,             /* cfstore_fsm_reset_on_exit */
01854     cfstore_fsm_null,             /* cfstore_fsm_ready_on_exit */
01855     cfstore_fsm_null              /* cfstore_fsm_format_on_exit */
01856 };
01857 
01858 
01859 /* @brief   inject event into fsm */
01860 static int32_t cfstore_fsm_state_handle_event(cfstore_fsm_t* fsm, cfstore_fsm_event_t event, void* context)
01861 {
01862     int32_t ret = ARM_DRIVER_ERROR;
01863     cfstore_ctx_t* ctx = (cfstore_ctx_t*) context;
01864 
01865     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);
01866     CFSTORE_ASSERT(event < cfstore_fsm_event_max);
01867     fsm->event = event;
01868     if(cfstore_flash_fsm[fsm->state][fsm->event] != NULL){
01869         ret = cfstore_flash_fsm[fsm->state][fsm->event](ctx);
01870         if(ret < ARM_DRIVER_OK){
01871             #ifdef CFSTORE_DEBUG
01872             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]);
01873             #endif
01874             return ret;
01875         }
01876     }
01877 
01878     /* do not clear context data set by caller as it may be used later
01879      *  fsm->event = cfstore_fsm_event_max;
01880      *  ctx->status = 0;
01881      *  ctx->cmd_code =  (FlashJournal_OpCode_t)((int) FLASH_JOURNAL_OPCODE_RESET+1);
01882      */
01883     return ret;
01884 }
01885 
01886 
01887 /* @brief   get the current state of the fsm */
01888 static cfstore_fsm_state_t cfstore_fsm_state_get(cfstore_fsm_t* fsm)
01889 {
01890     return fsm->state;
01891 }
01892 
01893 /* @brief   function to move to new fsm state, calling state exit function for old state and entry function for new state */
01894 static int32_t cfstore_fsm_state_set(cfstore_fsm_t* fsm, cfstore_fsm_state_t new_state, void* ctx)
01895 {
01896     int32_t ret = ARM_DRIVER_ERROR;
01897     cfstore_ctx_t* context = (cfstore_ctx_t*) ctx;
01898     #ifdef CFSTORE_DEBUG
01899     cfstore_fsm_state_t old_state = fsm->state;
01900     #endif
01901 
01902     CFSTORE_FENTRYLOG("%s:entered: fsm=%p, ctx=%p\n", __func__, fsm, ctx);
01903     #ifdef CFSTORE_DEBUG
01904     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]);
01905     #endif
01906     CFSTORE_ASSERT(fsm != NULL);
01907     CFSTORE_ASSERT(new_state < cfstore_fsm_state_max);
01908     CFSTORE_ASSERT(ctx != NULL);
01909     CFSTORE_ASSERT(fsm->state < cfstore_fsm_state_max);
01910 
01911     if(cfstore_fsm_on_exit[fsm->state] != NULL){
01912         ret = cfstore_fsm_on_exit[fsm->state](ctx);
01913         if(ret < ARM_DRIVER_OK){
01914             #ifdef CFSTORE_DEBUG
01915             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]);
01916             #endif
01917             /* handling of the error is done in the on_exit() method, which best knows how the state to move to */
01918             return ret;
01919         }
01920     }
01921     fsm->state = new_state;
01922     if(cfstore_fsm_on_entry[new_state] != NULL){
01923         ret = cfstore_fsm_on_entry[new_state](ctx);
01924         if(ret < ARM_DRIVER_OK){
01925             #ifdef CFSTORE_DEBUG
01926             CFSTORE_TP(CFSTORE_TP_FSM, "%s:FSM:REQ RX: fsm->state=%d (%s): new_state=%d (%s): Error: cfstore_fsm_on_entry() failed (ret=%d)\n", __func__, (int) fsm->state, cfstore_flash_state_str[fsm->state], (int) new_state, cfstore_flash_state_str[new_state], (int) ret);
01927             #endif
01928             /* handling of the error is done in the on_entry() method, which best knows how the state to move to */
01929             return ret;
01930         }
01931     }
01932     if(context->client_callback_notify_flag == true)
01933     {
01934         cfstore_client_notify_data_t notify_data;
01935 
01936         CFSTORE_TP(CFSTORE_TP_FSM, "%s:doing client callback\n", __func__);
01937 
01938         /* only one set of client notify data is required as there can only be 1 outstanding flash journal async notificaion
01939          * at one time. */
01940         context->client_callback_notify_flag = false; /* prevents re-calling callback if this function gets called again */
01941         memcpy(&notify_data, &context->client_notify_data, sizeof(cfstore_client_notify_data_t));
01942         /* clear context state before initiating call */
01943         cfstore_client_notify_data_init(&context->client_notify_data, CFSTORE_OPCODE_MAX, ARM_DRIVER_ERROR, NULL);
01944         cfstore_ctx_client_notify(ctx, &notify_data);
01945     }
01946     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]);
01947     return ret;
01948 }
01949 
01950 static bool cfstore_flash_journal_is_async_op_pending(cfstore_ctx_t* ctx)
01951 {
01952     CFSTORE_FENTRYLOG("%s:entered: fsm->state=%s\n", __func__, (char*) cfstore_flash_state_str[cfstore_fsm_state_get(&ctx->fsm)]);
01953     if(cfstore_fsm_state_get(&ctx->fsm) != cfstore_fsm_state_ready)
01954     {
01955         /* flash journal async operation is in progress */
01956         return true;
01957     }
01958     return false;
01959 }
01960 
01961 static int32_t cfstore_flash_init(void)
01962 {
01963     int32_t ret = ARM_DRIVER_ERROR;
01964     cfstore_ctx_t* ctx = cfstore_ctx_get();
01965 
01966     CFSTORE_FENTRYLOG("%s:entered: \n", __func__);
01967     ctx->cmd_code = (FlashJournal_OpCode_t)((int) FLASH_JOURNAL_OPCODE_RESET+1);
01968     ctx->expected_blob_size = 0;
01969     ctx->fsm.event = cfstore_fsm_event_max;
01970     ctx->fsm.state = cfstore_fsm_state_stopped;
01971     memset(&ctx->info, 0, sizeof(ctx->info));
01972     ret = cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_initing, ctx);
01973     if(ret < 0){
01974         CFSTORE_DBGLOG("%s:Error: cfstore_fsm_state_set() failed\n", __func__);
01975         return ret;
01976     }
01977     return ret;
01978 }
01979 
01980 
01981 /* @brief   de-initialise the flash journal */
01982 static int32_t cfstore_flash_deinit(void)
01983 {
01984     int32_t ret = ARM_DRIVER_ERROR;
01985     cfstore_ctx_t* ctx = cfstore_ctx_get();
01986 
01987     CFSTORE_FENTRYLOG("%s:entered: fsm->state=%s\n", __func__, (char*) cfstore_flash_state_str[cfstore_fsm_state_get(&ctx->fsm)]);
01988     ret = cfstore_fsm_state_set(&ctx->fsm, cfstore_fsm_state_stopped, ctx);
01989     if(ret < 0){
01990         CFSTORE_TP(CFSTORE_TP_INIT, "%s:Error: cfstore_fsm_state_set() failed\n", __func__);
01991     }
01992     return ret;
01993 }
01994 
01995 /*
01996 static int32_t cfstore_flash_reset(void)
01997 {
01998     int32_t ret = ARM_DRIVER_ERROR;
01999     cfstore_ctx_t* ctx = cfstore_ctx_get();
02000 
02001     ret = FlashJournal_reset(&ctx->jrnl);
02002     if(ret != JOURNAL_STATUS_OK){
02003         CFSTORE_ERRLOG("%s:Error: failed to reset flash journal (ret=%d)\n", __func__, (int) ret);
02004         goto out0;
02005     }
02006 out0:
02007     return ret;
02008 }
02009 */
02010 
02011 static int32_t cfstore_flash_flush(cfstore_ctx_t* ctx)
02012 {
02013     int32_t ret = ARM_DRIVER_OK;
02014 
02015     CFSTORE_FENTRYLOG("%s:entered\n", __func__);
02016     /* put the async completion code state variables into a known state */
02017     ctx->status = ARM_DRIVER_OK;
02018     ctx->cmd_code = (FlashJournal_OpCode_t)((int) FLASH_JOURNAL_OPCODE_RESET+1);
02019 
02020     /* cfstore_fsm_state_handle_event() is called at intr context via
02021      * cfstore_flash_journal_callback(), and hence calls from app context are
02022      * protected with CSs */
02023     cfstore_critical_section_lock(&ctx->rw_area0_lock, __func__);
02024     ret = cfstore_fsm_state_handle_event(&ctx->fsm, cfstore_fsm_event_commit_req, (void*) ctx);
02025     cfstore_critical_section_unlock(&ctx->rw_area0_lock, __func__);
02026     return ret;
02027 }
02028 
02029 #else /* CFSTORE_CONFIG_BACKEND_FLASH_ENABLED */
02030 
02031 static bool cfstore_flash_journal_is_async_op_pending(cfstore_ctx_t* ctx) { CFSTORE_FENTRYLOG("%s:SRAM:entered:\n", __func__); (void) ctx; return false; }
02032 
02033 /* @brief   generate the CFSTORE_OPCODE_INITIALIZE callback notification */
02034 static int32_t cfstore_flash_init(void)
02035 {
02036     cfstore_client_notify_data_t notify_data;
02037     cfstore_ctx_t* ctx = cfstore_ctx_get();
02038 
02039     CFSTORE_FENTRYLOG("%s:SRAM:entered:\n", __func__);
02040     cfstore_client_notify_data_init(&notify_data, CFSTORE_OPCODE_INITIALIZE, ARM_DRIVER_OK, NULL);
02041     cfstore_ctx_client_notify(ctx, &notify_data);
02042     return ARM_DRIVER_OK;
02043 }
02044 
02045 static int32_t cfstore_flash_deinit(void){ CFSTORE_FENTRYLOG("%s:SRAM:entered:\n", __func__); return ARM_DRIVER_OK; }
02046 /* static int32_t cfstore_flash_reset(void) { CFSTORE_FENTRYLOG("%s:SRAM:entered:\n", __func__); return ARM_DRIVER_OK; }*/
02047 static int32_t cfstore_flash_flush(cfstore_ctx_t* ctx)
02048 {
02049     cfstore_client_notify_data_t notify_data;
02050 
02051     CFSTORE_FENTRYLOG("%s:SRAM:entered:\n", __func__);
02052     cfstore_client_notify_data_init(&notify_data, CFSTORE_OPCODE_FLUSH, ARM_DRIVER_OK, NULL);
02053     cfstore_ctx_client_notify(ctx, &notify_data);
02054     return ARM_DRIVER_OK;
02055 }
02056 
02057 #endif /* CFSTORE_CONFIG_BACKEND_FLASH_ENABLED */
02058 
02059 
02060 /** @brief  After a cfstore KV area memmove() operation, update the file pointers
02061  *          to reflect the new location in memory of KVs.
02062  *
02063  * @param   head
02064  * the position at which size_diff bytes have been inserted/deleted
02065  *
02066  * @param   size_diff
02067  * Change in size (size difference) of the KV memory area.
02068  *  - size_diff > 0 => increase in area, |size_diff| bytes have been inserted at head,
02069  *    and the previously following KVs shifted up to higher memory addresses
02070  *  - size_diff < 0 => decrease in area, |size_diff| bytes have been removed at head,
02071  *    and the previously following KVs shifted down to lower memory addresses
02072  * */
02073 static int32_t cfstore_file_update(uint8_t* head, int32_t size_diff)
02074 {
02075     cfstore_ctx_t* ctx = cfstore_ctx_get();
02076     cfstore_file_t* file;
02077     cfstore_list_node_t* node;
02078     cfstore_list_node_t* file_list = &ctx->file_list;
02079 
02080     CFSTORE_FENTRYLOG("%s:entered:(ctx->area_0_head=%p, ctx->area_0_tail=%p)\n", __func__, ctx->area_0_head, ctx->area_0_tail);
02081 
02082     /* walk the file list updating head pointers for the KVs that remain*/
02083     node = file_list->next;
02084     while(node != file_list){
02085         /* Any KV positioned later in the area than the deleted KV will require file head pointers updating.
02086          * If file's head pointer is beyond the deleted KV tail then the file->head needs to be updated
02087          * to reflect the memove
02088          */
02089         file = (cfstore_file_t*) node;
02090         if(file->head >= head){
02091             /* sign of sign_diff used to move file->head up/down in memory*/
02092             file->head += size_diff;
02093         }
02094         node = node->next;
02095     }
02096     return ARM_DRIVER_OK;
02097 }
02098 
02099 
02100 static int32_t cfstore_delete_ex(cfstore_area_hkvt_t* hkvt)
02101 {
02102     int32_t ret = ARM_DRIVER_ERROR;
02103     ARM_CFSTORE_SIZE kv_size = 0;
02104     ARM_CFSTORE_SIZE kv_total_size = 0;
02105     ARM_CFSTORE_SIZE realloc_size = 0;      /* size aligned to flash program_unit size */
02106     cfstore_ctx_t* ctx = cfstore_ctx_get();
02107 
02108     CFSTORE_FENTRYLOG("%s:entered:(ctx->area_0_head=%p, ctx->area_0_tail=%p)\n", __func__, ctx->area_0_head, ctx->area_0_tail);
02109     kv_size  = cfstore_hkvt_get_size(hkvt);
02110     kv_total_size = cfstore_ctx_get_kv_total_len();
02111 
02112     /* Note the following:
02113      *  1. memmove() above shifts the position of the KVs falling after the deleted KV to be at
02114      *     lower memory addresses. The code (A) updates the cfstore_file_t::head pointers for these KVs
02115      *     so they point to the new locations.
02116      *  2. The operation at 1. above has to happen before the realloc because realloc() can move the
02117      *     start of heap block to a new location, in which case all cfstore_file_t::head pointers
02118      *     need to be updated. cfstore_realloc() can only do this starting from a set of correct
02119      *     cfstore_file_t::head pointers i.e. after 1. has been completed.
02120      */
02121     memmove(hkvt->head, hkvt->tail, ctx->area_0_tail - hkvt->tail);
02122     /* zero the deleted KV memory */
02123     memset(ctx->area_0_tail-kv_size, 0, kv_size);
02124 
02125     /* The KV area has shrunk so a negative size_diff should be indicated to cfstore_file_update(). */
02126     ret = cfstore_file_update(hkvt->head, -1 *(int32_t)kv_size);
02127     if(ret < ARM_DRIVER_OK){
02128         CFSTORE_ERRLOG("%s:Error:file update failed\n", __func__);
02129         goto out0;
02130     }
02131 
02132     /* setup the reallocation memory size. */
02133     realloc_size = kv_total_size - kv_size;
02134     ret = cfstore_realloc_ex(realloc_size, NULL);
02135     if(ret < ARM_DRIVER_OK){
02136         CFSTORE_ERRLOG("%s:Error:realloc failed\n", __func__);
02137         goto out0;
02138     }
02139 out0:
02140     return ret;
02141 }
02142 
02143 
02144 /*
02145  * File operations
02146  */
02147 
02148 static cfstore_file_t* cfstore_file_get(ARM_CFSTORE_HANDLE  hkey)
02149 {
02150     return (cfstore_file_t*) hkey;
02151 }
02152 
02153 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)
02154 {
02155     int32_t ret = ARM_DRIVER_ERROR;
02156     cfstore_file_t* file = (cfstore_file_t*) hkey;
02157 
02158     CFSTORE_FENTRYLOG("%s:entered\n", __func__);
02159     if(file != NULL){
02160         memset(file, 0, sizeof(cfstore_file_t));
02161         CFSTORE_INIT_LIST_HEAD(&file->node);
02162         ret = cfstore_hkvt_refcount_inc(hkvt, NULL);
02163         if(ret < ARM_DRIVER_OK){
02164             CFSTORE_ERRLOG("%s:Error: cfstore_hkvt_refcount_inc() failed (ret=%d)\n", __func__, (int) ret);
02165             return NULL;
02166         }
02167         file->head = hkvt->head;
02168         file->flags.read = flags.read;
02169         file->flags.write = flags.write;
02170         if(list_head != NULL){
02171             cfstore_listAdd(list_head, &file->node, list_head);
02172         }
02173     }
02174     return file;
02175 }
02176 
02177 /* @brief   required to be in critical section when called. */
02178 static int32_t cfstore_file_destroy(cfstore_file_t* file)
02179 {
02180     int32_t ret = ARM_DRIVER_ERROR;
02181     cfstore_area_hkvt_t hkvt;
02182     uint8_t refcount = 0;
02183 
02184     CFSTORE_FENTRYLOG("%s:entered\n", __func__);
02185     if(file) {
02186         hkvt = cfstore_get_hkvt_from_head_ptr(file->head);
02187         CFSTORE_ASSERT(cfstore_hkvt_is_valid(&hkvt, cfstore_ctx_get()->area_0_tail) == true);
02188         ret = ARM_DRIVER_OK;
02189         cfstore_hkvt_refcount_dec(&hkvt, &refcount);
02190         CFSTORE_TP(CFSTORE_TP_FILE, "%s:refcount =%d file->head=%p\n", __func__, (int)refcount, file->head);
02191         if(refcount == 0){
02192             /* check for delete */
02193             CFSTORE_TP(CFSTORE_TP_FILE, "%s:checking delete flag\n", __func__);
02194             if(cfstore_hkvt_get_flags_delete(&hkvt)){
02195                 ret = cfstore_delete_ex(&hkvt);
02196             }
02197         }
02198         /* reset client buffer to empty ready for reuse */
02199         /* delete the file even if not deleting the KV*/
02200         cfstore_listDel(&file->node);
02201         memset(file, 0, sizeof(cfstore_file_t));
02202     }
02203     return ret;
02204 }
02205 
02206 
02207 /**
02208  * @brief   check whether this is an valid buffer
02209  *
02210  * @param   hkey
02211  *          IN: The key handle to be validated
02212  *
02213  *          ctx
02214  *          IN: cfstore context block
02215  */
02216 static bool cfstore_file_is_valid(ARM_CFSTORE_HANDLE  hkey, cfstore_ctx_t* ctx)
02217 {
02218     cfstore_file_t* file = cfstore_file_get(hkey);
02219 
02220     if(ctx->area_0_head != NULL && ctx->area_0_tail != NULL){
02221         if(file->head < ctx->area_0_head || file->head > ctx->area_0_tail){
02222             return 0;
02223         }
02224         return true;
02225     }
02226     return false;
02227 }
02228 
02229 /**
02230  * @brief   check whether this is an empty buffer, or whether it
02231  *          has valid data
02232  *
02233  * @param   hkey
02234  *          IN: The key handle to be validated
02235  *
02236  *          ctx
02237  *          IN: cfstore context block
02238  */
02239 static bool cfstore_file_is_empty(ARM_CFSTORE_HANDLE  hkey)
02240 {
02241     ARM_CFSTORE_HANDLE_INIT(zero);
02242     if(hkey != NULL){
02243         return !memcmp(hkey, zero, CFSTORE_HANDLE_BUFSIZE);
02244     }
02245     return 0;
02246 }
02247 
02248 
02249 /* @brief  See definition in configuration_store.h for description. */
02250 ARM_CFSTORE_CAPABILITIES cfstore_get_capabilities(void)
02251 {
02252     /* getting capabilities doesn't change the sram area so this can happen independently of
02253      * an outstanding async operation. its unnecessary to check the fsm state */
02254     return cfstore_caps_g;
02255 }
02256 
02257 
02258 /* @brief   check the flags argument are supported */
02259 static int32_t cfstore_validate_fmode_flags(ARM_CFSTORE_FMODE flags)
02260 {
02261     if(flags.continuous){
02262         CFSTORE_ERRLOG("%s:Error:Continuous flag not supported.\n", __func__);
02263         return ARM_CFSTORE_DRIVER_ERROR_NOT_SUPPORTED;
02264     }
02265     if(flags.lazy_flush){
02266         CFSTORE_ERRLOG("%s:Error:Lazy flush flag not supported.\n", __func__);
02267         return ARM_CFSTORE_DRIVER_ERROR_NOT_SUPPORTED;
02268     }
02269     if(flags.flush_on_close){
02270         CFSTORE_ERRLOG("%s:Error:Flush on close flag not supported.\n", __func__);
02271         return ARM_CFSTORE_DRIVER_ERROR_NOT_SUPPORTED;
02272     }
02273     if(flags.storage_detect){
02274         CFSTORE_ERRLOG("%s:Error:Storage detect flag not supported.\n", __func__);
02275         return ARM_CFSTORE_DRIVER_ERROR_NOT_SUPPORTED;
02276     }
02277     return ARM_DRIVER_OK;
02278 }
02279 
02280 
02281 /* @brief   validate the client supplied opaque handle */
02282 static CFSTORE_INLINE int32_t cfstore_validate_handle(ARM_CFSTORE_HANDLE  hkey)
02283 {
02284     if(hkey == NULL){
02285         return ARM_CFSTORE_DRIVER_ERROR_INVALID_HANDLE;
02286     }
02287     return ARM_DRIVER_OK;
02288 }
02289 
02290 /* @brief   check the flash security features are valid (internal use only) */
02291 static int32_t cfstore_validate_flash_security_features(const ARM_STORAGE_SECURITY_FEATURES *security)
02292 {
02293     CFSTORE_ASSERT(security != NULL);
02294 
02295     if(security->acls){
02296         CFSTORE_ERRLOG("%s:Error: flash security features acls flag not supported.\n", __func__);
02297         return ARM_CFSTORE_DRIVER_ERROR_NOT_SUPPORTED;
02298     }
02299     if(security->internal_flash){
02300         CFSTORE_ERRLOG("%s:Error: flash security features internal_flash flag not supported.\n", __func__);
02301         return ARM_CFSTORE_DRIVER_ERROR_NOT_SUPPORTED;
02302     }
02303     if(security->rollback_protection){
02304         CFSTORE_ERRLOG("%s:Error: flash security features rollback_protection flag not supported.\n", __func__);
02305         return ARM_CFSTORE_DRIVER_ERROR_NOT_SUPPORTED;
02306     }
02307     if(security->tamper_proof){
02308         CFSTORE_ERRLOG("%s:Error: flash security features tamper_proof flag not supported.\n", __func__);
02309         return ARM_CFSTORE_DRIVER_ERROR_NOT_SUPPORTED;
02310     }
02311     if(security->board_level_attacks){
02312         CFSTORE_ERRLOG("%s:Error: flash security features board level attacks flag not supported.\n", __func__);
02313         return ARM_CFSTORE_DRIVER_ERROR_NOT_SUPPORTED;
02314     }
02315     if(security->software_attacks){
02316         CFSTORE_ERRLOG("%s:Error: flash security features device_software flag not supported.\n", __func__);
02317         return ARM_CFSTORE_DRIVER_ERROR_NOT_SUPPORTED;
02318     }
02319     if(security->chip_level_attacks){
02320         CFSTORE_ERRLOG("%s:Error: flash security features chip level attacks flag not supported.\n", __func__);
02321         return ARM_CFSTORE_DRIVER_ERROR_NOT_SUPPORTED;
02322     }
02323     if(security->side_channel_attacks){
02324         CFSTORE_ERRLOG("%s:Error: flash security features side channel attacks flag not supported.\n", __func__);
02325         return ARM_CFSTORE_DRIVER_ERROR_NOT_SUPPORTED;
02326     }
02327     return ARM_DRIVER_OK;
02328 }
02329 
02330 /* @brief   check the key descriptor are valid (internal use only) */
02331 static int32_t cfstore_validate_flash_data_retention_level(const uint8_t drl)
02332 {
02333     int32_t ret = ARM_DRIVER_ERROR;
02334 
02335     switch(drl)
02336     {
02337     case ARM_RETENTION_WHILE_DEVICE_ACTIVE :
02338     case ARM_RETENTION_ACROSS_SLEEP :
02339     case ARM_RETENTION_ACROSS_DEEP_SLEEP :
02340     case ARM_RETENTION_BATTERY_BACKED :
02341     case ARM_RETENTION_NVM :
02342         ret = ARM_DRIVER_OK;
02343         break;
02344     default:
02345         CFSTORE_ERRLOG("%s:Error: data retention level (%d) not supported.\n", __func__, drl);
02346         ret = ARM_CFSTORE_DRIVER_ERROR_NOT_SUPPORTED;
02347         break;
02348 
02349     }
02350     return ret;
02351 }
02352 
02353 /* @brief   check the access control list is valid (internal use only)  */
02354 static int32_t cfstore_validate_access_control_list(const ARM_CFSTORE_ACCESS_CONTROL_LIST acl)
02355 {
02356     if(acl.perm_owner_execute)
02357     {
02358         CFSTORE_ERRLOG("%s:Error: Access control list with permission owner execute set is not supported.\n", __func__);
02359         return ARM_CFSTORE_DRIVER_ERROR_NOT_SUPPORTED;
02360     }
02361     if(acl.perm_other_execute)
02362     {
02363         CFSTORE_ERRLOG("%s:Error: Access control list with permission other execute set is not supported.\n", __func__);
02364         return ARM_CFSTORE_DRIVER_ERROR_NOT_SUPPORTED;
02365     }
02366     return ARM_DRIVER_OK;
02367 }
02368 
02369 /* @brief   check the key descriptor is valid */
02370 static int32_t cfstore_validate_key_desc(const ARM_CFSTORE_KEYDESC *kdesc)
02371 {
02372     int32_t ret = ARM_DRIVER_ERROR;
02373 
02374     if(kdesc == NULL){
02375         return ARM_CFSTORE_DRIVER_ERROR_INVALID_KEY_DESCRIPTOR;
02376     }
02377     ret = cfstore_validate_access_control_list(kdesc->acl);
02378     if(ret < ARM_DRIVER_OK){
02379         return ret;
02380     }
02381     ret = cfstore_validate_flash_data_retention_level(kdesc->drl);
02382     if(ret < ARM_DRIVER_OK){
02383         return ret;
02384     }
02385     ret = cfstore_validate_flash_security_features(&kdesc->security);
02386     if(ret < ARM_DRIVER_OK){
02387         return ret;
02388     }
02389     ret = cfstore_validate_fmode_flags(kdesc->flags);
02390     if(ret < ARM_DRIVER_OK){
02391         return ret;
02392     }
02393     return ARM_DRIVER_OK;
02394 }
02395 
02396 /**
02397  * @brief   check the key_len pointer is valid
02398  *
02399  * @param   hkey
02400  *          IN: The key handle to be validated
02401  */
02402 static CFSTORE_INLINE int32_t cfstore_validate_len_ptr(ARM_CFSTORE_SIZE *len)
02403 {
02404     if(len == NULL){
02405         return ARM_CFSTORE_DRIVER_ERROR_INVALID_KEY_LEN;
02406     }
02407     return ARM_DRIVER_OK;
02408 }
02409 
02410 /* @brief   return a pointer to the next { or }, or NULL if not present */
02411 static inline char* cfstore_validate_pos_next_brace(const char* pos)
02412 {
02413     char* pos_open = strchr(pos, '{');
02414     char* pos_close = strchr(pos, '}');
02415     if(pos_open != NULL) {
02416         if(pos_close != NULL){
02417             return pos_open < pos_close ? pos_open : pos_close;
02418         }
02419         return pos_open;
02420     }
02421     return pos_close;
02422 }
02423 
02424 
02425 static int32_t cfstore_validate_key_name_ex(const char* key_name, const char* permissible)
02426 {
02427     char* pos = NULL;
02428     int brace_count = 0;
02429     ARM_CFSTORE_SIZE len = 0;
02430     ARM_CFSTORE_SIZE valid_len = 0;
02431 
02432     CFSTORE_FENTRYLOG("%s:entered\n", __func__);
02433     if(key_name != NULL){
02434         /* check the key_name is terminated by a 0 */
02435         pos = (char*) memchr(key_name, '\0', CFSTORE_KEY_NAME_MAX_LENGTH+1);
02436         if(pos == NULL){
02437             CFSTORE_ERRLOG("%s:key_name does not have terminating null.\n", __func__);
02438             return ARM_CFSTORE_DRIVER_ERROR_INVALID_KEY_NAME;
02439         }
02440         /* check for zero length key_name*/
02441         if(strlen(key_name) == 0){
02442             CFSTORE_ERRLOG("%s:Error: invalid key_name.\n", __func__);
02443             return ARM_CFSTORE_DRIVER_ERROR_INVALID_KEY_NAME;
02444         }
02445         /* check the key_name len is less than the max length (220) */
02446         len = strlen(key_name);
02447         if(len > CFSTORE_KEY_NAME_MAX_LENGTH){
02448             CFSTORE_ERRLOG("%s:key_name string is longer (%d) than the supported maximum (%d).\n", __func__, (int) len, (int) CFSTORE_KEY_NAME_MAX_LENGTH);
02449             return ARM_CFSTORE_DRIVER_ERROR_INVALID_KEY_NAME;
02450         }
02451         /* check the key_name only contains permissible characters */
02452         valid_len = strspn(key_name, permissible);
02453         if(valid_len != len){
02454             CFSTORE_ERRLOG("%s:Invalid character (%c) found in key_name (key_name=%s).\n", __func__, key_name[valid_len], key_name);
02455             return ARM_CFSTORE_DRIVER_ERROR_INVALID_KEY_NAME;
02456         }
02457 
02458         /*check there isnt a leading '.' on the kv name */
02459         if(key_name[0] == '.'){
02460             CFSTORE_ERRLOG("%s:Leading (.) character found in key_name (key_name=%s) is not allowed.\n", __func__, key_name);
02461             return ARM_CFSTORE_DRIVER_ERROR_INVALID_KEY_NAME;
02462         }
02463 
02464         /* - check for matching '{' for each '}' present
02465          * - only check a string if either { or } are present
02466          *   i.e. dont process string without
02467          *   checking for existence of single brace, and checking for either { or } so
02468          *   that the case where } is the first brace is convered.
02469          * - start loop at first { or } char,  both {} covers case where } is the first brace
02470          * - (brace_count >=0 && brace_count <= 1) must always be true
02471          * - brace_count must == 0 at end of string
02472          */
02473         pos = cfstore_validate_pos_next_brace(key_name);
02474         while(pos != NULL && brace_count >= 0 && brace_count <= 1)
02475         {
02476             switch(*pos)
02477             {
02478             case '{':
02479                 brace_count++;
02480                 break;
02481             case '}':
02482                 brace_count--;
02483                 break;
02484             default:
02485                 break;
02486             }
02487             pos++;
02488             pos = cfstore_validate_pos_next_brace(pos);
02489         }
02490         if(brace_count != 0){
02491             CFSTORE_ERRLOG("%s: Unmatched brace found in key_name (count=%d.\n", __func__, brace_count);
02492             return ARM_CFSTORE_DRIVER_ERROR_INVALID_KEY_NAME;
02493         }
02494     }
02495     return ARM_DRIVER_OK;
02496 }
02497 
02498 
02499 /* @brief   check the key name is valid */
02500 static int32_t cfstore_validate_key_name(const char* key_name)
02501 {
02502     int32_t ret = ARM_DRIVER_ERROR;
02503 
02504     ret = cfstore_uvisor_security_context_prefix_check(key_name);
02505     if(ret < ARM_DRIVER_OK){
02506         CFSTORE_ERRLOG("%s:Error: failed uvisor security context check.\n", __func__);
02507         return ret;
02508     }
02509     return cfstore_validate_key_name_ex(key_name, CFSTORE_KEY_NAME_CHARS_ACCEPTABLE);
02510 }
02511 
02512 /* @brief   check the key name query is valid */
02513 static int32_t cfstore_validate_key_name_query(const char* key_name_query)
02514 {
02515     return cfstore_validate_key_name_ex(key_name_query, CFSTORE_KEY_NAME_QUERY_CHARS_ACCEPTABLE);
02516 }
02517 
02518 
02519 /**
02520  * @brief   check the value length field is valid
02521  *
02522  * @param   key_name
02523  *          IN: The key name string to be validated
02524  * @note    This will be replaced with the actual uvisor call, when available.
02525  */
02526 static CFSTORE_INLINE int32_t cfstore_validate_value_len(ARM_CFSTORE_SIZE value_len)
02527 {
02528     if(value_len <= CFSTORE_VALUE_SIZE_MAX) {
02529         return ARM_DRIVER_OK;
02530     }
02531     return ARM_CFSTORE_DRIVER_ERROR_VALUE_SIZE_TOO_LARGE;
02532 }
02533 
02534 
02535 /* @brief  See definition in configuration_store.h for description. */
02536 static int32_t cfstore_get_key_name_ex(cfstore_area_hkvt_t *hkvt, char* key_name, uint8_t *key_name_len)
02537 {
02538     int32_t ret = ARM_DRIVER_OK;
02539     int32_t max_len = 0;
02540 
02541     max_len = cfstore_hkvt_get_key_len(hkvt) + 1;
02542     max_len = max_len <= *key_name_len ? max_len : *key_name_len;
02543     memcpy(key_name, (const char*) hkvt->key, max_len-1);
02544     key_name[max_len-1] = '\0';
02545     *key_name_len = max_len;
02546     return ret;
02547 }
02548 
02549 
02550 /* @brief  See definition in configuration_store.h for description. */
02551 static int32_t cfstore_get_key_name(ARM_CFSTORE_HANDLE  hkey, char* key_name, uint8_t *key_name_len)
02552 {
02553     int32_t ret = ARM_DRIVER_ERROR;
02554     cfstore_area_hkvt_t hkvt;
02555     cfstore_client_notify_data_t notify_data;
02556     cfstore_ctx_t* ctx = cfstore_ctx_get();
02557 
02558     CFSTORE_ASSERT(key_name != NULL);
02559     CFSTORE_ASSERT(key_name_len != NULL);
02560 
02561     CFSTORE_FENTRYLOG("%s:entered\n", __func__);
02562     if(!cfstore_ctx_is_initialised(ctx)) {
02563         CFSTORE_ERRLOG("%s:Error: CFSTORE is not initialised.\n", __func__);
02564         ret = ARM_CFSTORE_DRIVER_ERROR_UNINITIALISED;
02565         goto out0;
02566     }
02567     /* getting a keyname doesnt change the sram area so this can happen independently of
02568      * an oustanding async operation. its unnecessary to check the fsm state */
02569     ret = cfstore_validate_handle(hkey);
02570     if(ret < ARM_DRIVER_OK){
02571         CFSTORE_ERRLOG("%s:Error: invalid handle.\n", __func__);
02572         goto out0;
02573     }
02574     if(key_name == NULL){
02575         CFSTORE_ERRLOG("%s:Error: invalid handle.\n", __func__);
02576         ret = ARM_CFSTORE_DRIVER_ERROR_INVALID_KEY_NAME;
02577         goto out0;
02578     }
02579     ret = cfstore_validate_len_ptr((ARM_CFSTORE_SIZE*)key_name_len);
02580     if(ret < ARM_DRIVER_OK){
02581         CFSTORE_ERRLOG("%s:Error: invalid key_name_len argument.\n", __func__);
02582         goto out0;
02583     }
02584     memset(&hkvt, 0, sizeof(hkvt));
02585     hkvt = cfstore_get_hkvt(hkey);
02586     if(!cfstore_hkvt_is_valid(&hkvt, ctx->area_0_tail)){
02587         CFSTORE_ERRLOG("%s:ARM_CFSTORE_DRIVER_ERROR_INVALID_HANDLE\n", __func__);
02588         ret = ARM_CFSTORE_DRIVER_ERROR_INVALID_HANDLE;
02589         goto out0;
02590     }
02591     ret = cfstore_get_key_name_ex(&hkvt, key_name, key_name_len);
02592     if(ret < ARM_DRIVER_OK){
02593         CFSTORE_ERRLOG("%s:Error: cfstore_get_key_name_ex() returned error.\n", __func__);
02594         goto out0;
02595     }
02596     ret = *key_name_len;
02597 out0:
02598     /* GetKeyName() always completes synchronously irrespective of flash mode, so indicate to caller */
02599     cfstore_client_notify_data_init(&notify_data, CFSTORE_OPCODE_GET_KEY_NAME, ret, hkey);
02600     cfstore_ctx_client_notify(ctx, &notify_data);
02601     return ret;
02602 }
02603 
02604 /* @brief  See definition in configuration_store.h for description. */
02605 static ARM_CFSTORE_STATUS cfstore_get_status(void)
02606 {
02607     ARM_CFSTORE_STATUS status;
02608     cfstore_ctx_t* ctx = cfstore_ctx_get();
02609 
02610     memset(&status, 0, sizeof(status));
02611     if(!cfstore_ctx_is_initialised(ctx)) {
02612         CFSTORE_ERRLOG("%s:Error: CFSTORE is not initialised.\n", __func__);
02613         status.error = true;
02614     }
02615     /* getting status doesnt change the sram area so this can happen independently of
02616      * an oustanding async operation. */
02617     if(cfstore_flash_journal_is_async_op_pending(ctx))
02618     {
02619         status.in_progress = true;
02620     }
02621     else
02622     {
02623         status.in_progress = false;
02624     }
02625     return status;
02626 }
02627 
02628 /* @brief  See definition in configuration_store.h for description. */
02629 static int32_t cfstore_get_value_len(ARM_CFSTORE_HANDLE  hkey, ARM_CFSTORE_SIZE *value_len)
02630 {
02631     int32_t ret = ARM_CFSTORE_DRIVER_ERROR_UNINITIALISED;
02632     cfstore_area_hkvt_t hkvt;
02633     cfstore_client_notify_data_t notify_data;
02634     cfstore_ctx_t* ctx = cfstore_ctx_get();
02635 
02636     CFSTORE_FENTRYLOG("%s:entered\n", __func__);
02637     CFSTORE_ASSERT(hkey != NULL);
02638     CFSTORE_ASSERT(value_len != NULL);
02639 
02640     if(!cfstore_ctx_is_initialised(ctx)) {
02641         CFSTORE_ERRLOG("%s:Error: CFSTORE is not initialised.\n", __func__);
02642         goto out0;
02643     }
02644     /* getting a value len doesnt change the sram area so this can happen independently of
02645      * an outstanding async operation. its unnecessary to check the fsm state */
02646     ret = cfstore_validate_handle(hkey);
02647     if(ret < ARM_DRIVER_OK){
02648         CFSTORE_ERRLOG("%s:Error: invalid handle.\n", __func__);
02649         goto out0;
02650     }
02651     ret = cfstore_validate_len_ptr(value_len);
02652     if(ret < ARM_DRIVER_OK){
02653         CFSTORE_ERRLOG("%s:Error: invalid value len argument.\n", __func__);
02654         goto out0;
02655     }
02656     hkvt = cfstore_get_hkvt(hkey);
02657     if(!cfstore_hkvt_is_valid(&hkvt, ctx->area_0_tail)){
02658         CFSTORE_ERRLOG("%s:ARM_CFSTORE_DRIVER_ERROR_INVALID_HANDLE\n", __func__);
02659         ret = ARM_CFSTORE_DRIVER_ERROR_INVALID_HANDLE;
02660         goto out0;
02661     }
02662     *value_len = cfstore_hkvt_get_value_len(&hkvt);
02663     ret = (int32_t) *value_len;
02664 out0:
02665     /* GetValueLen() always completes synchronously irrespective of flash mode, so indicate to caller */
02666     cfstore_client_notify_data_init(&notify_data, CFSTORE_OPCODE_GET_VALUE_LEN, ret, hkey);
02667     cfstore_ctx_client_notify(ctx, &notify_data);
02668     return ret;
02669 }
02670 
02671 #ifdef CFSTORE_DEBUG
02672 
02673 /* @brief   debug trace a struct cfstore_area_hkvt_t, providing values for key field. */
02674 static CFSTORE_INLINE void cfstore_hkvt_dump(cfstore_area_hkvt_t* hkvt, const char* tag)
02675 {
02676 /* #define CFSTORE_HKVT_DUMP_ON */
02677 #ifdef CFSTORE_HKVT_DUMP_ON
02678     char kname[CFSTORE_KEY_NAME_MAX_LENGTH+1];
02679     char value[CFSTORE_KEY_NAME_MAX_LENGTH+1];
02680     uint32_t klen = 0;
02681     uint32_t vlen = 0;
02682     cfstore_ctx_t* ctx = cfstore_ctx_get();
02683 
02684     memset(kname, 0, CFSTORE_KEY_NAME_MAX_LENGTH+1);
02685     memset(value, 0, CFSTORE_KEY_NAME_MAX_LENGTH+1);
02686     klen = cfstore_hkvt_get_key_len(hkvt);
02687     vlen = cfstore_hkvt_get_value_len(hkvt);
02688     memcpy((void*)kname, (void*) hkvt->key, klen);
02689     memcpy((void*)value, (void*) hkvt->value, vlen);
02690     kname[klen] = '\0';
02691     value[vlen] = '\0';
02692 
02693     /* table column description
02694      * col 1: tag, descriptive string supplied by client to identify context of table dump
02695      * col 2: hkvt struct member that is to be reported i.e. head, key, value, tail
02696      * col 3: the value of the pointer described in col 2.
02697      * col 4: the value of the pointer described in col 3 as an offset from the start of the sram area
02698      * col 5: field specified data e.g. for header, the extracted key length, value_length.
02699      */
02700     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);
02701     CFSTORE_TP(CFSTORE_TP_VERBOSE3, "%s:hkvt->key :%8p:%8p:%s\n", tag, hkvt->key, (void*)(hkvt->key - ctx->area_0_head), kname);
02702     CFSTORE_TP(CFSTORE_TP_VERBOSE3, "%s:hkvt->val :%8p:%8p:%s\n", tag, hkvt->value, (void*)(hkvt->value - ctx->area_0_head), value);
02703     CFSTORE_TP(CFSTORE_TP_VERBOSE3, "%s:hkvt->tail:%8p:%8p:\n", tag, hkvt->tail, (void*)(hkvt->tail - ctx->area_0_head));
02704     return;
02705 #else
02706     (void) hkvt;
02707     (void) tag;
02708 
02709 #endif /*  CFSTORE_HKVT_DUMP_ON */
02710 }
02711 
02712 static CFSTORE_INLINE void cfstore_flags_dump(ARM_CFSTORE_FMODE flag, const char* tag)
02713 {
02714     int pos = 0;
02715     char flags[9];
02716 
02717     pos += snprintf(&flags[pos], 9, "%c", flag.continuous ? 'C' : 'c');
02718     pos += snprintf(&flags[pos], 9, "%c", flag.lazy_flush ? 'L' : 'l');
02719     pos += snprintf(&flags[pos], 9, "%c", flag.flush_on_close ? 'F' : 'f');
02720     pos += snprintf(&flags[pos], 9, "%c", flag.read ? 'R' : 'r');
02721     pos += snprintf(&flags[pos], 9, "%c", flag.write ? 'W' : 'w');
02722     pos += snprintf(&flags[pos], 9, "%c", flag.storage_detect ? 'S' : 's');
02723     pos += snprintf(&flags[pos], 9, "--");
02724 
02725     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);
02726     return;
02727 }
02728 
02729 static CFSTORE_INLINE void cfstore_file_dump(cfstore_file_t* file, const char* tag)
02730 {
02731 /*#define CFSTORE_FILE_DUMP_ON */
02732 #ifdef CFSTORE_FILE_DUMP_ON
02733     cfstore_area_hkvt_t hkvt;
02734 
02735     CFSTORE_TP(CFSTORE_TP_VERBOSE3, "%s:*** Dumping File Contents : Start ***\n", tag);
02736     CFSTORE_TP(CFSTORE_TP_VERBOSE3, "%s:file==hkey:%p\n", tag, file);
02737     CFSTORE_TP(CFSTORE_TP_VERBOSE3, "%s:rloc/wloc :%08u/%08u:\n", tag, (unsigned int)  file->rlocation, (unsigned int)  file->wlocation);
02738     cfstore_flags_dump(file->flags, tag);
02739     hkvt = cfstore_get_hkvt((ARM_CFSTORE_HANDLE )file);
02740     cfstore_hkvt_dump(&hkvt, tag);
02741     CFSTORE_TP(CFSTORE_TP_VERBOSE3, "%s:*** Dumping File Contents : End ***\n", tag);
02742     return;
02743 #else
02744     (void) file;
02745     (void) tag;
02746 
02747 #endif /*  CFSTORE_FILE_DUMP_ON */
02748 }
02749 
02750 /* dump sram contents of cfstore in a useful manner for debugging */
02751 static CFSTORE_INLINE void cfstore_dump_contents(const char* tag)
02752 {
02753     int32_t ret = ARM_DRIVER_ERROR;
02754     cfstore_area_hkvt_t hkvt;
02755     cfstore_ctx_t* ctx = cfstore_ctx_get();
02756 
02757     CFSTORE_TP(CFSTORE_TP_VERBOSE3, "%s:*** Dumping CFSTORE Contents : Start ***\n", tag);
02758     CFSTORE_TP(CFSTORE_TP_VERBOSE3, "%s:cfstore_ctx_g.area_0_head=%8p\n", tag, ctx->area_0_head);
02759     CFSTORE_TP(CFSTORE_TP_VERBOSE3, "%s:cfstore_ctx_g.area_0_tail=%8p\n", tag, ctx->area_0_tail);
02760     ret = cfstore_get_head_hkvt(&hkvt);
02761     if(ret == ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND){
02762         CFSTORE_TP(CFSTORE_TP_VERBOSE1, "%s:CFSTORE has no KVs\n", tag);
02763         goto out0;
02764     } else if(ret < ARM_DRIVER_OK){
02765         CFSTORE_ERRLOG("%s:Error: could not get head of list.\n", tag);
02766         goto out0;
02767     }
02768     while(cfstore_get_next_hkvt(&hkvt, &hkvt) != ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND)
02769     {
02770         cfstore_hkvt_dump(&hkvt, tag);
02771     }
02772 out0:
02773     CFSTORE_TP(CFSTORE_TP_VERBOSE3, "%s:*** Dumping CFSTORE Contents : End ***\n", tag);
02774     return;
02775 }
02776 
02777 
02778 
02779 #else
02780 static CFSTORE_INLINE void cfstore_hkvt_dump(cfstore_area_hkvt_t* hkvt, const char* tag){ (void) hkvt; (void) tag; return; }
02781 static CFSTORE_INLINE void cfstore_file_dump(cfstore_file_t* file, const char* tag){ (void) file; (void) tag;  return; }
02782 static CFSTORE_INLINE void cfstore_dump_contents(const char* tag){ (void) tag;  return; }
02783 static CFSTORE_INLINE void cfstore_flags_dump(ARM_CFSTORE_FMODE flag, const char* tag){ (void) flag; (void) tag;  return; }
02784 #endif /*CFSTORE_DEBUG*/
02785 
02786 /*
02787  * CS operations
02788  */
02789 
02790 /* @brief  See definition in configuration_store.h for description. */
02791 ARM_DRIVER_VERSION cfstore_get_version(void)
02792 {
02793     /* getting version info doesnt change the sram area so this can happen independently of
02794      * an oustanding async operation. its unnecessary to check the fsm state */
02795     return cfstore_driver_version_g;
02796 }
02797 
02798 
02799 /*
02800  * CS API Key-Value operations
02801  */
02802 
02803 /* @brief  See definition in configuration_store.h for description. */
02804 static int32_t cfstore_delete(ARM_CFSTORE_HANDLE  hkey)
02805 {
02806     int32_t ret = ARM_DRIVER_ERROR;
02807     cfstore_area_hkvt_t hkvt;
02808     cfstore_ctx_t* ctx = cfstore_ctx_get();
02809     cfstore_client_notify_data_t notify_data;
02810 
02811     CFSTORE_TP((CFSTORE_TP_DELETE|CFSTORE_TP_FENTRY), "%s:entered\n", __func__);
02812     if(!cfstore_ctx_is_initialised(ctx)) {
02813         CFSTORE_TP(CFSTORE_TP_DELETE, "%s:Error: CFSTORE is not initialised.\n", __func__);
02814         ret = ARM_CFSTORE_DRIVER_ERROR_UNINITIALISED;
02815         goto out0;
02816     }
02817     /* deleting a key will change the sram area while a logging/flushing operation is pending, which
02818      * should not happen while an async operation is outstanding */
02819     if(cfstore_flash_journal_is_async_op_pending(ctx)) {
02820         CFSTORE_TP(CFSTORE_TP_DELETE, "%s:Debug: flash journal operation pending (awaiting asynchronous notification).\n", __func__);
02821         ret = ARM_CFSTORE_DRIVER_ERROR_OPERATION_PENDING;
02822         goto out0;
02823     }
02824     ret = cfstore_validate_handle(hkey);
02825     if(ret < ARM_DRIVER_OK){
02826         CFSTORE_ERRLOG("%s:Error: invalid handle.\n", __func__);
02827         goto out0;
02828     }
02829     if(!cfstore_is_kv_client_deletable((cfstore_file_t*) hkey)){
02830         CFSTORE_ERRLOG("%s:Error: client is not permitted to delete KV.\n", __func__);
02831         ret = ARM_CFSTORE_DRIVER_ERROR_NO_PERMISSIONS;
02832         goto out0;
02833     }
02834     hkvt = cfstore_get_hkvt(hkey);
02835     /* check its a valid hkvt */
02836     if(!cfstore_hkvt_is_valid(&hkvt, ctx->area_0_tail)){
02837         CFSTORE_ERRLOG("%s:ARM_CFSTORE_DRIVER_ERROR_INVALID_HANDLE\n", __func__);
02838         ret = ARM_CFSTORE_DRIVER_ERROR_INVALID_HANDLE;
02839         goto out0;
02840     }
02841     /* set the delete flag so the delete occurs when the file is closed
02842      * no further handles will be returned to this key */
02843     cfstore_hkvt_set_flags_delete(&hkvt, true);
02844 
02845     /* set the dirty flag so the changes are persisted to backing store when flushed */
02846     ctx->area_dirty_flag = true;
02847 
02848 out0:
02849     /* Delete() always completes synchronously irrespective of flash mode, so indicate to caller */
02850     cfstore_client_notify_data_init(&notify_data, CFSTORE_OPCODE_DELETE, ret, NULL);
02851     cfstore_ctx_client_notify(ctx, &notify_data);
02852     return ret;
02853 }
02854 
02855 
02856 /** @brief  Internal find function using hkvt's.
02857  *
02858  * @note
02859  * Not the following:
02860  *  - Any required locks should be taken before this function is called.
02861  *    This function does not affect refcount for underlying KVs.
02862  *  - The function assumes the arguments have been validated before calling this function
02863  *  - No acl policy is enforced by the function.
02864  *
02865  * @return  return_value
02866  *          On success (finding a KV matching the query) ARM_DRIVER_OK is
02867  *          returned. If a KV is not found matching the description then
02868  *          ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND is returned.
02869  */
02870 static int32_t cfstore_find_ex(const char* key_name_query, cfstore_area_hkvt_t *prev, cfstore_area_hkvt_t *next)
02871 {
02872     int32_t ret = ARM_DRIVER_ERROR;
02873     uint8_t next_key_len;
02874     char key_name[CFSTORE_KEY_NAME_MAX_LENGTH+1];
02875     cfstore_ctx_t* ctx = cfstore_ctx_get();
02876 
02877     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);
02878     if(prev == NULL){
02879         ret = cfstore_get_head_hkvt(next);
02880         /* 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); */
02881         if(ret == ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND){
02882             CFSTORE_TP(CFSTORE_TP_FIND, "%s:CFSTORE has no KVs\n", __func__);
02883             return ret;
02884         } else if(ret < ARM_DRIVER_OK) {
02885             CFSTORE_TP(CFSTORE_TP_FIND, "%s:failed to find the first KV in area\n", __func__);
02886             return ret;
02887         }
02888 
02889         /* check for no KVs in the store => hkvt is not valid */
02890         if(!cfstore_hkvt_is_valid(next, ctx->area_0_tail)){
02891             /* no KVs in store */
02892             CFSTORE_TP(CFSTORE_TP_FIND, "%s:hkvt is not valid\n", __func__);
02893             return ARM_DRIVER_OK;
02894         }
02895 
02896     } else {
02897         /* CFSTORE_TP(CFSTORE_TP_FIND, "%s:getting hkvt from prev\n", __func__);*/
02898         ret = cfstore_get_next_hkvt(prev, next);
02899         if(ret < ARM_DRIVER_OK){
02900             /* no more matching entries or error.
02901              * either way, return*/
02902             return ret;
02903         }
02904     }
02905     if(next->head == NULL){
02906         /* no entry*/
02907         CFSTORE_TP(CFSTORE_TP_FIND, "%s:No more entries found\n", __func__);
02908         return ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND;
02909     }
02910     /* 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);*/
02911     cfstore_hkvt_dump(next, __func__);
02912     while(cfstore_hkvt_is_valid(next, ctx->area_0_tail))
02913     {
02914         /* 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); */
02915         cfstore_hkvt_dump(next, __func__);
02916 
02917         /* if this KV is deleting then proceed to the next item */
02918         if(cfstore_hkvt_get_flags_delete(next)){
02919             ret = cfstore_get_next_hkvt(next, next);
02920             if(ret == ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND) {
02921                 CFSTORE_TP(CFSTORE_TP_FIND, "%s:No more KVs found\n", __func__);
02922                 return ret;
02923             }
02924             continue;
02925         }
02926         /* if this KV is not readable by the client then proceed to the next item */
02927         if(!cfstore_is_kv_client_readable(next)){
02928             ret = cfstore_get_next_hkvt(next, next);
02929             if(ret == ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND) {
02930                 CFSTORE_TP(CFSTORE_TP_FIND, "%s:No more KVs found\n", __func__);
02931                 return ret;
02932             }
02933             continue;
02934         }
02935         /* check if this key_name matches the query */
02936         next_key_len = cfstore_hkvt_get_key_len(next);
02937         next_key_len++;
02938         cfstore_get_key_name_ex(next, key_name, &next_key_len);
02939         ret = cfstore_fnmatch(key_name_query, key_name, 0);
02940         if(ret == 0){
02941             /* found the entry in the store. return handle */
02942             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);
02943             cfstore_hkvt_dump(next, __func__);
02944             return ARM_DRIVER_OK;
02945         } else if(ret != CFSTORE_FNM_NOMATCH){
02946             CFSTORE_ERRLOG("%s:Error: cfstore_fnmatch() error (ret=%d).\n", __func__, (int) ret);
02947             return ARM_DRIVER_ERROR;
02948         }
02949         /* CFSTORE_FNM_NOMATCH => get the next hkvt if any */
02950         ret = cfstore_get_next_hkvt(next, next);
02951         if(ret == ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND) {
02952             CFSTORE_TP(CFSTORE_TP_FIND, "%s:No more KVs found\n", __func__);
02953             return ret;
02954         }
02955     }
02956     return ARM_DRIVER_OK;
02957 }
02958 
02959 
02960 /* @brief  See definition in configuration_store.h for description. */
02961 static int32_t cfstore_find(const char* key_name_query, const ARM_CFSTORE_HANDLE  previous, ARM_CFSTORE_HANDLE  next)
02962 {
02963     char key_name[CFSTORE_KEY_NAME_MAX_LENGTH+1];
02964     uint8_t key_len = 0;
02965     cfstore_area_hkvt_t hkvt_next;
02966     cfstore_area_hkvt_t hkvt_previous;
02967     cfstore_area_hkvt_t *phkvt_previous = NULL;
02968     int32_t ret = ARM_DRIVER_ERROR;
02969     ARM_CFSTORE_FMODE fmode;
02970     cfstore_ctx_t* ctx = cfstore_ctx_get();
02971     cfstore_client_notify_data_t notify_data;
02972 
02973     CFSTORE_ASSERT(next != NULL);
02974     CFSTORE_FENTRYLOG("%s:entered: key_name_query=\"%s\", previous=%p, next=%p\n", __func__, key_name_query, previous, next);
02975     if(!cfstore_ctx_is_initialised(ctx)) {
02976         CFSTORE_ERRLOG("%s:Error: CFSTORE is not initialised.\n", __func__);
02977         ret = ARM_CFSTORE_DRIVER_ERROR_UNINITIALISED;
02978         goto out1;
02979     }
02980     /* finding a key doesnt change the sram area so this can happen independently of
02981      * an oustanding async operation. its unnecessary to check the fsm state */
02982     ret = cfstore_validate_key_name_query(key_name_query);
02983     if(ret < ARM_DRIVER_OK){
02984         CFSTORE_ERRLOG("%s:Error: invalid key_name.\n", __func__);
02985         goto out1;
02986     }
02987     ret = cfstore_validate_handle(next);
02988     if(ret < ARM_DRIVER_OK){
02989         CFSTORE_ERRLOG("%s:Error: invalid next argument.\n", __func__);
02990         goto out1;
02991     }
02992     /* note previous can be NULL if this is the first call the find */
02993     memset(&hkvt_next, 0, sizeof(hkvt_next));
02994     memset(&fmode, 0, sizeof(fmode));
02995     if(previous != NULL && cfstore_file_is_valid(previous, ctx)){
02996         ret = cfstore_validate_handle(previous);
02997         if(ret < ARM_DRIVER_OK){
02998             CFSTORE_ERRLOG("%s:Error: invalid handle.\n", __func__);
02999             goto out1;
03000         }
03001         phkvt_previous = &hkvt_previous;
03002         memset(phkvt_previous, 0, sizeof(hkvt_previous));
03003         hkvt_previous = cfstore_get_hkvt(previous);
03004         cfstore_hkvt_dump(&hkvt_previous, __func__);
03005         if(!cfstore_hkvt_is_valid(phkvt_previous, ctx->area_0_tail)){
03006             ret = ARM_CFSTORE_DRIVER_ERROR_INVALID_HANDLE;
03007             goto out1;
03008         }
03009     } else if(previous != NULL && !cfstore_file_is_empty(previous)){
03010         CFSTORE_TP(CFSTORE_TP_FIND, "%s:Invalid previous hkey buffer.\n", __func__);
03011         ret = ARM_CFSTORE_DRIVER_ERROR_INVALID_HANDLE_BUF;
03012         goto out1;
03013     }
03014     ret = cfstore_find_ex(key_name_query, phkvt_previous, &hkvt_next);
03015     if(ret < ARM_DRIVER_OK){
03016         /* either no more entries or error but either way, return */
03017         CFSTORE_TP(CFSTORE_TP_FIND, "%s:No more KVs found.\n", __func__);
03018         goto out2;
03019     }
03020 
03021     if(!cfstore_hkvt_is_valid(&hkvt_next, ctx->area_0_tail)){
03022         CFSTORE_TP(CFSTORE_TP_FIND, "%s:Did not find any matching KVs.\n", __func__);
03023         ret = ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND;
03024         goto out2;
03025     }
03026 
03027     /* Have a valid kv. cfstore_find_ex() checked the client has
03028      * permission to read the KV, so dont have to perform this check again here. */
03029 
03030     /* return handle to client */
03031     cfstore_file_create(&hkvt_next, fmode, next, &ctx->file_list);
03032     ret = ARM_DRIVER_OK;
03033 out2:
03034     /* previous handle is being returned to CFSTORE with this call so destroy file struct */
03035     if(previous != NULL && cfstore_file_is_valid(previous, ctx))
03036     {
03037         /* do not use ret in this stanza as will loose return state from above */
03038         /* CFSTORE_TP(CFSTORE_TP_FIND, "%s:about to destroy KV, previous=%p.\n", __func__, previous); */
03039         cfstore_file_dump((cfstore_file_t*) previous, __func__);
03040 
03041         key_len = CFSTORE_KEY_NAME_MAX_LENGTH+1;
03042         memset(key_name, 0, CFSTORE_KEY_NAME_MAX_LENGTH+1);
03043 
03044         cfstore_file_destroy(cfstore_file_get(previous));
03045 
03046         /* check hkvt is valid before trying to retrieve name*/
03047         if(!cfstore_hkvt_is_valid(&hkvt_next, ctx->area_0_tail)){
03048             goto out1;
03049         }
03050         if(cfstore_get_key_name_ex(&hkvt_next, key_name, &key_len) < ARM_DRIVER_OK){
03051             /* either no more entries or error but either way, return */
03052             CFSTORE_TP(CFSTORE_TP_FIND, "%s:debug: cfstore_get_key_name_ex failed or no more kvs.\n", __func__);
03053             goto out1;
03054         }
03055         /* now get hkvt_next again based on the name to overcome the fact that the hkvt
03056          * may be invalid due to the possible deletion of the previous KV.x */
03057         if(cfstore_find_ex(key_name, NULL, &hkvt_next) < ARM_DRIVER_OK){
03058             /* either no more entries or error but either way, return */
03059             CFSTORE_TP(CFSTORE_TP_FIND, "%s:find failed key_name=%s ret=%d.\n", __func__, key_name, (int) ret);
03060             goto out1;
03061         }
03062         cfstore_hkvt_dump(&hkvt_next, __func__);
03063     }
03064 out1:
03065     /* Find() always completes synchronously irrespective of flash mode, so indicate to caller */
03066     cfstore_client_notify_data_init(&notify_data, CFSTORE_OPCODE_FIND, ret, next);
03067     cfstore_ctx_client_notify(ctx, &notify_data);
03068     return ret;
03069 }
03070 
03071 
03072 /* @brief  grow/shrink pre-existing KV.
03073  *
03074  * @note rw_lock must be held by the caller of this function rw_area0_lock */
03075 static int32_t cfstore_recreate(const char* key_name, ARM_CFSTORE_SIZE value_len, ARM_CFSTORE_HANDLE  hkey, cfstore_area_hkvt_t* hkvt)
03076 {
03077     uint8_t* old_area_0_head = NULL;
03078     int32_t kv_size_diff = 0;
03079     int32_t ret = ARM_DRIVER_ERROR;
03080     size_t memmove_len = 0;
03081     ARM_CFSTORE_SIZE area_size = 0;
03082     ARM_CFSTORE_FMODE flags;
03083     cfstore_ctx_t* ctx = cfstore_ctx_get();
03084 
03085     CFSTORE_FENTRYLOG("%s:entered: key_name=\"%s\", value_len=%d\n", __func__, key_name, (int) value_len);
03086     cfstore_dump_contents(__func__);
03087     memset(&flags, 0, sizeof(flags));
03088     flags.read = true;
03089     flags.write = true;
03090     kv_size_diff = value_len - cfstore_hkvt_get_value_len(hkvt);
03091     if(kv_size_diff == 0){
03092         /* nothing more to do*/
03093         CFSTORE_TP(CFSTORE_TP_CREATE, "%s:new value length the same as the old\n", __func__);
03094         return ARM_DRIVER_OK;
03095     }
03096 
03097     /* grow the area by the size of the new KV */
03098     area_size = cfstore_ctx_get_kv_total_len();
03099     /* store the area_0_head, and move length for later updating hkvt if realloc moves KV area */
03100     old_area_0_head = ctx->area_0_head;
03101     memmove_len = ctx->area_0_tail - hkvt->tail;
03102 
03103     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);
03104     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);
03105     if (kv_size_diff < 0){
03106         /* value blob size shrinking => do memmove() before realloc() which will free memory */
03107         memmove(hkvt->tail + kv_size_diff, hkvt->tail, memmove_len);
03108         ret = cfstore_file_update(hkvt->head, kv_size_diff);
03109         if(ret < ARM_DRIVER_OK){
03110             CFSTORE_ERRLOG("%s:Error:file update failed\n", __func__);
03111             goto out0;
03112         }
03113     }
03114 
03115     ret = cfstore_realloc_ex(area_size + kv_size_diff, NULL);
03116     if(ret < ARM_DRIVER_OK){
03117         CFSTORE_ERRLOG("%s:Error:file realloc failed\n", __func__);
03118         goto out0;
03119     }
03120     if(old_area_0_head != ctx->area_0_head){
03121         /* As realloc() has caused the memory to move, hkvt needs re-initialising */
03122         hkvt->head += ctx->area_0_head - old_area_0_head;
03123         hkvt->key += ctx->area_0_head - old_area_0_head;
03124         hkvt->value +=  ctx->area_0_head - old_area_0_head;
03125         hkvt->tail += ctx->area_0_head - old_area_0_head;
03126     }
03127 
03128     if(kv_size_diff > 0) {
03129         /* value blob size growing requires memmove() after realloc() */
03130         memmove(hkvt->tail+kv_size_diff, hkvt->tail, memmove_len);
03131         ret = cfstore_file_update(hkvt->head, kv_size_diff);
03132         if(ret < ARM_DRIVER_OK){
03133             CFSTORE_ERRLOG("%s:Error:file update failed\n", __func__);
03134             goto out0;
03135         }
03136     }
03137     /* hkvt->head, hkvt->key and hkvt->value remain unchanged but hkvt->tail has moved. Update it.*/
03138     hkvt->tail = hkvt->tail + kv_size_diff;
03139 
03140     /* set the new value length in the header */
03141     cfstore_hkvt_set_value_len(hkvt, value_len);
03142     cfstore_file_create(hkvt, flags, hkey, &ctx->file_list);
03143     ctx->area_dirty_flag = true;
03144 
03145 #ifdef CFSTORE_DEBUG
03146     cfstore_hkvt_dump(hkvt, __func__);
03147     cfstore_dump_contents(__func__);
03148 #endif
03149     ret = ARM_DRIVER_OK;
03150 out0:
03151     return ret;
03152 }
03153 
03154 
03155 /* @brief  See definition in configuration_store.h for description. */
03156 static int32_t cfstore_create(const char* key_name, ARM_CFSTORE_SIZE value_len, const ARM_CFSTORE_KEYDESC* kdesc, ARM_CFSTORE_HANDLE  hkey)
03157 {
03158     bool b_acl_default = false;
03159     int32_t ret = ARM_DRIVER_ERROR;
03160     int32_t cfstore_uvisor_box_id = 0;
03161     ARM_CFSTORE_SIZE area_size = 0;
03162     ARM_CFSTORE_SIZE kv_size = 0;
03163     ARM_CFSTORE_SIZE realloc_size = 0;
03164     cfstore_area_header_t * hdr;
03165     cfstore_area_hkvt_t hkvt;
03166     cfstore_ctx_t* ctx = cfstore_ctx_get();
03167     ARM_CFSTORE_FMODE flags;
03168     cfstore_client_notify_data_t notify_data;
03169 
03170     CFSTORE_FENTRYLOG("%s:entered: key_name=\"%s\", value_len=%d, kdesc=%p\n", __func__, key_name, (int)value_len, kdesc);
03171     CFSTORE_ASSERT(kdesc != NULL);
03172     CFSTORE_ASSERT(hkey != NULL);
03173 
03174     memset(&flags, 0, sizeof(flags));
03175     if(!cfstore_ctx_is_initialised(ctx)) {
03176         CFSTORE_ERRLOG("%s:Error: CFSTORE is not initialised.\n", __func__);
03177         return ARM_CFSTORE_DRIVER_ERROR_UNINITIALISED;
03178     }
03179     /* creating a key cannot happen while a flashJournal_log() is pending as it would change the sram area being logged*/
03180     if(cfstore_flash_journal_is_async_op_pending(ctx)) {
03181         CFSTORE_TP(CFSTORE_TP_CREATE, "%s:Debug: flash journal operation pending (awaiting asynchronous notification).\n", __func__);
03182         return ARM_CFSTORE_DRIVER_ERROR_OPERATION_PENDING;
03183     }
03184     ret = cfstore_validate_key_name(key_name);
03185     if(ret < ARM_DRIVER_OK){
03186         CFSTORE_ERRLOG("%s:Error: invalid key_name (%s).\n", __func__, key_name);
03187         goto out0;
03188     }
03189     ret = cfstore_validate_handle(hkey);
03190     if(ret < ARM_DRIVER_OK){
03191         CFSTORE_ERRLOG("%s:Error: invalid handle.\n", __func__);
03192         goto out0;
03193     }
03194     ret = cfstore_validate_value_len(value_len);
03195     if(ret < ARM_DRIVER_OK){
03196         CFSTORE_ERRLOG("%s:Error: invalid key_name.\n", __func__);
03197         goto out0;
03198     }
03199     /* check uvisor security */
03200     if(cfstore_is_client_kv_owner(key_name, &cfstore_uvisor_box_id) != ARM_DRIVER_OK){
03201         CFSTORE_ERRLOG("%s:Error: Client has insufficient permissions to create KV.\n", __func__);
03202         ret = ARM_CFSTORE_DRIVER_ERROR_NO_PERMISSIONS;
03203         goto out0;
03204     }
03205     /* the cfstore (uvisor) client is the owner of the KV and therefore is permitted to created it */
03206     /* A null kdesc is permitted if client is growing/shrinking pre-existing key.
03207      * Hence, find if key_name pre-exists before validating kdesc */
03208     ret = cfstore_find_ex(key_name, NULL, &hkvt);
03209     if(ret < ARM_DRIVER_OK && ret != ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND){
03210         CFSTORE_ERRLOG("%s:CFSTORE find() returned error (%d)\n", __func__, (int) ret);
03211         goto out1;
03212     }
03213 
03214     if(ret != ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND && cfstore_hkvt_is_valid(&hkvt, ctx->area_0_tail)){
03215         /* found pre-existing entry; */
03216         if(cfstore_hkvt_get_flags_delete(&hkvt)){
03217             CFSTORE_ERRLOG("%s:CFSTORE pre-existing KV with key_name=\"%s\" deleting\n", __func__, key_name);
03218             ret = ARM_CFSTORE_DRIVER_ERROR_PREEXISTING_KEY_DELETING;
03219             goto out1;
03220         }
03221         if(kdesc != NULL) {
03222             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);
03223             ret = ARM_CFSTORE_DRIVER_ERROR_PREEXISTING_KEY;
03224             goto out1;
03225         }
03226 
03227         /* client is requesting to grow/shrink pre-existing key */
03228         ret = cfstore_recreate(key_name, value_len, hkey, &hkvt);
03229         goto out1;
03230     }
03231     /* not a valid hkvt implying the key_name wasn't found */
03232 
03233     /* create new key */
03234     ret = cfstore_validate_key_desc(kdesc);
03235     if(ret < ARM_DRIVER_OK){
03236         CFSTORE_ERRLOG("%s:Error: invalid key descriptor.\n", __func__);
03237         goto out1;
03238     }
03239     /* insert the KV into the area */
03240     kv_size = strlen(key_name);
03241     kv_size += value_len;
03242     kv_size += sizeof(cfstore_area_header_t );
03243 
03244     /* grow the area by the size of the new KV
03245      * In the general case the new ((area_size + kv_size) % program_unit > 0). The new area_size is
03246      * aligned to a program_unit boundary to facilitate r/w to flash and so the memory realloc size
03247      * is calculated to align, as follows */
03248     area_size = cfstore_ctx_get_kv_total_len();
03249     /* setup the reallocation memory size. */
03250     realloc_size = area_size + kv_size;
03251     ret = cfstore_realloc_ex(realloc_size, NULL);
03252     if(ret < ARM_DRIVER_OK){
03253         CFSTORE_ERRLOG("%s:Error:file realloc failed\n", __func__);
03254         goto out1;
03255     }
03256 
03257     /* determine if should adopt a default behavior for acl permission setting */
03258     if(cfstore_acl_is_default(kdesc->acl)){
03259         /* set as read-write by default default */
03260         CFSTORE_TP(CFSTORE_TP_CREATE, "%s:Note: No ACL bits set. Adopting default permissions of owner read and write.\n", __func__);
03261         b_acl_default = true;
03262     }
03263     /* set the header up, then copy key_name into header */
03264     hdr = (cfstore_area_header_t *) (ctx->area_0_head + area_size);
03265     CFSTORE_FENTRYLOG("%s:hdr=%p\n", __func__, hdr);
03266     hdr->klength = (uint8_t) strlen(key_name);
03267     hdr->vlength = value_len;
03268     hdr->perm_owner_read = b_acl_default ? true : kdesc->acl.perm_owner_read;
03269     hdr->perm_owner_write = b_acl_default ? true : kdesc->acl.perm_owner_write;
03270     hdr->perm_owner_execute = kdesc->acl.perm_owner_execute;
03271     hdr->perm_other_read = kdesc->acl.perm_other_read;
03272     hdr->perm_other_write = kdesc->acl.perm_other_write;
03273     hdr->perm_other_execute = kdesc->acl.perm_other_execute;
03274     strncpy((char*)hdr + sizeof(cfstore_area_header_t ), key_name, strlen(key_name));
03275     hkvt = cfstore_get_hkvt_from_head_ptr((uint8_t*) hdr);
03276     if(cfstore_flags_is_default(kdesc->flags)){
03277         /* set as read-only by default default */
03278         flags.read = true;
03279         flags.write = true;
03280     } else {
03281         flags.read = kdesc->flags.read;
03282         flags.write = kdesc->flags.write;
03283     }
03284     cfstore_file_create(&hkvt, flags, hkey, &ctx->file_list);
03285     ctx->area_dirty_flag = true;
03286     ret = ARM_DRIVER_OK;
03287 out1:
03288     cfstore_hkvt_dump(&hkvt,  __func__);
03289 out0:
03290     cfstore_dump_contents(__func__);
03291     /* Create() always completes synchronously irrespective of flash mode, so indicate to caller */
03292     cfstore_client_notify_data_init(&notify_data, CFSTORE_OPCODE_CREATE, ret, hkey);
03293     cfstore_ctx_client_notify(ctx, &notify_data);
03294     return ret;
03295 }
03296 
03297 
03298 /* @brief  See definition in configuration_store.h for description. */
03299 static int32_t cfstore_open(const char* key_name, ARM_CFSTORE_FMODE flags, ARM_CFSTORE_HANDLE  hkey)
03300 {
03301     int32_t ret = ARM_DRIVER_ERROR;
03302     cfstore_area_hkvt_t hkvt;
03303     cfstore_file_t *file = NULL;
03304     cfstore_ctx_t* ctx = cfstore_ctx_get();
03305     cfstore_client_notify_data_t notify_data;
03306 
03307     CFSTORE_FENTRYLOG("%s:entered\n", __func__);
03308     cfstore_flags_dump(flags, __func__);
03309     CFSTORE_ASSERT(key_name != NULL);
03310     CFSTORE_ASSERT(hkey != NULL);
03311     if(!cfstore_ctx_is_initialised(ctx)) {
03312         CFSTORE_ERRLOG("%s:Error: CFSTORE is not initialised.\n", __func__);
03313         ret = ARM_CFSTORE_DRIVER_ERROR_UNINITIALISED;
03314         goto out1;
03315     }
03316     ret = cfstore_validate_key_name(key_name);
03317     if(ret < ARM_DRIVER_OK){
03318         CFSTORE_ERRLOG("%s:Error: invalid key_name.\n", __func__);
03319         goto out1;
03320     }
03321     ret = cfstore_validate_fmode_flags(flags);
03322     if(ret < ARM_DRIVER_OK){
03323         CFSTORE_ERRLOG("%s:Error: invalid flags.\n", __func__);
03324         goto out1;
03325     }
03326     if(flags.write){
03327         /* opening a pre-existing key for writing can result in the sram area being changed, which
03328          * cannot happen while a flashJournal_xxx() async completion notification is outstanding */
03329         if(cfstore_flash_journal_is_async_op_pending(ctx)) {
03330             CFSTORE_TP(CFSTORE_TP_OPEN, "%s:Debug: flash journal operation pending (awaiting asynchronous notification).\n", __func__);
03331             ret = ARM_CFSTORE_DRIVER_ERROR_OPERATION_PENDING;
03332             goto out1;
03333         }
03334     }
03335     ret = cfstore_validate_handle(hkey);
03336     if(ret < ARM_DRIVER_OK){
03337         CFSTORE_ERRLOG("%s:Error: invalid handle.\n", __func__);
03338         goto out1;
03339     }
03340     /* find the KV and return a handle */
03341     cfstore_hkvt_init(&hkvt);
03342     ret = cfstore_find_ex(key_name, NULL, &hkvt);
03343     if(ret < ARM_DRIVER_OK){
03344         /* either no more entries or error but either way, return */
03345         CFSTORE_TP(CFSTORE_TP_OPEN, "%s:debug: find failed or no more kvs.\n", __func__);
03346         goto out1;
03347     }
03348     if(!cfstore_hkvt_is_valid(&hkvt, ctx->area_0_tail))
03349     {
03350         CFSTORE_ERRLOG("%s:Error: Could not find pre-existing key to open with key_name=(%s).\n", __func__, key_name);
03351         ret = ARM_CFSTORE_DRIVER_ERROR_KEY_NOT_FOUND;
03352         goto out1;
03353     }
03354     /* if this KV is deleting then do not allow item to be opened */
03355     if(cfstore_hkvt_get_flags_delete(&hkvt)){
03356         CFSTORE_ERRLOG("%s:Error: Pre-existing key key_name=(%s) is deleting.\n", __func__, key_name);
03357         ret = ARM_CFSTORE_DRIVER_ERROR_PREEXISTING_KEY_DELETING;
03358         goto out1;
03359     }
03360     /* key found, check permissions */
03361     if(cfstore_flags_is_default(flags)){
03362         /* set as read-only by default default */
03363         flags.read = true;
03364     }
03365     if(flags.read == true && !cfstore_is_kv_client_readable(&hkvt)){
03366         CFSTORE_ERRLOG("%s:Error: Client has no read access to KV (key_name=%s).\n", __func__, key_name);
03367         ret = ARM_CFSTORE_DRIVER_ERROR_PERM_NO_READ_ACCESS;
03368         goto out1;
03369     }
03370     if(flags.write == true && !cfstore_is_kv_client_writable(&hkvt)){
03371         CFSTORE_ERRLOG("%s:Error: Client has no write access to KV (key_name=%s).\n", __func__, key_name);
03372         ret = ARM_CFSTORE_DRIVER_ERROR_PERM_NO_WRITE_ACCESS;
03373         goto out1;
03374     }
03375     if(flags.execute == true && !cfstore_is_kv_client_executable(&hkvt)){
03376         CFSTORE_ERRLOG("%s:Error: Client has no execute access to KV (key_name=%s).\n", __func__, key_name);
03377         ret = ARM_CFSTORE_DRIVER_ERROR_PERM_NO_EXECUTE_ACCESS;
03378         goto out1;
03379     }
03380     /* return handle to client */
03381     file = cfstore_file_create(&hkvt, flags, hkey, &ctx->file_list);
03382     if(file) {
03383         cfstore_file_dump(file, __func__);
03384     } else {
03385         CFSTORE_ERRLOG("%s:Error: failed to create file (key_name=%s).\n", __func__, key_name);
03386     }
03387 out1:
03388     /* Open() always completes synchronously irrespective of flash mode, so indicate to caller */
03389     cfstore_client_notify_data_init(&notify_data, CFSTORE_OPCODE_OPEN, ret, hkey);
03390     cfstore_ctx_client_notify(ctx, &notify_data);
03391     return ret;
03392 }
03393 
03394 
03395 /* @brief  See definition in configuration_store.h for description. */
03396 static int32_t cfstore_close(ARM_CFSTORE_HANDLE  hkey)
03397 {
03398     int32_t ret = ARM_DRIVER_ERROR;
03399     cfstore_ctx_t* ctx = cfstore_ctx_get();
03400     cfstore_client_notify_data_t notify_data;
03401     cfstore_area_hkvt_t hkvt;
03402 
03403     CFSTORE_FENTRYLOG("%s:entered\n", __func__);
03404     if(!cfstore_ctx_is_initialised(ctx)) {
03405         CFSTORE_ERRLOG("%s:Error: CFSTORE is not initialised.\n", __func__);
03406         ret = ARM_CFSTORE_DRIVER_ERROR_UNINITIALISED;
03407         goto out0;
03408     }
03409     /* closing a key can lead to its deletion, which cannot happening while there are pending
03410      * async operations outstanding */
03411     if(cfstore_flash_journal_is_async_op_pending(ctx)) {
03412         CFSTORE_TP(CFSTORE_TP_CLOSE, "%s:Debug: flash journal operation pending (awaiting asynchronous notification).\n", __func__);
03413         ret = ARM_CFSTORE_DRIVER_ERROR_OPERATION_PENDING;
03414         goto out0;
03415     }
03416     ret = cfstore_validate_handle(hkey);
03417     if(ret < ARM_DRIVER_OK){
03418         CFSTORE_ERRLOG("%s:Error: invalid hkey argument.\n", __func__);
03419         goto out0;
03420     }
03421     /* check the hkey is valid */
03422     hkvt = cfstore_get_hkvt(hkey);
03423     if(!cfstore_hkvt_is_valid(&hkvt, ctx->area_0_tail)){
03424         CFSTORE_ERRLOG("%s:ARM_CFSTORE_DRIVER_ERROR_INVALID_HANDLE\n", __func__);
03425         ret = ARM_CFSTORE_DRIVER_ERROR_INVALID_HANDLE;
03426         goto out0;
03427     }
03428     if(!cfstore_is_kv_client_closable((cfstore_file_t*) hkey)){
03429         CFSTORE_ERRLOG("%s:Error: client is not permitted to close KV.\n", __func__);
03430         ret = ARM_CFSTORE_DRIVER_ERROR_NO_PERMISSIONS;
03431         goto out0;
03432     }
03433     /* delete the file associated with this open handle */
03434     CFSTORE_TP(CFSTORE_TP_CLOSE, "%s:about to call cfstore_file_destroy().\n", __func__);
03435     cfstore_file_dump((cfstore_file_t*) hkey, __func__);
03436     ret = cfstore_file_destroy(cfstore_file_get(hkey));
03437 out0:
03438     /* Close() always completes synchronously irrespective of flash mode, so indicate to caller */
03439     cfstore_client_notify_data_init(&notify_data, CFSTORE_OPCODE_CLOSE, ret, NULL);
03440     cfstore_ctx_client_notify(ctx, &notify_data);
03441     return ret;
03442 }
03443 
03444 
03445 /* @brief  See definition in configuration_store.h for description. */
03446 static int32_t cfstore_read(ARM_CFSTORE_HANDLE  hkey, void* data, ARM_CFSTORE_SIZE* len)
03447 {
03448     int32_t ret = ARM_DRIVER_ERROR;
03449     ARM_CFSTORE_SIZE read_len = 0;
03450     cfstore_area_hkvt_t hkvt;
03451     cfstore_ctx_t* ctx = cfstore_ctx_get();
03452     cfstore_file_t* file = cfstore_file_get(hkey);
03453     cfstore_client_notify_data_t notify_data;
03454 
03455     CFSTORE_ASSERT(data);
03456     CFSTORE_ASSERT(len);
03457     CFSTORE_FENTRYLOG("%s:entered, hkey=%p\n", __func__, hkey);
03458     if(!cfstore_ctx_is_initialised(ctx)) {
03459         CFSTORE_ERRLOG("%s:Error: CFSTORE is not initialised.\n", __func__);
03460         ret = ARM_CFSTORE_DRIVER_ERROR_UNINITIALISED;
03461         goto out0;
03462     }
03463     /* reading KVs doesnt change the sram area so this can happen independently of
03464      * an oustanding async operation. its unnecessary to check the fsm state */
03465     ret = cfstore_validate_handle(hkey);
03466     if(ret < ARM_DRIVER_OK){
03467         CFSTORE_ERRLOG("%s:Error: invalid handle.\n", __func__);
03468         goto out0;
03469     }
03470     if(data == NULL){
03471         CFSTORE_ERRLOG("%s:Error: invalid read data buffer.\n", __func__);
03472         ret = ARM_CFSTORE_DRIVER_ERROR_INVALID_READ_BUFFER;
03473         goto out0;
03474     }
03475     ret = cfstore_validate_len_ptr(len);
03476     if(ret < ARM_DRIVER_OK){
03477         CFSTORE_ERRLOG("%s:Error: invalid len argument.\n", __func__);
03478         goto out0;
03479     }
03480     cfstore_hkvt_init(&hkvt);
03481     hkvt = cfstore_get_hkvt(hkey);
03482     /* check the hkey is valid */
03483     if(!cfstore_hkvt_is_valid(&hkvt, ctx->area_0_tail)){
03484         CFSTORE_ERRLOG("%s:ARM_CFSTORE_DRIVER_ERROR_INVALID_HANDLE\n", __func__);
03485         ret = ARM_CFSTORE_DRIVER_ERROR_INVALID_HANDLE;
03486         goto out0;
03487     }
03488 
03489     if(!cfstore_is_kv_client_readable(&hkvt)){
03490         CFSTORE_ERRLOG("%s:Error: client does not have permission to read KV.\n", __func__);
03491         ret = ARM_CFSTORE_DRIVER_ERROR_PERM_NO_READ_ACCESS;
03492         goto out0;
03493     }
03494     read_len = *len <= (cfstore_hkvt_get_value_len(&hkvt) - file->rlocation) ? *len : cfstore_hkvt_get_value_len(&hkvt) - file->rlocation;
03495     memcpy(data, hkvt.value + file->rlocation, read_len);
03496     file->rlocation += read_len;
03497     *len = read_len;
03498     ret = read_len;
03499 out0:
03500     /* Read() always completes synchronously irrespective of flash mode, so indicate to caller */
03501     cfstore_client_notify_data_init(&notify_data, CFSTORE_OPCODE_READ, ret, hkey);
03502     cfstore_ctx_client_notify(ctx, &notify_data);
03503     return ret;
03504 }
03505 
03506 
03507 /* @brief  See definition in configuration_store.h for description. */
03508 static int32_t cfstore_write(ARM_CFSTORE_HANDLE  hkey, const char* data, ARM_CFSTORE_SIZE* len)
03509 {
03510     int32_t ret = ARM_DRIVER_ERROR;
03511     ARM_CFSTORE_SIZE value_len = 0;
03512     cfstore_area_hkvt_t hkvt;
03513     cfstore_file_t* file = cfstore_file_get(hkey);
03514     cfstore_ctx_t* ctx = cfstore_ctx_get();
03515     cfstore_client_notify_data_t notify_data;
03516 
03517     CFSTORE_FENTRYLOG("%s:entered, hkey=%p\n", __func__, hkey);
03518     CFSTORE_ASSERT(hkey != NULL);
03519     CFSTORE_ASSERT(len != NULL);
03520     if(!cfstore_ctx_is_initialised(ctx)) {
03521         CFSTORE_ERRLOG("%s:Error: CFSTORE is not initialised.\n", __func__);
03522         ret = ARM_CFSTORE_DRIVER_ERROR_UNINITIALISED;
03523         goto out0;
03524     }
03525     /* writing a key cannot happen while a flashJournal_xxx() async operation is pending */
03526     if(cfstore_flash_journal_is_async_op_pending(ctx)) {
03527         CFSTORE_TP(CFSTORE_TP_WRITE, "%s:Debug: flash journal operation pending (awaiting asynchronous notification).\n", __func__);
03528         ret = ARM_CFSTORE_DRIVER_ERROR_OPERATION_PENDING;
03529         goto out0;
03530     }
03531     ret = cfstore_validate_handle(hkey);
03532     if(ret < ARM_DRIVER_OK){
03533         CFSTORE_ERRLOG("%s:Error: invalid handle.\n", __func__);
03534         goto out0;
03535     }
03536     if(data == NULL){
03537         CFSTORE_ERRLOG("%s:Error: invalid write data buffer.\n", __func__);
03538         ret = ARM_CFSTORE_DRIVER_ERROR_INVALID_WRITE_BUFFER;
03539         goto out0;
03540     }
03541     ret = cfstore_validate_len_ptr(len);
03542     if(ret < ARM_DRIVER_OK){
03543         CFSTORE_ERRLOG("%s:Error: invalid len argument.\n", __func__);
03544         goto out0;
03545     }
03546     ret = cfstore_validate_value_len(*len);
03547     if (ret < ARM_DRIVER_OK) {
03548         CFSTORE_ERRLOG("%s:Error: invalid key_name.\n", __func__);
03549         goto out0;
03550     }
03551     /*check file has write permission set */
03552     if(!file->flags.write){
03553         CFSTORE_ERRLOG("%s:Error: KV is read-only.\n", __func__);
03554         ret = ARM_CFSTORE_DRIVER_ERROR_KEY_READ_ONLY;
03555         goto out0;
03556     }
03557     memset(&hkvt, 0, sizeof(hkvt));
03558     hkvt = cfstore_get_hkvt(hkey);
03559     if(!cfstore_hkvt_is_valid(&hkvt, ctx->area_0_tail)){
03560         CFSTORE_ERRLOG("%s:Error: ARM_CFSTORE_DRIVER_ERROR_INVALID_HANDLE.\n", __func__);
03561         ret = ARM_CFSTORE_DRIVER_ERROR_INVALID_HANDLE;
03562         goto out0;
03563     }
03564     if(!cfstore_is_kv_client_writable(&hkvt)){
03565         CFSTORE_ERRLOG("%s:Error: client does not have permission to write KV.\n", __func__);
03566         ret = ARM_CFSTORE_DRIVER_ERROR_PERM_NO_WRITE_ACCESS;
03567         goto out0;
03568     }
03569     value_len = (ARM_CFSTORE_SIZE) cfstore_hkvt_get_value_len(&hkvt);
03570     *len = *len < value_len ? *len: value_len;
03571     memcpy(hkvt.value + file->wlocation, data, *len);
03572     file->wlocation += *len;
03573     cfstore_hkvt_dump(&hkvt, __func__);
03574     ctx->area_dirty_flag = true;
03575     ret = *len;
03576 out0:
03577     /* Write() always completes synchronously irrespective of flash mode, so indicate to caller */
03578     cfstore_client_notify_data_init(&notify_data, CFSTORE_OPCODE_WRITE, ret, hkey);
03579     cfstore_ctx_client_notify(ctx, &notify_data);
03580     return ret;
03581 }
03582 
03583 
03584 /* @brief  See definition in configuration_store.h for description. */
03585 static int32_t cfstore_rseek(ARM_CFSTORE_HANDLE  hkey, ARM_CFSTORE_OFFSET offset)
03586 {
03587     int32_t ret = ARM_DRIVER_ERROR;
03588     cfstore_area_hkvt_t hkvt;
03589     cfstore_file_t* file = cfstore_file_get(hkey);
03590     cfstore_ctx_t* ctx = cfstore_ctx_get();
03591     cfstore_client_notify_data_t notify_data;
03592 
03593     CFSTORE_FENTRYLOG("%s:entered\n", __func__);
03594     if(!cfstore_ctx_is_initialised(ctx)) {
03595         CFSTORE_ERRLOG("%s:Error: CFSTORE is not initialised.\n", __func__);
03596         return ARM_CFSTORE_DRIVER_ERROR_UNINITIALISED;
03597     }
03598     /* read-seeking KVs doesnt change the sram area so this can happen independently of
03599      * an oustanding async operation. its unnecessary to check the fsm state */
03600     ret = cfstore_validate_handle(hkey);
03601     if(ret < ARM_DRIVER_OK){
03602         CFSTORE_ERRLOG("%s:Error: invalid handle.\n", __func__);
03603         return ret;
03604     }
03605     ret = cfstore_validate_value_len(offset);
03606     if(ret < ARM_DRIVER_OK){
03607         CFSTORE_ERRLOG("%s:Error: offset (%u) greater than maximum value blob size (%u).\n", __func__, (unsigned int) offset, CFSTORE_VALUE_SIZE_MAX);
03608         return ret;
03609     }
03610     if(!file->flags.read){
03611         CFSTORE_ERRLOG("%s:Error: KV is not readable.\n", __func__);
03612         ret = ARM_CFSTORE_DRIVER_ERROR_KEY_UNREADABLE;
03613         goto out0;
03614 
03615     }
03616     cfstore_hkvt_init(&hkvt);
03617     hkvt = cfstore_get_hkvt(hkey);
03618     if(!cfstore_hkvt_is_valid(&hkvt, ctx->area_0_tail)){
03619         CFSTORE_ERRLOG("%s:Error: ARM_CFSTORE_DRIVER_ERROR_INVALID_HANDLE.\n", __func__);
03620         ret = ARM_CFSTORE_DRIVER_ERROR_INVALID_HANDLE;
03621         goto out0;
03622     }
03623     if(!cfstore_is_kv_client_readable(&hkvt)){
03624         CFSTORE_ERRLOG("%s:Error: client does not have permission to read KV.\n", __func__);
03625         ret = ARM_CFSTORE_DRIVER_ERROR_PERM_NO_READ_ACCESS;
03626         goto out0;
03627     }
03628     /* check offset is in range */
03629     if(offset > cfstore_hkvt_get_value_len(&hkvt)){
03630         CFSTORE_ERRLOG("%s:Error: seeking beyond end of value.\n", __func__);
03631         ret = ARM_CFSTORE_DRIVER_ERROR_INVALID_SEEK;
03632         goto out0;
03633 
03634     }
03635     file->rlocation = offset;
03636     ret = (int32_t) offset;
03637 out0:
03638     /* Rseek() always completes synchronously irrespective of flash mode, so indicate to caller */
03639     cfstore_client_notify_data_init(&notify_data, CFSTORE_OPCODE_RSEEK, ret, hkey);
03640     cfstore_ctx_client_notify(ctx, &notify_data);
03641     return ret;
03642 }
03643 
03644 
03645 /* @brief  See definition in configuration_store.h for description. */
03646 static int32_t cfstore_flush(void)
03647 {
03648     int32_t ret = ARM_DRIVER_ERROR;
03649     cfstore_ctx_t* ctx = cfstore_ctx_get();
03650 
03651     CFSTORE_FENTRYLOG("%s:entered\n", __func__);
03652     if(!cfstore_ctx_is_initialised(ctx)) {
03653         CFSTORE_ERRLOG("%s:Error: CFSTORE is not initialised.\n", __func__);
03654         ret = ARM_CFSTORE_DRIVER_ERROR_UNINITIALISED;
03655         goto out0;
03656     }
03657     /* only 1 flush operation can be outstanding so check whether one is already in progress */
03658     if(cfstore_flash_journal_is_async_op_pending(ctx)) {
03659         CFSTORE_TP(CFSTORE_TP_FLUSH, "%s:Debug: flash journal operation pending (awaiting asynchronous notification).\n", __func__);
03660         return ARM_CFSTORE_DRIVER_ERROR_OPERATION_PENDING;
03661     }
03662     ret = cfstore_flash_flush(ctx);
03663     if(ret < ARM_DRIVER_OK) {
03664         CFSTORE_ERRLOG("%s:Error: cfstore_flash_flush() returned error (ret=%d).\n", __func__, (int) ret);
03665         goto out0;
03666     }
03667 out0:
03668     return ret;
03669 }
03670 
03671 /* @brief  See definition in configuration_store.h for description. */
03672 static int32_t cfstore_initialise(ARM_CFSTORE_CALLBACK callback, void* client_context)
03673 {
03674     int ret = ARM_DRIVER_ERROR;
03675     cfstore_ctx_t* ctx = cfstore_ctx_get();
03676 #ifdef CFSTORE_CONFIG_BACKEND_FLASH_ENABLED
03677     ARM_STORAGE_CAPABILITIES storage_caps;
03678 #endif /* CFSTORE_CONFIG_BACKEND_FLASH_ENABLED */
03679 
03680     CFSTORE_FENTRYLOG("%s:entered: callback=%p, client_context=%p, ref_count=%d\n", __func__, callback, client_context, (int) ctx->init_ref_count);
03681     /* init cfstore context the first time this method is called
03682      * note ctx->rw_area0_lock has already been initialised */
03683 
03684     /* CS protection required to get into the fsm into the initing state, without another client g*/
03685     cfstore_critical_section_lock(&ctx->rw_area0_lock, __func__);
03686     if(ctx->init_ref_count == 0)
03687     {
03688         CFSTORE_TP(CFSTORE_TP_INIT, "%s:debug: first time init\n", __func__);
03689         /* perform first time initialisation */
03690         ctx->init_ref_count++;
03691         /* initially there is no memory allocated for the area */
03692         CFSTORE_INIT_LIST_HEAD(&ctx->file_list);
03693         /* ctx->rw_area0_lock initialisation is not required here as the lock is statically initialised to 0 */
03694         ctx->area_0_head = NULL;
03695         ctx->area_0_tail = NULL;
03696 
03697         CFSTORE_ASSERT(sizeof(cfstore_file_t) == CFSTORE_HANDLE_BUFSIZE);
03698         if(sizeof(cfstore_file_t) != CFSTORE_HANDLE_BUFSIZE){
03699             CFSTORE_ERRLOG("%s:Error: sizeof(cfstore_file_t)=(%d) != CFSTORE_HANDLE_BUFSIZE (%d)\n", __func__,(int) sizeof(cfstore_file_t), (int) CFSTORE_HANDLE_BUFSIZE);
03700             ret = ARM_CFSTORE_DRIVER_ERROR_INTERNAL;
03701             goto out0;
03702         }
03703         ctx->client_callback = callback;
03704         ctx->client_context = client_context;
03705         ctx->area_dirty_flag = false;
03706         ctx->client_callback_notify_flag = false;
03707 
03708         cfstore_client_notify_data_init(&ctx->client_notify_data, CFSTORE_OPCODE_MAX, ARM_DRIVER_ERROR, NULL);
03709         ctx->power_state = ARM_POWER_FULL;
03710         ctx->status = ARM_DRIVER_OK;
03711 
03712 #ifdef CFSTORE_CONFIG_BACKEND_FLASH_ENABLED
03713         /* set the cfstore async flag according to the storage driver mode */
03714         storage_caps = cfstore_storage_drv->GetCapabilities();
03715         cfstore_caps_g.asynchronous_ops = storage_caps.asynchronous_ops;
03716 #endif /* CFSTORE_CONFIG_BACKEND_FLASH_ENABLED */
03717 
03718         ret = cfstore_flash_init();
03719         if(ret < ARM_DRIVER_OK) {
03720             CFSTORE_ERRLOG("%s:Error: failed to initialise flash layer\n", __func__);
03721             goto out0;
03722         }
03723     }
03724     else
03725     {
03726         CFSTORE_TP(CFSTORE_TP_INIT, "%s:debug: n-th time init\n", __func__);
03727         /* initialisation already done so only increment the ref count */
03728         ctx->init_ref_count++;
03729         ret = ARM_DRIVER_OK;
03730     }
03731 out0:
03732     /* if not initialised already, fsm now in the initing state so safe to come out of CS */
03733     cfstore_critical_section_unlock(&ctx->rw_area0_lock, __func__);
03734     CFSTORE_FENTRYLOG("%s:exiting: callback=%p, client_context=%p, ref_count=%d\n", __func__, callback, client_context, (int) ctx->init_ref_count);
03735     return ret;
03736 }
03737 
03738 
03739 /* @brief  See prototype definition in configuration_store.h for function description.
03740  *
03741  * @note    unitialising cfstore results in all entries that have not been flushed being lost
03742  */
03743 static int32_t cfstore_uninitialise(void)
03744 {
03745     int32_t ret = ARM_DRIVER_ERROR;
03746     ARM_STORAGE_CAPABILITIES caps;
03747     cfstore_ctx_t* ctx = cfstore_ctx_get();
03748     cfstore_file_t* file;
03749     cfstore_list_node_t* node;
03750     cfstore_list_node_t* file_list = &ctx->file_list;
03751 
03752     CFSTORE_FENTRYLOG("%s:entered\n", __func__);
03753     memset(&caps, 0, sizeof(caps));
03754 
03755     if(!cfstore_ctx_is_initialised(ctx)) {
03756         CFSTORE_ERRLOG("%s:Error: CFSTORE is not initialised.\n", __func__);
03757         ret = ARM_CFSTORE_DRIVER_ERROR_UNINITIALISED;
03758         goto out;
03759     }
03760     /* only uninitialise when there are no flash journal async operations pending*/
03761     if(cfstore_flash_journal_is_async_op_pending(ctx)) {
03762         CFSTORE_TP(CFSTORE_TP_INIT, "%s:Debug: flash journal operation pending (awaiting asynchronous notification).\n", __func__);
03763         ret = ARM_CFSTORE_DRIVER_ERROR_OPERATION_PENDING;
03764         goto out;
03765     }
03766     if(ctx->init_ref_count > 0) {
03767         ctx->init_ref_count--;
03768         CFSTORE_TP(CFSTORE_TP_INIT, "%s:Debug: decremented init_ref_count (%d).\n", __func__, (int) ctx->init_ref_count);
03769     }
03770     if(ctx->init_ref_count == 0)
03771     {
03772         CFSTORE_TP(CFSTORE_TP_INIT, "%s:Debug: init_ref_count == 0 (%d) so uninitialising.\n", __func__, (int) ctx->init_ref_count);
03773         /* check file list is empty and if not, free the items */
03774         if(ctx->file_list.next != ctx->file_list.prev)
03775         {
03776             /* list is not empty. walk the list and close the files, cleaning up state */
03777             node = file_list->next;
03778             while(node != file_list){
03779                 file = (cfstore_file_t*) node;
03780                 cfstore_close((ARM_CFSTORE_HANDLE ) file);
03781                 node = node->next;
03782             }
03783         }
03784         ret = cfstore_flash_deinit();
03785         if(ret < ARM_DRIVER_OK){
03786             CFSTORE_ERRLOG("%s:Error: failed to uninitialise flash journal layer.\n", __func__);
03787             goto out;
03788         }
03789         if(ctx->area_0_head){
03790             CFSTORE_FREE(ctx->area_0_head);
03791             ctx->area_0_head = NULL;
03792             ctx->area_0_tail = NULL;
03793             ctx->area_0_len = 0;
03794         }
03795     }
03796 out:
03797     /* notify client */
03798     cfstore_client_notify_data_init(&ctx->client_notify_data, CFSTORE_OPCODE_UNINITIALIZE, ret, NULL);
03799     cfstore_ctx_client_notify(ctx, &ctx->client_notify_data);
03800     return ret;
03801 }
03802 
03803 
03804 /* @brief  See definition in configuration_store.h for description. */
03805 static int32_t cfstore_power_control(ARM_POWER_STATE state)
03806 {
03807     int32_t ret = ARM_DRIVER_ERROR;
03808     cfstore_ctx_t* ctx = cfstore_ctx_get();
03809     cfstore_client_notify_data_t notify_data;
03810 
03811     CFSTORE_FENTRYLOG("%s:entered\n", __func__);
03812     if(!cfstore_ctx_is_initialised(ctx)) {
03813         CFSTORE_ERRLOG("%s:Error: CFSTORE is not initialised.\n", __func__);
03814         ret = ARM_CFSTORE_DRIVER_ERROR_UNINITIALISED;
03815         goto out0;
03816     }
03817     /* setting power state doesnt change the sram area so this can happen independently of
03818      * an oustanding async operation. its unnecessary to check the fsm state */
03819     if(state <= ARM_POWER_FULL){
03820         ctx->power_state = state;
03821         /* set return to a positive value*/
03822         ret = (int32_t) state;
03823     }
03824 out0:
03825     /* PowerControl() always completes synchronously irrespective of flash mode, so indicate to caller */
03826     cfstore_client_notify_data_init(&notify_data, CFSTORE_OPCODE_POWER_CONTROL, ret, NULL);
03827     cfstore_ctx_client_notify(ctx, &notify_data);
03828     return ret;
03829 }
03830 
03831 ARM_CFSTORE_DRIVER cfstore_driver =
03832 {
03833         .Close = cfstore_close,
03834         .Create = cfstore_create,
03835         .Delete= cfstore_delete,
03836         .Find = cfstore_find,
03837         .Flush = cfstore_flush,
03838         .GetCapabilities = cfstore_get_capabilities,
03839         .GetKeyName = cfstore_get_key_name,
03840         .GetStatus = cfstore_get_status,
03841         .GetValueLen = cfstore_get_value_len,
03842         .GetVersion = cfstore_get_version,
03843         .Initialize = cfstore_initialise,
03844         .Open = cfstore_open,
03845         .PowerControl = cfstore_power_control,
03846         .Read = cfstore_read,
03847         .Rseek = cfstore_rseek,
03848         .Uninitialize = cfstore_uninitialise,
03849         .Write = cfstore_write,
03850 };